summaryrefslogtreecommitdiffstats
path: root/collectors
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2018-11-07 12:19:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2018-11-07 12:20:17 +0000
commita64a253794ac64cb40befee54db53bde17dd0d49 (patch)
treec1024acc5f6e508814b944d99f112259bb28b1be /collectors
parentNew upstream version 1.10.0+dfsg (diff)
downloadnetdata-a64a253794ac64cb40befee54db53bde17dd0d49.tar.xz
netdata-a64a253794ac64cb40befee54db53bde17dd0d49.zip
New upstream version 1.11.0+dfsgupstream/1.11.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--collectors/Makefile.am28
-rw-r--r--collectors/Makefile.in663
-rw-r--r--collectors/README.md118
-rw-r--r--collectors/all.h318
-rw-r--r--collectors/apps.plugin/Makefile.am13
-rw-r--r--collectors/apps.plugin/Makefile.in521
-rw-r--r--collectors/apps.plugin/README.md372
-rw-r--r--collectors/apps.plugin/apps_groups.conf (renamed from conf.d/apps_groups.conf)14
-rw-r--r--collectors/apps.plugin/apps_plugin.c (renamed from src/apps_plugin.c)712
-rw-r--r--collectors/cgroups.plugin/Makefile.am21
-rw-r--r--collectors/cgroups.plugin/Makefile.in (renamed from charts.d/Makefile.in)160
-rw-r--r--collectors/cgroups.plugin/README.md187
-rw-r--r--[-rwxr-xr-x]collectors/cgroups.plugin/cgroup-name.sh (renamed from plugins.d/cgroup-name.sh)35
-rwxr-xr-xcollectors/cgroups.plugin/cgroup-name.sh.in196
-rwxr-xr-xcollectors/cgroups.plugin/cgroup-network-helper.sh (renamed from plugins.d/cgroup-network-helper.sh)29
-rw-r--r--collectors/cgroups.plugin/cgroup-network.c (renamed from src/cgroup-network.c)97
-rw-r--r--collectors/cgroups.plugin/sys_fs_cgroup.c (renamed from src/sys_fs_cgroup.c)340
-rw-r--r--collectors/cgroups.plugin/sys_fs_cgroup.h31
-rw-r--r--collectors/charts.d.plugin/Makefile.am62
-rw-r--r--collectors/charts.d.plugin/Makefile.in953
-rw-r--r--collectors/charts.d.plugin/README.md193
-rw-r--r--collectors/charts.d.plugin/ap/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/ap/README.md84
-rw-r--r--collectors/charts.d.plugin/ap/ap.chart.sh (renamed from charts.d/ap.chart.sh)9
-rw-r--r--collectors/charts.d.plugin/ap/ap.conf (renamed from conf.d/charts.d/ap.conf)0
-rw-r--r--collectors/charts.d.plugin/apache/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/apache/README.md127
-rw-r--r--collectors/charts.d.plugin/apache/apache.chart.sh (renamed from charts.d/apache.chart.sh)52
-rw-r--r--collectors/charts.d.plugin/apache/apache.conf (renamed from conf.d/charts.d/apache.conf)0
-rw-r--r--collectors/charts.d.plugin/apcupsd/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/apcupsd/README.md (renamed from python.d/python_modules/bases/FrameworkServices/__init__.py)0
-rw-r--r--collectors/charts.d.plugin/apcupsd/apcupsd.chart.sh (renamed from charts.d/apcupsd.chart.sh)7
-rw-r--r--collectors/charts.d.plugin/apcupsd/apcupsd.conf (renamed from conf.d/charts.d/apcupsd.conf)0
-rw-r--r--collectors/charts.d.plugin/charts.d.conf (renamed from conf.d/charts.d.conf)0
-rwxr-xr-xcollectors/charts.d.plugin/charts.d.dryrun-helper.sh (renamed from plugins.d/charts.d.dryrun-helper.sh)9
-rw-r--r--[-rwxr-xr-x]collectors/charts.d.plugin/charts.d.plugin (renamed from plugins.d/charts.d.plugin)86
-rwxr-xr-xcollectors/charts.d.plugin/charts.d.plugin.in743
-rw-r--r--collectors/charts.d.plugin/cpu_apps/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/cpu_apps/README.md2
-rw-r--r--collectors/charts.d.plugin/cpu_apps/cpu_apps.chart.sh (renamed from charts.d/cpu_apps.chart.sh)3
-rw-r--r--collectors/charts.d.plugin/cpu_apps/cpu_apps.conf (renamed from conf.d/charts.d/cpu_apps.conf)0
-rw-r--r--collectors/charts.d.plugin/cpufreq/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/cpufreq/README.md2
-rw-r--r--collectors/charts.d.plugin/cpufreq/cpufreq.chart.sh (renamed from charts.d/cpufreq.chart.sh)32
-rw-r--r--collectors/charts.d.plugin/cpufreq/cpufreq.conf (renamed from conf.d/charts.d/cpufreq.conf)0
-rw-r--r--collectors/charts.d.plugin/example/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/example/README.md2
-rw-r--r--collectors/charts.d.plugin/example/example.chart.sh (renamed from charts.d/example.chart.sh)15
-rw-r--r--collectors/charts.d.plugin/example/example.conf (renamed from conf.d/charts.d/example.conf)0
-rw-r--r--collectors/charts.d.plugin/exim/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/exim/README.md2
-rw-r--r--collectors/charts.d.plugin/exim/exim.chart.sh (renamed from charts.d/exim.chart.sh)7
-rw-r--r--collectors/charts.d.plugin/exim/exim.conf (renamed from conf.d/charts.d/exim.conf)0
-rw-r--r--collectors/charts.d.plugin/hddtemp/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/hddtemp/README.md28
-rw-r--r--collectors/charts.d.plugin/hddtemp/hddtemp.chart.sh (renamed from charts.d/hddtemp.chart.sh)13
-rw-r--r--collectors/charts.d.plugin/hddtemp/hddtemp.conf (renamed from conf.d/charts.d/hddtemp.conf)0
-rw-r--r--collectors/charts.d.plugin/libreswan/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/libreswan/README.md42
-rw-r--r--collectors/charts.d.plugin/libreswan/libreswan.chart.sh (renamed from charts.d/libreswan.chart.sh)9
-rw-r--r--collectors/charts.d.plugin/libreswan/libreswan.conf (renamed from conf.d/charts.d/libreswan.conf)0
-rw-r--r--collectors/charts.d.plugin/load_average/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/load_average/README.md2
-rw-r--r--collectors/charts.d.plugin/load_average/load_average.chart.sh (renamed from charts.d/load_average.chart.sh)3
-rw-r--r--collectors/charts.d.plugin/load_average/load_average.conf (renamed from conf.d/charts.d/load_average.conf)0
-rw-r--r--collectors/charts.d.plugin/loopsleepms.sh.inc (renamed from plugins.d/loopsleepms.sh.inc)54
-rw-r--r--collectors/charts.d.plugin/mem_apps/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/mem_apps/README.md2
-rw-r--r--collectors/charts.d.plugin/mem_apps/mem_apps.chart.sh (renamed from charts.d/mem_apps.chart.sh)3
-rw-r--r--collectors/charts.d.plugin/mem_apps/mem_apps.conf (renamed from conf.d/charts.d/mem_apps.conf)0
-rw-r--r--collectors/charts.d.plugin/mysql/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/mysql/README.md81
-rw-r--r--collectors/charts.d.plugin/mysql/mysql.chart.sh (renamed from charts.d/mysql.chart.sh)28
-rw-r--r--collectors/charts.d.plugin/mysql/mysql.conf (renamed from conf.d/charts.d/mysql.conf)0
-rw-r--r--collectors/charts.d.plugin/nginx/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/nginx/README.md2
-rw-r--r--collectors/charts.d.plugin/nginx/nginx.chart.sh (renamed from charts.d/nginx.chart.sh)51
-rw-r--r--collectors/charts.d.plugin/nginx/nginx.conf (renamed from conf.d/charts.d/nginx.conf)0
-rw-r--r--collectors/charts.d.plugin/nut/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/nut/README.md59
-rw-r--r--collectors/charts.d.plugin/nut/nut.chart.sh (renamed from charts.d/nut.chart.sh)41
-rw-r--r--collectors/charts.d.plugin/nut/nut.conf (renamed from conf.d/charts.d/nut.conf)5
-rw-r--r--collectors/charts.d.plugin/opensips/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/opensips/README.md (renamed from python.d/python_modules/bases/__init__.py)0
-rw-r--r--collectors/charts.d.plugin/opensips/opensips.chart.sh (renamed from charts.d/opensips.chart.sh)10
-rw-r--r--collectors/charts.d.plugin/opensips/opensips.conf (renamed from conf.d/charts.d/opensips.conf)0
-rw-r--r--collectors/charts.d.plugin/phpfpm/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/phpfpm/README.md2
-rw-r--r--collectors/charts.d.plugin/phpfpm/phpfpm.chart.sh (renamed from charts.d/phpfpm.chart.sh)20
-rw-r--r--collectors/charts.d.plugin/phpfpm/phpfpm.conf (renamed from conf.d/charts.d/phpfpm.conf)0
-rw-r--r--collectors/charts.d.plugin/postfix/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/postfix/README.md26
-rw-r--r--collectors/charts.d.plugin/postfix/postfix.chart.sh (renamed from charts.d/postfix.chart.sh)13
-rw-r--r--collectors/charts.d.plugin/postfix/postfix.conf (renamed from conf.d/charts.d/postfix.conf)0
-rw-r--r--collectors/charts.d.plugin/sensors/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/sensors/README.md52
-rw-r--r--collectors/charts.d.plugin/sensors/sensors.chart.sh (renamed from charts.d/sensors.chart.sh)113
-rw-r--r--collectors/charts.d.plugin/sensors/sensors.conf (renamed from conf.d/charts.d/sensors.conf)0
-rw-r--r--collectors/charts.d.plugin/squid/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/squid/README.md66
-rw-r--r--collectors/charts.d.plugin/squid/squid.chart.sh (renamed from charts.d/squid.chart.sh)21
-rw-r--r--collectors/charts.d.plugin/squid/squid.conf (renamed from conf.d/charts.d/squid.conf)0
-rw-r--r--collectors/charts.d.plugin/tomcat/Makefile.inc13
-rw-r--r--collectors/charts.d.plugin/tomcat/README.md2
-rw-r--r--collectors/charts.d.plugin/tomcat/tomcat.chart.sh (renamed from charts.d/tomcat.chart.sh)7
-rw-r--r--collectors/charts.d.plugin/tomcat/tomcat.conf (renamed from conf.d/charts.d/tomcat.conf)0
-rw-r--r--collectors/checks.plugin/Makefile.am4
-rw-r--r--collectors/checks.plugin/Makefile.in457
-rw-r--r--collectors/checks.plugin/plugin_checks.c (renamed from src/plugin_checks.c)22
-rw-r--r--collectors/checks.plugin/plugin_checks.h29
-rw-r--r--collectors/diskspace.plugin/Makefile.am8
-rw-r--r--collectors/diskspace.plugin/Makefile.in464
-rw-r--r--collectors/diskspace.plugin/README.md5
-rw-r--r--collectors/diskspace.plugin/plugin_diskspace.c (renamed from src/plugin_proc_diskspace.c)29
-rw-r--r--collectors/diskspace.plugin/plugin_diskspace.h34
-rw-r--r--collectors/fping.plugin/Makefile.am24
-rw-r--r--collectors/fping.plugin/Makefile.in (renamed from plugins.d/Makefile.in)120
-rw-r--r--collectors/fping.plugin/README.md96
-rw-r--r--collectors/fping.plugin/fping.conf (renamed from conf.d/fping.conf)0
-rw-r--r--[-rwxr-xr-x]collectors/fping.plugin/fping.plugin (renamed from plugins.d/fping.plugin)34
-rwxr-xr-xcollectors/fping.plugin/fping.plugin.in200
-rw-r--r--collectors/freebsd.plugin/Makefile.am5
-rw-r--r--collectors/freebsd.plugin/Makefile.in457
-rw-r--r--collectors/freebsd.plugin/freebsd_devstat.c (renamed from src/freebsd_devstat.c)40
-rw-r--r--collectors/freebsd.plugin/freebsd_getifaddrs.c (renamed from src/freebsd_getifaddrs.c)156
-rw-r--r--collectors/freebsd.plugin/freebsd_getmntinfo.c (renamed from src/freebsd_getmntinfo.c)12
-rw-r--r--collectors/freebsd.plugin/freebsd_ipfw.c (renamed from src/freebsd_ipfw.c)24
-rw-r--r--collectors/freebsd.plugin/freebsd_kstat_zfs.c (renamed from src/freebsd_kstat_zfs.c)10
-rw-r--r--collectors/freebsd.plugin/freebsd_sysctl.c (renamed from src/freebsd_sysctl.c)191
-rw-r--r--collectors/freebsd.plugin/plugin_freebsd.c (renamed from src/plugin_freebsd.c)6
-rw-r--r--collectors/freebsd.plugin/plugin_freebsd.h74
-rw-r--r--collectors/freeipmi.plugin/Makefile.am8
-rw-r--r--collectors/freeipmi.plugin/Makefile.in464
-rw-r--r--collectors/freeipmi.plugin/README.md180
-rw-r--r--collectors/freeipmi.plugin/freeipmi_plugin.c (renamed from src/freeipmi_plugin.c)104
-rw-r--r--collectors/idlejitter.plugin/Makefile.am8
-rw-r--r--collectors/idlejitter.plugin/Makefile.in464
-rw-r--r--collectors/idlejitter.plugin/README.md13
-rw-r--r--collectors/idlejitter.plugin/plugin_idlejitter.c (renamed from src/plugin_idlejitter.c)8
-rw-r--r--collectors/idlejitter.plugin/plugin_idlejitter.h21
-rw-r--r--collectors/macos.plugin/Makefile.am4
-rw-r--r--collectors/macos.plugin/Makefile.in457
-rw-r--r--collectors/macos.plugin/macos_fw.c (renamed from src/macos_fw.c)5
-rw-r--r--collectors/macos.plugin/macos_mach_smi.c (renamed from src/macos_mach_smi.c)5
-rw-r--r--collectors/macos.plugin/macos_sysctl.c (renamed from src/macos_sysctl.c)20
-rw-r--r--collectors/macos.plugin/plugin_macos.c (renamed from src/plugin_macos.c)4
-rw-r--r--collectors/macos.plugin/plugin_macos.h43
-rw-r--r--collectors/nfacct.plugin/Makefile.am8
-rw-r--r--collectors/nfacct.plugin/Makefile.in464
-rw-r--r--collectors/nfacct.plugin/README.md10
-rw-r--r--collectors/nfacct.plugin/plugin_nfacct.c (renamed from src/plugin_nfacct.c)41
-rw-r--r--collectors/nfacct.plugin/plugin_nfacct.h30
-rw-r--r--collectors/node.d.plugin/Makefile.am59
-rw-r--r--collectors/node.d.plugin/Makefile.in805
-rw-r--r--collectors/node.d.plugin/README.md218
-rw-r--r--collectors/node.d.plugin/fronius/Makefile.inc13
-rw-r--r--collectors/node.d.plugin/fronius/README.md (renamed from conf.d/node.d/fronius.conf.md)53
-rw-r--r--collectors/node.d.plugin/fronius/fronius.node.js (renamed from node.d/fronius.node.js)5
-rw-r--r--collectors/node.d.plugin/named/Makefile.inc13
-rw-r--r--collectors/node.d.plugin/named/README.md (renamed from conf.d/node.d/named.conf.md)2
-rw-r--r--collectors/node.d.plugin/named/named.node.js (renamed from node.d/named.node.js)9
-rw-r--r--collectors/node.d.plugin/node.d.conf (renamed from conf.d/node.d.conf)0
-rw-r--r--[-rwxr-xr-x]collectors/node.d.plugin/node.d.plugin (renamed from plugins.d/node.d.plugin)97
-rwxr-xr-xcollectors/node.d.plugin/node.d.plugin.in303
-rw-r--r--collectors/node.d.plugin/node_modules/asn1-ber.js (renamed from node.d/node_modules/asn1-ber.js)1
-rw-r--r--collectors/node.d.plugin/node_modules/extend.js (renamed from node.d/node_modules/extend.js)1
-rw-r--r--collectors/node.d.plugin/node_modules/lib/ber/errors.js (renamed from node.d/node_modules/lib/ber/errors.js)1
-rw-r--r--collectors/node.d.plugin/node_modules/lib/ber/index.js (renamed from node.d/node_modules/lib/ber/index.js)1
-rw-r--r--collectors/node.d.plugin/node_modules/lib/ber/reader.js (renamed from node.d/node_modules/lib/ber/reader.js)1
-rw-r--r--collectors/node.d.plugin/node_modules/lib/ber/types.js (renamed from node.d/node_modules/lib/ber/types.js)1
-rw-r--r--collectors/node.d.plugin/node_modules/lib/ber/writer.js (renamed from node.d/node_modules/lib/ber/writer.js)1
-rw-r--r--collectors/node.d.plugin/node_modules/net-snmp.js (renamed from node.d/node_modules/net-snmp.js)16
-rw-r--r--collectors/node.d.plugin/node_modules/netdata.js (renamed from node.d/node_modules/netdata.js)2
-rw-r--r--collectors/node.d.plugin/node_modules/pixl-xml.js (renamed from node.d/node_modules/pixl-xml.js)1
-rw-r--r--collectors/node.d.plugin/sma_webbox/Makefile.inc13
-rw-r--r--collectors/node.d.plugin/sma_webbox/README.md (renamed from conf.d/node.d/sma_webbox.conf.md)2
-rw-r--r--collectors/node.d.plugin/sma_webbox/sma_webbox.node.js (renamed from node.d/sma_webbox.node.js)5
-rw-r--r--collectors/node.d.plugin/snmp/Makefile.inc13
-rw-r--r--collectors/node.d.plugin/snmp/README.md (renamed from conf.d/node.d/snmp.conf.md)12
-rw-r--r--collectors/node.d.plugin/snmp/snmp.node.js (renamed from node.d/snmp.node.js)17
-rw-r--r--collectors/node.d.plugin/stiebeleltron/Makefile.inc13
-rw-r--r--collectors/node.d.plugin/stiebeleltron/README.md (renamed from conf.d/node.d/stiebeleltron.conf.md)54
-rw-r--r--collectors/node.d.plugin/stiebeleltron/stiebeleltron.node.js (renamed from node.d/stiebeleltron.node.js)5
-rw-r--r--collectors/plugins.d/Makefile.am11
-rw-r--r--collectors/plugins.d/Makefile.in647
-rw-r--r--collectors/plugins.d/README.md472
-rw-r--r--collectors/plugins.d/plugins_d.c (renamed from src/plugins_d.c)4
-rw-r--r--collectors/plugins.d/plugins_d.h (renamed from src/plugins_d.h)16
-rw-r--r--collectors/proc.plugin/Makefile.am8
-rw-r--r--collectors/proc.plugin/Makefile.in464
-rw-r--r--collectors/proc.plugin/README.md200
-rw-r--r--collectors/proc.plugin/ipc.c (renamed from src/ipc.c)22
-rw-r--r--collectors/proc.plugin/plugin_proc.c (renamed from src/plugin_proc.c)20
-rw-r--r--collectors/proc.plugin/plugin_proc.h (renamed from src/plugin_proc.h)36
-rw-r--r--collectors/proc.plugin/proc_diskstats.c (renamed from src/proc_diskstats.c)455
-rw-r--r--collectors/proc.plugin/proc_interrupts.c (renamed from src/proc_interrupts.c)77
-rw-r--r--collectors/proc.plugin/proc_loadavg.c (renamed from src/proc_loadavg.c)25
-rw-r--r--collectors/proc.plugin/proc_meminfo.c (renamed from src/proc_meminfo.c)71
-rw-r--r--collectors/proc.plugin/proc_net_dev.c (renamed from src/proc_net_dev.c)82
-rw-r--r--collectors/proc.plugin/proc_net_ip_vs_stats.c (renamed from src/proc_net_ip_vs_stats.c)34
-rw-r--r--collectors/proc.plugin/proc_net_netstat.c (renamed from src/proc_net_netstat.c)421
-rw-r--r--collectors/proc.plugin/proc_net_rpc_nfs.c (renamed from src/proc_net_rpc_nfs.c)49
-rw-r--r--collectors/proc.plugin/proc_net_rpc_nfsd.c (renamed from src/proc_net_rpc_nfsd.c)84
-rw-r--r--collectors/proc.plugin/proc_net_sctp_snmp.c352
-rw-r--r--collectors/proc.plugin/proc_net_snmp.c (renamed from src/proc_net_snmp.c)253
-rw-r--r--collectors/proc.plugin/proc_net_snmp6.c (renamed from src/proc_net_snmp6.c)137
-rw-r--r--collectors/proc.plugin/proc_net_sockstat.c (renamed from src/proc_net_sockstat.c)66
-rw-r--r--collectors/proc.plugin/proc_net_sockstat6.c (renamed from src/proc_net_sockstat6.c)36
-rw-r--r--collectors/proc.plugin/proc_net_softnet_stat.c (renamed from src/proc_net_softnet_stat.c)18
-rw-r--r--collectors/proc.plugin/proc_net_stat_conntrack.c (renamed from src/proc_net_stat_conntrack.c)41
-rw-r--r--collectors/proc.plugin/proc_net_stat_synproxy.c (renamed from src/proc_net_stat_synproxy.c)30
-rw-r--r--collectors/proc.plugin/proc_self_mountinfo.c (renamed from src/proc_self_mountinfo.c)4
-rw-r--r--collectors/proc.plugin/proc_self_mountinfo.h (renamed from src/proc_self_mountinfo.h)2
-rw-r--r--collectors/proc.plugin/proc_softirqs.c (renamed from src/proc_softirqs.c)73
-rw-r--r--collectors/proc.plugin/proc_spl_kstat_zfs.c (renamed from src/proc_spl_kstat_zfs.c)8
-rw-r--r--collectors/proc.plugin/proc_stat.c (renamed from src/proc_stat.c)71
-rw-r--r--collectors/proc.plugin/proc_sys_kernel_random_entropy_avail.c (renamed from src/proc_sys_kernel_random_entropy_avail.c)10
-rw-r--r--collectors/proc.plugin/proc_uptime.c (renamed from src/proc_uptime.c)10
-rw-r--r--collectors/proc.plugin/proc_vmstat.c (renamed from src/proc_vmstat.c)26
-rw-r--r--collectors/proc.plugin/sys_devices_system_edac_mc.c (renamed from src/sys_devices_system_edac_mc.c)12
-rw-r--r--collectors/proc.plugin/sys_devices_system_node.c (renamed from src/sys_devices_system_node.c)8
-rw-r--r--collectors/proc.plugin/sys_fs_btrfs.c (renamed from src/sys_fs_btrfs.c)58
-rw-r--r--collectors/proc.plugin/sys_kernel_mm_ksm.c (renamed from src/sys_kernel_mm_ksm.c)22
-rw-r--r--collectors/proc.plugin/zfs_common.c (renamed from src/zfs_common.c)79
-rw-r--r--collectors/proc.plugin/zfs_common.h (renamed from src/zfs_common.h)10
-rw-r--r--collectors/python.d.plugin/Makefile.am (renamed from python.d/Makefile.am)150
-rw-r--r--collectors/python.d.plugin/Makefile.in1987
-rw-r--r--collectors/python.d.plugin/README.md198
-rw-r--r--collectors/python.d.plugin/adaptec_raid/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/adaptec_raid/README.md46
-rw-r--r--collectors/python.d.plugin/adaptec_raid/adaptec_raid.chart.py247
-rw-r--r--collectors/python.d.plugin/adaptec_raid/adaptec_raid.conf55
-rw-r--r--collectors/python.d.plugin/apache/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/apache/README.md59
-rw-r--r--collectors/python.d.plugin/apache/apache.chart.py (renamed from python.d/apache.chart.py)57
-rw-r--r--collectors/python.d.plugin/apache/apache.conf (renamed from conf.d/python.d/apache.conf)2
-rw-r--r--collectors/python.d.plugin/beanstalk/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/beanstalk/README.md103
-rw-r--r--collectors/python.d.plugin/beanstalk/beanstalk.chart.py (renamed from python.d/beanstalk.chart.py)43
-rw-r--r--collectors/python.d.plugin/beanstalk/beanstalk.conf (renamed from conf.d/python.d/beanstalk.conf)0
-rw-r--r--collectors/python.d.plugin/bind_rndc/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/bind_rndc/README.md60
-rw-r--r--collectors/python.d.plugin/bind_rndc/bind_rndc.chart.py (renamed from python.d/bind_rndc.chart.py)77
-rw-r--r--collectors/python.d.plugin/bind_rndc/bind_rndc.conf (renamed from conf.d/python.d/bind_rndc.conf)0
-rw-r--r--collectors/python.d.plugin/boinc/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/boinc/README.md28
-rw-r--r--collectors/python.d.plugin/boinc/boinc.chart.py162
-rw-r--r--collectors/python.d.plugin/boinc/boinc.conf68
-rw-r--r--collectors/python.d.plugin/ceph/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/ceph/README.md32
-rw-r--r--collectors/python.d.plugin/ceph/ceph.chart.py (renamed from python.d/ceph.chart.py)86
-rw-r--r--collectors/python.d.plugin/ceph/ceph.conf (renamed from conf.d/python.d/ceph.conf)0
-rw-r--r--collectors/python.d.plugin/chrony/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/chrony/README.md31
-rw-r--r--collectors/python.d.plugin/chrony/chrony.chart.py (renamed from python.d/chrony.chart.py)69
-rw-r--r--collectors/python.d.plugin/chrony/chrony.conf (renamed from conf.d/python.d/chrony.conf)0
-rw-r--r--collectors/python.d.plugin/couchdb/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/couchdb/README.md35
-rw-r--r--collectors/python.d.plugin/couchdb/couchdb.chart.py (renamed from python.d/couchdb.chart.py)3
-rw-r--r--collectors/python.d.plugin/couchdb/couchdb.conf (renamed from conf.d/python.d/couchdb.conf)0
-rw-r--r--collectors/python.d.plugin/cpufreq/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/cpufreq/README.md30
-rw-r--r--collectors/python.d.plugin/cpufreq/cpufreq.chart.py (renamed from python.d/cpufreq.chart.py)12
-rw-r--r--collectors/python.d.plugin/cpufreq/cpufreq.conf (renamed from conf.d/python.d/cpufreq.conf)0
-rw-r--r--collectors/python.d.plugin/cpuidle/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/cpuidle/README.md11
-rw-r--r--collectors/python.d.plugin/cpuidle/cpuidle.chart.py (renamed from python.d/cpuidle.chart.py)8
-rw-r--r--collectors/python.d.plugin/cpuidle/cpuidle.conf40
-rw-r--r--collectors/python.d.plugin/dns_query_time/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/dns_query_time/README.md10
-rw-r--r--collectors/python.d.plugin/dns_query_time/dns_query_time.chart.py (renamed from python.d/dns_query_time.chart.py)27
-rw-r--r--collectors/python.d.plugin/dns_query_time/dns_query_time.conf (renamed from conf.d/python.d/dns_query_time.conf)0
-rw-r--r--collectors/python.d.plugin/dnsdist/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/dnsdist/README.md54
-rw-r--r--collectors/python.d.plugin/dnsdist/dnsdist.chart.py133
-rw-r--r--collectors/python.d.plugin/dnsdist/dnsdist.conf (renamed from conf.d/python.d/dnsdist.conf)0
-rw-r--r--collectors/python.d.plugin/dockerd/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/dockerd/README.md26
-rw-r--r--collectors/python.d.plugin/dockerd/dockerd.chart.py77
-rw-r--r--collectors/python.d.plugin/dockerd/dockerd.conf79
-rw-r--r--collectors/python.d.plugin/dovecot/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/dovecot/README.md73
-rw-r--r--collectors/python.d.plugin/dovecot/dovecot.chart.py (renamed from python.d/dovecot.chart.py)87
-rw-r--r--collectors/python.d.plugin/dovecot/dovecot.conf (renamed from conf.d/python.d/dovecot.conf)0
-rw-r--r--collectors/python.d.plugin/elasticsearch/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/elasticsearch/README.md60
-rw-r--r--collectors/python.d.plugin/elasticsearch/elasticsearch.chart.py (renamed from python.d/elasticsearch.chart.py)220
-rw-r--r--collectors/python.d.plugin/elasticsearch/elasticsearch.conf (renamed from conf.d/python.d/elasticsearch.conf)0
-rw-r--r--collectors/python.d.plugin/example/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/example/README.md1
-rw-r--r--collectors/python.d.plugin/example/example.chart.py (renamed from python.d/example.chart.py)3
-rw-r--r--collectors/python.d.plugin/example/example.conf (renamed from conf.d/python.d/example.conf)0
-rw-r--r--collectors/python.d.plugin/exim/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/exim/README.md13
-rw-r--r--collectors/python.d.plugin/exim/exim.chart.py (renamed from python.d/exim.chart.py)8
-rw-r--r--collectors/python.d.plugin/exim/exim.conf (renamed from conf.d/python.d/exim.conf)0
-rw-r--r--collectors/python.d.plugin/fail2ban/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/fail2ban/README.md23
-rw-r--r--collectors/python.d.plugin/fail2ban/fail2ban.chart.py196
-rw-r--r--collectors/python.d.plugin/fail2ban/fail2ban.conf (renamed from conf.d/python.d/fail2ban.conf)0
-rw-r--r--collectors/python.d.plugin/freeradius/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/freeradius/README.md70
-rw-r--r--collectors/python.d.plugin/freeradius/freeradius.chart.py (renamed from python.d/freeradius.chart.py)24
-rw-r--r--collectors/python.d.plugin/freeradius/freeradius.conf (renamed from conf.d/python.d/freeradius.conf)0
-rw-r--r--collectors/python.d.plugin/go_expvar/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/go_expvar/README.md276
-rw-r--r--collectors/python.d.plugin/go_expvar/go_expvar.chart.py (renamed from python.d/go_expvar.chart.py)22
-rw-r--r--collectors/python.d.plugin/go_expvar/go_expvar.conf (renamed from conf.d/python.d/go_expvar.conf)2
-rw-r--r--collectors/python.d.plugin/haproxy/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/haproxy/README.md49
-rw-r--r--collectors/python.d.plugin/haproxy/haproxy.chart.py (renamed from python.d/haproxy.chart.py)243
-rw-r--r--collectors/python.d.plugin/haproxy/haproxy.conf (renamed from conf.d/python.d/haproxy.conf)0
-rw-r--r--collectors/python.d.plugin/hddtemp/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/hddtemp/README.md22
-rw-r--r--collectors/python.d.plugin/hddtemp/hddtemp.chart.py100
-rw-r--r--collectors/python.d.plugin/hddtemp/hddtemp.conf (renamed from conf.d/python.d/hddtemp.conf)0
-rw-r--r--collectors/python.d.plugin/httpcheck/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/httpcheck/README.md41
-rw-r--r--collectors/python.d.plugin/httpcheck/httpcheck.chart.py (renamed from python.d/httpcheck.chart.py)18
-rw-r--r--collectors/python.d.plugin/httpcheck/httpcheck.conf (renamed from conf.d/python.d/httpcheck.conf)1
-rw-r--r--collectors/python.d.plugin/icecast/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/icecast/README.md26
-rw-r--r--collectors/python.d.plugin/icecast/icecast.chart.py (renamed from python.d/icecast.chart.py)15
-rw-r--r--collectors/python.d.plugin/icecast/icecast.conf (renamed from conf.d/python.d/icecast.conf)0
-rw-r--r--collectors/python.d.plugin/ipfs/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/ipfs/README.md25
-rw-r--r--collectors/python.d.plugin/ipfs/ipfs.chart.py (renamed from python.d/ipfs.chart.py)60
-rw-r--r--collectors/python.d.plugin/ipfs/ipfs.conf (renamed from conf.d/python.d/ipfs.conf)9
-rw-r--r--collectors/python.d.plugin/isc_dhcpd/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/isc_dhcpd/README.md34
-rw-r--r--collectors/python.d.plugin/isc_dhcpd/isc_dhcpd.chart.py (renamed from python.d/isc_dhcpd.chart.py)20
-rw-r--r--collectors/python.d.plugin/isc_dhcpd/isc_dhcpd.conf (renamed from conf.d/python.d/isc_dhcpd.conf)0
-rw-r--r--collectors/python.d.plugin/linux_power_supply/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/linux_power_supply/README.md67
-rw-r--r--collectors/python.d.plugin/linux_power_supply/linux_power_supply.chart.py160
-rw-r--r--collectors/python.d.plugin/linux_power_supply/linux_power_supply.conf81
-rw-r--r--collectors/python.d.plugin/litespeed/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/litespeed/README.md47
-rw-r--r--collectors/python.d.plugin/litespeed/litespeed.chart.py186
-rw-r--r--collectors/python.d.plugin/litespeed/litespeed.conf74
-rw-r--r--collectors/python.d.plugin/logind/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/logind/README.md54
-rw-r--r--collectors/python.d.plugin/logind/logind.chart.py79
-rw-r--r--collectors/python.d.plugin/logind/logind.conf62
-rw-r--r--collectors/python.d.plugin/mdstat/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/mdstat/README.md26
-rw-r--r--collectors/python.d.plugin/mdstat/mdstat.chart.py205
-rw-r--r--collectors/python.d.plugin/mdstat/mdstat.conf (renamed from conf.d/python.d/mdstat.conf)0
-rw-r--r--collectors/python.d.plugin/megacli/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/megacli/README.md48
-rw-r--r--collectors/python.d.plugin/megacli/megacli.chart.py279
-rw-r--r--collectors/python.d.plugin/megacli/megacli.conf62
-rw-r--r--collectors/python.d.plugin/memcached/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/memcached/README.md69
-rw-r--r--collectors/python.d.plugin/memcached/memcached.chart.py (renamed from python.d/memcached.chart.py)61
-rw-r--r--collectors/python.d.plugin/memcached/memcached.conf (renamed from conf.d/python.d/memcached.conf)0
-rw-r--r--collectors/python.d.plugin/mongodb/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/mongodb/README.md141
-rw-r--r--collectors/python.d.plugin/mongodb/mongodb.chart.py (renamed from python.d/mongodb.chart.py)150
-rw-r--r--collectors/python.d.plugin/mongodb/mongodb.conf (renamed from conf.d/python.d/mongodb.conf)0
-rw-r--r--collectors/python.d.plugin/monit/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/monit/README.md33
-rw-r--r--collectors/python.d.plugin/monit/monit.chart.py166
-rw-r--r--collectors/python.d.plugin/monit/monit.conf88
-rw-r--r--collectors/python.d.plugin/mysql/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/mysql/README.md90
-rw-r--r--collectors/python.d.plugin/mysql/mysql.chart.py (renamed from python.d/mysql.chart.py)451
-rw-r--r--collectors/python.d.plugin/mysql/mysql.conf (renamed from conf.d/python.d/mysql.conf)0
-rw-r--r--collectors/python.d.plugin/nginx/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/nginx/README.md45
-rw-r--r--collectors/python.d.plugin/nginx/nginx.chart.py (renamed from python.d/nginx.chart.py)27
-rw-r--r--collectors/python.d.plugin/nginx/nginx.conf (renamed from conf.d/python.d/nginx.conf)0
-rw-r--r--collectors/python.d.plugin/nginx_plus/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/nginx_plus/README.md125
-rw-r--r--collectors/python.d.plugin/nginx_plus/nginx_plus.chart.py (renamed from python.d/nginx_plus.chart.py)107
-rw-r--r--collectors/python.d.plugin/nginx_plus/nginx_plus.conf (renamed from conf.d/python.d/nginx_plus.conf)0
-rw-r--r--collectors/python.d.plugin/nsd/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/nsd/README.md54
-rw-r--r--collectors/python.d.plugin/nsd/nsd.chart.py (renamed from python.d/nsd.chart.py)45
-rw-r--r--collectors/python.d.plugin/nsd/nsd.conf (renamed from conf.d/python.d/nsd.conf)0
-rw-r--r--collectors/python.d.plugin/ntpd/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/ntpd/README.md71
-rw-r--r--collectors/python.d.plugin/ntpd/ntpd.chart.py (renamed from python.d/ntpd.chart.py)80
-rw-r--r--collectors/python.d.plugin/ntpd/ntpd.conf (renamed from conf.d/python.d/ntpd.conf)0
-rw-r--r--collectors/python.d.plugin/ovpn_status_log/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/ovpn_status_log/README.md32
-rw-r--r--collectors/python.d.plugin/ovpn_status_log/ovpn_status_log.chart.py (renamed from python.d/ovpn_status_log.chart.py)27
-rw-r--r--collectors/python.d.plugin/ovpn_status_log/ovpn_status_log.conf (renamed from conf.d/python.d/ovpn_status_log.conf)6
-rw-r--r--collectors/python.d.plugin/phpfpm/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/phpfpm/README.md40
-rw-r--r--collectors/python.d.plugin/phpfpm/phpfpm.chart.py (renamed from python.d/phpfpm.chart.py)20
-rw-r--r--collectors/python.d.plugin/phpfpm/phpfpm.conf (renamed from conf.d/python.d/phpfpm.conf)2
-rw-r--r--collectors/python.d.plugin/portcheck/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/portcheck/README.md35
-rw-r--r--collectors/python.d.plugin/portcheck/portcheck.chart.py (renamed from python.d/portcheck.chart.py)12
-rw-r--r--collectors/python.d.plugin/portcheck/portcheck.conf (renamed from conf.d/python.d/portcheck.conf)0
-rw-r--r--collectors/python.d.plugin/postfix/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/postfix/README.md15
-rw-r--r--collectors/python.d.plugin/postfix/postfix.chart.py (renamed from python.d/postfix.chart.py)15
-rw-r--r--collectors/python.d.plugin/postfix/postfix.conf (renamed from conf.d/python.d/postfix.conf)0
-rw-r--r--collectors/python.d.plugin/postgres/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/postgres/README.md68
-rw-r--r--collectors/python.d.plugin/postgres/postgres.chart.py (renamed from python.d/postgres.chart.py)593
-rw-r--r--collectors/python.d.plugin/postgres/postgres.conf (renamed from conf.d/python.d/postgres.conf)0
-rw-r--r--collectors/python.d.plugin/powerdns/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/powerdns/README.md77
-rw-r--r--collectors/python.d.plugin/powerdns/powerdns.chart.py150
-rw-r--r--collectors/python.d.plugin/powerdns/powerdns.conf (renamed from conf.d/python.d/powerdns.conf)0
-rw-r--r--collectors/python.d.plugin/proxysql/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/proxysql/README.md62
-rw-r--r--collectors/python.d.plugin/proxysql/proxysql.chart.py356
-rw-r--r--collectors/python.d.plugin/proxysql/proxysql.conf118
-rw-r--r--collectors/python.d.plugin/puppet/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/puppet/README.md48
-rw-r--r--collectors/python.d.plugin/puppet/puppet.chart.py121
-rw-r--r--collectors/python.d.plugin/puppet/puppet.conf98
-rw-r--r--collectors/python.d.plugin/python.d.conf (renamed from conf.d/python.d.conf)30
-rw-r--r--[-rwxr-xr-x]collectors/python.d.plugin/python.d.plugin (renamed from plugins.d/python.d.plugin)121
-rwxr-xr-xcollectors/python.d.plugin/python.d.plugin.in427
-rw-r--r--collectors/python.d.plugin/python_modules/__init__.py (renamed from python.d/python_modules/third_party/__init__.py)0
-rw-r--r--collectors/python.d.plugin/python_modules/bases/FrameworkServices/ExecutableService.py (renamed from python.d/python_modules/bases/FrameworkServices/ExecutableService.py)9
-rw-r--r--collectors/python.d.plugin/python_modules/bases/FrameworkServices/LogService.py (renamed from python.d/python_modules/bases/FrameworkServices/LogService.py)2
-rw-r--r--collectors/python.d.plugin/python_modules/bases/FrameworkServices/MySQLService.py (renamed from python.d/python_modules/bases/FrameworkServices/MySQLService.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/bases/FrameworkServices/SimpleService.py (renamed from python.d/python_modules/bases/FrameworkServices/SimpleService.py)13
-rw-r--r--collectors/python.d.plugin/python_modules/bases/FrameworkServices/SocketService.py (renamed from python.d/python_modules/bases/FrameworkServices/SocketService.py)64
-rw-r--r--collectors/python.d.plugin/python_modules/bases/FrameworkServices/UrlService.py (renamed from python.d/python_modules/bases/FrameworkServices/UrlService.py)32
-rw-r--r--collectors/python.d.plugin/python_modules/bases/FrameworkServices/__init__.py (renamed from python.d/python_modules/urllib3/contrib/__init__.py)0
-rw-r--r--collectors/python.d.plugin/python_modules/bases/__init__.py (renamed from python.d/python_modules/urllib3/contrib/_securetransport/__init__.py)0
-rw-r--r--collectors/python.d.plugin/python_modules/bases/charts.py (renamed from python.d/python_modules/bases/charts.py)18
-rw-r--r--collectors/python.d.plugin/python_modules/bases/collection.py (renamed from python.d/python_modules/bases/collection.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/bases/loaders.py (renamed from python.d/python_modules/bases/loaders.py)21
-rw-r--r--collectors/python.d.plugin/python_modules/bases/loggers.py (renamed from python.d/python_modules/bases/loggers.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/__init__.py (renamed from python.d/python_modules/pyyaml2/__init__.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/composer.py (renamed from python.d/python_modules/pyyaml2/composer.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/constructor.py (renamed from python.d/python_modules/pyyaml2/constructor.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/cyaml.py (renamed from python.d/python_modules/pyyaml2/cyaml.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/dumper.py (renamed from python.d/python_modules/pyyaml2/dumper.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/emitter.py (renamed from python.d/python_modules/pyyaml2/emitter.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/error.py (renamed from python.d/python_modules/pyyaml2/error.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/events.py (renamed from python.d/python_modules/pyyaml2/events.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/loader.py (renamed from python.d/python_modules/pyyaml2/loader.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/nodes.py (renamed from python.d/python_modules/pyyaml2/nodes.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/parser.py (renamed from python.d/python_modules/pyyaml2/parser.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/reader.py (renamed from python.d/python_modules/pyyaml2/reader.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/representer.py (renamed from python.d/python_modules/pyyaml2/representer.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/resolver.py (renamed from python.d/python_modules/pyyaml2/resolver.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/scanner.py (renamed from python.d/python_modules/pyyaml2/scanner.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/serializer.py (renamed from python.d/python_modules/pyyaml2/serializer.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml2/tokens.py (renamed from python.d/python_modules/pyyaml2/tokens.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/__init__.py (renamed from python.d/python_modules/pyyaml3/__init__.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/composer.py (renamed from python.d/python_modules/pyyaml3/composer.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/constructor.py (renamed from python.d/python_modules/pyyaml3/constructor.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/cyaml.py (renamed from python.d/python_modules/pyyaml3/cyaml.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/dumper.py (renamed from python.d/python_modules/pyyaml3/dumper.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/emitter.py (renamed from python.d/python_modules/pyyaml3/emitter.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/error.py (renamed from python.d/python_modules/pyyaml3/error.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/events.py (renamed from python.d/python_modules/pyyaml3/events.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/loader.py (renamed from python.d/python_modules/pyyaml3/loader.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/nodes.py (renamed from python.d/python_modules/pyyaml3/nodes.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/parser.py (renamed from python.d/python_modules/pyyaml3/parser.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/reader.py (renamed from python.d/python_modules/pyyaml3/reader.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/representer.py (renamed from python.d/python_modules/pyyaml3/representer.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/resolver.py (renamed from python.d/python_modules/pyyaml3/resolver.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/scanner.py (renamed from python.d/python_modules/pyyaml3/scanner.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/serializer.py (renamed from python.d/python_modules/pyyaml3/serializer.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/pyyaml3/tokens.py (renamed from python.d/python_modules/pyyaml3/tokens.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/third_party/__init__.py (renamed from python.d/python_modules/urllib3/packages/backports/__init__.py)0
-rw-r--r--collectors/python.d.plugin/python_modules/third_party/boinc_client.py515
-rw-r--r--collectors/python.d.plugin/python_modules/third_party/lm_sensors.py (renamed from python.d/python_modules/third_party/lm_sensors.py)3
-rw-r--r--collectors/python.d.plugin/python_modules/third_party/mcrcon.py74
-rw-r--r--collectors/python.d.plugin/python_modules/third_party/monotonic.py171
-rw-r--r--collectors/python.d.plugin/python_modules/third_party/ordereddict.py (renamed from python.d/python_modules/third_party/ordereddict.py)20
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/__init__.py (renamed from python.d/python_modules/urllib3/__init__.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/_collections.py (renamed from python.d/python_modules/urllib3/_collections.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/connection.py (renamed from python.d/python_modules/urllib3/connection.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/connectionpool.py (renamed from python.d/python_modules/urllib3/connectionpool.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/contrib/__init__.py (renamed from src/.keep)0
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/contrib/_securetransport/__init__.py0
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/contrib/_securetransport/bindings.py (renamed from python.d/python_modules/urllib3/contrib/_securetransport/bindings.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/contrib/_securetransport/low_level.py (renamed from python.d/python_modules/urllib3/contrib/_securetransport/low_level.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/contrib/appengine.py (renamed from python.d/python_modules/urllib3/contrib/appengine.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/contrib/ntlmpool.py (renamed from python.d/python_modules/urllib3/contrib/ntlmpool.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/contrib/pyopenssl.py (renamed from python.d/python_modules/urllib3/contrib/pyopenssl.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/contrib/securetransport.py (renamed from python.d/python_modules/urllib3/contrib/securetransport.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/contrib/socks.py (renamed from python.d/python_modules/urllib3/contrib/socks.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/exceptions.py (renamed from python.d/python_modules/urllib3/exceptions.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/fields.py (renamed from python.d/python_modules/urllib3/fields.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/filepost.py (renamed from python.d/python_modules/urllib3/filepost.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/packages/__init__.py (renamed from python.d/python_modules/urllib3/packages/__init__.py)0
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/packages/backports/__init__.py0
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/packages/backports/makefile.py (renamed from python.d/python_modules/urllib3/packages/backports/makefile.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/packages/ordered_dict.py (renamed from python.d/python_modules/urllib3/packages/ordered_dict.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/packages/six.py (renamed from python.d/python_modules/urllib3/packages/six.py)18
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/packages/ssl_match_hostname/__init__.py (renamed from python.d/python_modules/urllib3/packages/ssl_match_hostname/__init__.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/packages/ssl_match_hostname/_implementation.py (renamed from python.d/python_modules/urllib3/packages/ssl_match_hostname/_implementation.py)3
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/poolmanager.py (renamed from python.d/python_modules/urllib3/poolmanager.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/request.py (renamed from python.d/python_modules/urllib3/request.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/response.py (renamed from python.d/python_modules/urllib3/response.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/util/__init__.py (renamed from python.d/python_modules/urllib3/util/__init__.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/util/connection.py (renamed from python.d/python_modules/urllib3/util/connection.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/util/request.py (renamed from python.d/python_modules/urllib3/util/request.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/util/response.py (renamed from python.d/python_modules/urllib3/util/response.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/util/retry.py (renamed from python.d/python_modules/urllib3/util/retry.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/util/selectors.py (renamed from python.d/python_modules/urllib3/util/selectors.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/util/ssl_.py (renamed from python.d/python_modules/urllib3/util/ssl_.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/util/timeout.py (renamed from python.d/python_modules/urllib3/util/timeout.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/util/url.py (renamed from python.d/python_modules/urllib3/util/url.py)1
-rw-r--r--collectors/python.d.plugin/python_modules/urllib3/util/wait.py (renamed from python.d/python_modules/urllib3/util/wait.py)1
-rw-r--r--collectors/python.d.plugin/rabbitmq/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/rabbitmq/README.md56
-rw-r--r--collectors/python.d.plugin/rabbitmq/rabbitmq.chart.py (renamed from python.d/rabbitmq.chart.py)112
-rw-r--r--collectors/python.d.plugin/rabbitmq/rabbitmq.conf (renamed from conf.d/python.d/rabbitmq.conf)0
-rw-r--r--collectors/python.d.plugin/redis/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/redis/README.md42
-rw-r--r--collectors/python.d.plugin/redis/redis.chart.py261
-rw-r--r--collectors/python.d.plugin/redis/redis.conf (renamed from conf.d/python.d/redis.conf)0
-rw-r--r--collectors/python.d.plugin/rethinkdbs/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/rethinkdbs/README.md34
-rw-r--r--collectors/python.d.plugin/rethinkdbs/rethinkdbs.chart.py235
-rw-r--r--collectors/python.d.plugin/rethinkdbs/rethinkdbs.conf78
-rw-r--r--collectors/python.d.plugin/retroshare/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/retroshare/README.md1
-rw-r--r--collectors/python.d.plugin/retroshare/retroshare.chart.py (renamed from python.d/retroshare.chart.py)10
-rw-r--r--collectors/python.d.plugin/retroshare/retroshare.conf (renamed from conf.d/python.d/retroshare.conf)0
-rw-r--r--collectors/python.d.plugin/samba/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/samba/README.md67
-rw-r--r--collectors/python.d.plugin/samba/samba.chart.py138
-rw-r--r--collectors/python.d.plugin/samba/samba.conf (renamed from conf.d/python.d/samba.conf)0
-rw-r--r--collectors/python.d.plugin/sensors/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/sensors/README.md17
-rw-r--r--collectors/python.d.plugin/sensors/sensors.chart.py (renamed from python.d/sensors.chart.py)29
-rw-r--r--collectors/python.d.plugin/sensors/sensors.conf (renamed from conf.d/python.d/sensors.conf)0
-rw-r--r--collectors/python.d.plugin/smartd_log/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/smartd_log/README.md38
-rw-r--r--collectors/python.d.plugin/smartd_log/smartd_log.chart.py (renamed from python.d/smartd_log.chart.py)9
-rw-r--r--collectors/python.d.plugin/smartd_log/smartd_log.conf (renamed from conf.d/python.d/smartd_log.conf)0
-rw-r--r--collectors/python.d.plugin/spigotmc/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/spigotmc/README.md22
-rw-r--r--collectors/python.d.plugin/spigotmc/spigotmc.chart.py120
-rw-r--r--collectors/python.d.plugin/spigotmc/spigotmc.conf68
-rw-r--r--collectors/python.d.plugin/springboot/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/springboot/README.md129
-rw-r--r--collectors/python.d.plugin/springboot/springboot.chart.py (renamed from python.d/springboot.chart.py)96
-rw-r--r--collectors/python.d.plugin/springboot/springboot.conf (renamed from conf.d/python.d/springboot.conf)0
-rw-r--r--collectors/python.d.plugin/squid/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/squid/README.md38
-rw-r--r--collectors/python.d.plugin/squid/squid.chart.py (renamed from python.d/squid.chart.py)75
-rw-r--r--collectors/python.d.plugin/squid/squid.conf (renamed from conf.d/python.d/squid.conf)0
-rw-r--r--collectors/python.d.plugin/tomcat/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/tomcat/README.md33
-rw-r--r--collectors/python.d.plugin/tomcat/tomcat.chart.py (renamed from python.d/tomcat.chart.py)110
-rw-r--r--collectors/python.d.plugin/tomcat/tomcat.conf (renamed from conf.d/python.d/tomcat.conf)0
-rw-r--r--collectors/python.d.plugin/traefik/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/traefik/README.md54
-rw-r--r--collectors/python.d.plugin/traefik/traefik.chart.py (renamed from python.d/traefik.chart.py)40
-rw-r--r--collectors/python.d.plugin/traefik/traefik.conf (renamed from conf.d/python.d/traefik.conf)0
-rw-r--r--collectors/python.d.plugin/unbound/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/unbound/README.md76
-rw-r--r--collectors/python.d.plugin/unbound/unbound.chart.py275
-rw-r--r--collectors/python.d.plugin/unbound/unbound.conf87
-rw-r--r--collectors/python.d.plugin/uwsgi/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/uwsgi/README.md37
-rw-r--r--collectors/python.d.plugin/uwsgi/uwsgi.chart.py183
-rw-r--r--collectors/python.d.plugin/uwsgi/uwsgi.conf94
-rw-r--r--collectors/python.d.plugin/varnish/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/varnish/README.md69
-rw-r--r--collectors/python.d.plugin/varnish/varnish.chart.py (renamed from python.d/varnish.chart.py)29
-rw-r--r--collectors/python.d.plugin/varnish/varnish.conf (renamed from conf.d/python.d/varnish.conf)0
-rw-r--r--collectors/python.d.plugin/w1sensor/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/w1sensor/README.md13
-rw-r--r--collectors/python.d.plugin/w1sensor/w1sensor.chart.py93
-rw-r--r--collectors/python.d.plugin/w1sensor/w1sensor.conf74
-rw-r--r--collectors/python.d.plugin/web_log/Makefile.inc13
-rw-r--r--collectors/python.d.plugin/web_log/README.md64
-rw-r--r--collectors/python.d.plugin/web_log/web_log.chart.py (renamed from python.d/web_log.chart.py)359
-rw-r--r--collectors/python.d.plugin/web_log/web_log.conf (renamed from conf.d/python.d/web_log.conf)13
-rw-r--r--collectors/statsd.plugin/Makefile.am20
-rw-r--r--collectors/statsd.plugin/Makefile.in (renamed from node.d/Makefile.in)149
-rw-r--r--collectors/statsd.plugin/README.md523
-rw-r--r--collectors/statsd.plugin/example.conf (renamed from conf.d/statsd.d/example.conf)23
-rw-r--r--collectors/statsd.plugin/statsd.c (renamed from src/statsd.c)373
-rw-r--r--collectors/statsd.plugin/statsd.h25
-rw-r--r--collectors/tc.plugin/Makefile.am20
-rw-r--r--collectors/tc.plugin/Makefile.in562
-rw-r--r--collectors/tc.plugin/README.md183
-rw-r--r--collectors/tc.plugin/plugin_tc.c (renamed from src/plugin_tc.c)58
-rw-r--r--collectors/tc.plugin/plugin_tc.h31
-rw-r--r--[-rwxr-xr-x]collectors/tc.plugin/tc-qos-helper.sh (renamed from plugins.d/tc-qos-helper.sh)110
-rwxr-xr-xcollectors/tc.plugin/tc-qos-helper.sh.in315
589 files changed, 33591 insertions, 3976 deletions
diff --git a/collectors/Makefile.am b/collectors/Makefile.am
new file mode 100644
index 000000000..4ecd1f176
--- /dev/null
+++ b/collectors/Makefile.am
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+SUBDIRS = \
+ plugins.d \
+ apps.plugin \
+ cgroups.plugin \
+ charts.d.plugin \
+ checks.plugin \
+ diskspace.plugin \
+ fping.plugin \
+ freebsd.plugin \
+ freeipmi.plugin \
+ idlejitter.plugin \
+ macos.plugin \
+ nfacct.plugin \
+ node.d.plugin \
+ proc.plugin \
+ python.d.plugin \
+ statsd.plugin \
+ tc.plugin \
+ $(NULL)
+
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
diff --git a/collectors/Makefile.in b/collectors/Makefile.in
new file mode 100644
index 000000000..357f69d7a
--- /dev/null
+++ b/collectors/Makefile.in
@@ -0,0 +1,663 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(dist_noinst_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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
+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 \
+ distdir
+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
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+SUBDIRS = \
+ plugins.d \
+ apps.plugin \
+ cgroups.plugin \
+ charts.d.plugin \
+ checks.plugin \
+ diskspace.plugin \
+ fping.plugin \
+ freebsd.plugin \
+ freeipmi.plugin \
+ idlejitter.plugin \
+ macos.plugin \
+ nfacct.plugin \
+ node.d.plugin \
+ proc.plugin \
+ python.d.plugin \
+ statsd.plugin \
+ tc.plugin \
+ $(NULL)
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+# 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; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(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
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-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
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @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; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic cscopelist-am ctags ctags-am \
+ distclean distclean-generic distclean-tags 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 installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/collectors/README.md b/collectors/README.md
new file mode 100644
index 000000000..b7fc73286
--- /dev/null
+++ b/collectors/README.md
@@ -0,0 +1,118 @@
+# Data Collection Plugins
+
+netdata supports **internal** and **external** data collection plugins:
+
+- **internal** plugins are written in `C` and run as threads inside the netdata daemon.
+
+- **external** plugins may be written in any computer language and are spawn as independent long-running processes by the netdata daemon.
+ They communicate with the netdata daemon via `pipes` (`stdout` communication).
+
+To minimize the number of processes spawn for data collection, netdata also supports **plugin orchestrators**.
+
+- **plugin orchestrators** are external plugins that do not collect any data by themeselves.
+ Instead they support data collection **modules** written in the language of the orchestrator.
+ Usually the orchestrator provides a higher level abstraction, making it ideal for writing new
+ data collection modules with the minimum of code.
+
+ Currently netdata provides plugin orchestrators
+ BASH v4+ [charts.d.plugin](charts.d.plugin),
+ node.js [node.d.plugin](node.d.plugin) and
+ python v2+ (including v3) [python.d.plugin](python.d.plugin).
+
+## Netdata Plugins
+
+plugin|lang|O/S|runs as|modular|description
+:---:|:---:|:---:|:---:|:---:|:---
+[apps.plugin](apps.plugin/)|`C`|linux, freebsd|external|-|monitors the whole process tree on Linux and FreeBSD and breaks down system resource usage by **process**, **user** and **user group**.
+[cgroups.plugin](cgroups.plugin/)|`C`|linux|internal|-|collects resource usage of **Containers**, libvirt **VMs** and **systemd services**, on Linux systems
+[charts.d.plugin](charts.d.plugin/)|`BASH` v4+|any|external|yes|a **plugin orchestrator** for data collection modules written in `BASH` v4+.
+[checks.plugin](checks.plugin/)|`C`|any|internal|-|a debugging plugin (by default it is disabled)
+[diskspace.plugin](diskspace.plugin/)|`C`|linux|internal|-|collects disk space usage metrics on Linux mount points
+[fping.plugin](fping.plugin/)|`C`|any|external|-|measures network latency, jitter and packet loss between the monitored node and any number of remote network end points.
+[freebsd.plugin](freebsd.plugin/)|`C`|freebsd|internal|yes|collects resource usage and performance data on FreeBSD systems
+[freeipmi.plugin](freeipmi.plugin/)|`C`|linux, freebsd|external|-|collects metrics from enterprise hardware sensors, on Linux and FreeBSD servers.
+[idlejitter.plugin](idlejitter.plugin/)|`C`|any|internal|-|measures CPU latency and jitter on all operating systems
+[macos.plugin](macos.plugin/)|`C`|macos|internal|yes|collects resource usage and performance data on MacOS systems
+[nfacct.plugin](nfacct.plugin/)|`C`|linux|internal|-|collects netfilter firewall, connection tracker and accounting metrics using `libmnl` and `libnetfilter_acct`
+[node.d.plugin](node.d.plugin/)|`node.js`|any|external|yes|a **plugin orchestrator** for data collection modules written in `node.js`.
+[plugins.d](plugins.d/)|`C`|any|internal|-|implements the **external plugins** API and serves external plugins
+[proc.plugin](proc.plugin/)|`C`|linux|internal|yes|collects resource usage and performance data on Linux systems
+[python.d.plugin](python.d.plugin/)|`python` v2+|any|external|yes|a **plugin orchestrator** for data collection modules written in `python` v2 or v3 (both are supported).
+[statsd.plugin](statsd.plugin/)|`C`|any|internal|-|implements a high performance **statsd** server for netdata
+[tc.plugin](tc.plugin/)|`C`|linux|internal|-|collects traffic QoS metrics (`tc`) of Linux network interfaces
+
+## Enabling and Disabling plugins
+
+Each plugin can be enabled or disabled via `netdata.conf`, section `[plugins]`.
+
+At this section there a list of all the plugins with a boolean setting to enable them or disable them.
+
+The exception is `statsd.plugin` that has its own `[statsd]` section.
+
+Once a plugin is enabled, consult the page of each plugin for additional configuration options.
+
+All **external plugins** are managed by [plugins.d](plugins.d/), which provides additional management options.
+
+### Internal Plugins
+
+Each of the internal plugins runs as a thread inside the netdata daemon.
+Once this thread has started, the plugin may spawn additional threads according to its design.
+
+#### Internal Plugins API
+
+The internal data collection API consists of the following calls:
+
+```c
+collect_data() {
+ // collect data here (one iteration)
+
+ collected_number collected_value = collect_a_value();
+
+ // give the metrics to netdata
+
+ static RRDSET *st = NULL; // the chart
+ static RRDDIM *rd = NULL; // a dimension attached to this chart
+
+ if(unlikely(!st)) {
+ // we haven't created this chart before
+ // create it now
+ st = rrdset_create_localhost(
+ "type"
+ , "id"
+ , "name"
+ , "family"
+ , "context"
+ , "Chart Title"
+ , "units"
+ , "plugin-name"
+ , "module-name"
+ , priority
+ , update_every
+ , chart_type
+ );
+
+ // attach a metric to it
+ rd = rrddim_add(st, "id", "name", multiplier, divider, algorithm);
+ }
+ else {
+ // this chart is already created
+ // let netdata know we start a new iteration on it
+ rrdset_next(st);
+ }
+
+ // give the collected value(s) to the chart
+ rrddim_set_by_pointer(st, rd, collected_value);
+
+ // signal netdata we are done with this iteration
+ rrdset_done(st);
+}
+```
+
+Of course netdata has a lot of libraries to help you also in collecting the metrics.
+The best way to find your way through this, is to examine what other similar plugins do.
+
+
+### External Plugins
+
+**External plugins** use the API and are managed by [plugins.d](plugins.d/).
+
diff --git a/collectors/all.h b/collectors/all.h
new file mode 100644
index 000000000..aa19bd5bd
--- /dev/null
+++ b/collectors/all.h
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_ALL_H
+#define NETDATA_ALL_H 1
+
+#include "../daemon/common.h"
+
+// netdata internal data collection plugins
+
+#include "checks.plugin/plugin_checks.h"
+#include "freebsd.plugin/plugin_freebsd.h"
+#include "idlejitter.plugin/plugin_idlejitter.h"
+#include "cgroups.plugin/sys_fs_cgroup.h"
+#include "diskspace.plugin/plugin_diskspace.h"
+#include "nfacct.plugin/plugin_nfacct.h"
+#include "proc.plugin/plugin_proc.h"
+#include "tc.plugin/plugin_tc.h"
+#include "macos.plugin/plugin_macos.h"
+#include "statsd.plugin/statsd.h"
+
+#include "plugins.d/plugins_d.h"
+
+
+// ----------------------------------------------------------------------------
+// netdata chart priorities
+
+// This is a work in progress - to scope is to collect here all chart priorities.
+// These should be based on the CONTEXT of the charts + the chart id when needed
+// - for each SECTION +1000 (or +X000 for big sections)
+// - for each FAMILY +100
+// - for each CHART +10
+
+#define NETDATA_CHART_PRIO_SYSTEM_CPU 100
+#define NETDATA_CHART_PRIO_SYSTEM_LOAD 100
+#define NETDATA_CHART_PRIO_SYSTEM_IO 150
+#define NETDATA_CHART_PRIO_SYSTEM_PGPGIO 151
+#define NETDATA_CHART_PRIO_SYSTEM_RAM 200
+#define NETDATA_CHART_PRIO_SYSTEM_SWAP 201
+#define NETDATA_CHART_PRIO_SYSTEM_SWAPIO 250
+#define NETDATA_CHART_PRIO_SYSTEM_NET 500
+#define NETDATA_CHART_PRIO_SYSTEM_IPV4 500 // freebsd only
+#define NETDATA_CHART_PRIO_SYSTEM_IP 501
+#define NETDATA_CHART_PRIO_SYSTEM_IPV6 502
+#define NETDATA_CHART_PRIO_SYSTEM_PROCESSES 600
+#define NETDATA_CHART_PRIO_SYSTEM_FORKS 700
+#define NETDATA_CHART_PRIO_SYSTEM_ACTIVE_PROCESSES 750
+#define NETDATA_CHART_PRIO_SYSTEM_CTXT 800
+#define NETDATA_CHART_PRIO_SYSTEM_IDLEJITTER 800
+#define NETDATA_CHART_PRIO_SYSTEM_INTR 900
+#define NETDATA_CHART_PRIO_SYSTEM_SOFTIRQS 950
+#define NETDATA_CHART_PRIO_SYSTEM_SOFTNET_STAT 955
+#define NETDATA_CHART_PRIO_SYSTEM_INTERRUPTS 1000
+#define NETDATA_CHART_PRIO_SYSTEM_DEV_INTR 1000 // freebsd only
+#define NETDATA_CHART_PRIO_SYSTEM_SOFT_INTR 1100 // freebsd only
+#define NETDATA_CHART_PRIO_SYSTEM_ENTROPY 1000
+#define NETDATA_CHART_PRIO_SYSTEM_UPTIME 1000
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_QUEUES 990 // freebsd only
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_MESSAGES 1000 // freebsd only
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_SIZE 1100 // freebsd only
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_SEMAPHORES 1000
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_SEM_ARRAYS 1000
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_SEGS 1000 // freebsd only
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_SIZE 1000 // freebsd only
+#define NETDATA_CHART_PRIO_SYSTEM_PACKETS 7001 // freebsd only
+
+
+// CPU per core
+
+#define NETDATA_CHART_PRIO_CPU_PER_CORE 1000 // +1 per core
+#define NETDATA_CHART_PRIO_CPU_TEMPERATURE 1050 // freebsd only
+#define NETDATA_CHART_PRIO_CPUFREQ_SCALING_CUR_FREQ 5003 // freebsd only
+
+#define NETDATA_CHART_PRIO_CORE_THROTTLING 5001
+#define NETDATA_CHART_PRIO_PACKAGE_THROTTLING 5002
+
+// Interrupts per core
+
+#define NETDATA_CHART_PRIO_INTERRUPTS_PER_CORE 1100 // +1 per core
+
+// Memory Section - 1xxx
+
+#define NETDATA_CHART_PRIO_MEM_SYSTEM_AVAILABLE 1010
+#define NETDATA_CHART_PRIO_MEM_SYSTEM_COMMITTED 1020
+#define NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS 1030
+#define NETDATA_CHART_PRIO_MEM_KERNEL 1100
+#define NETDATA_CHART_PRIO_MEM_SLAB 1200
+#define NETDATA_CHART_PRIO_MEM_HUGEPAGES 1250
+#define NETDATA_CHART_PRIO_MEM_KSM 1300
+#define NETDATA_CHART_PRIO_MEM_KSM_SAVINGS 1301
+#define NETDATA_CHART_PRIO_MEM_KSM_RATIOS 1302
+#define NETDATA_CHART_PRIO_MEM_NUMA 1400
+#define NETDATA_CHART_PRIO_MEM_NUMA_NODES 1410
+#define NETDATA_CHART_PRIO_MEM_HW 1500
+#define NETDATA_CHART_PRIO_MEM_HW_ECC_CE 1550
+#define NETDATA_CHART_PRIO_MEM_HW_ECC_UE 1560
+
+// Disks
+
+#define NETDATA_CHART_PRIO_DISK_IO 2000
+#define NETDATA_CHART_PRIO_DISK_OPS 2001
+#define NETDATA_CHART_PRIO_DISK_QOPS 2002
+#define NETDATA_CHART_PRIO_DISK_BACKLOG 2003
+#define NETDATA_CHART_PRIO_DISK_UTIL 2004
+#define NETDATA_CHART_PRIO_DISK_AWAIT 2005
+#define NETDATA_CHART_PRIO_DISK_AVGSZ 2006
+#define NETDATA_CHART_PRIO_DISK_SVCTM 2007
+#define NETDATA_CHART_PRIO_DISK_MOPS 2021
+#define NETDATA_CHART_PRIO_DISK_IOTIME 2022
+#define NETDATA_CHART_PRIO_BCACHE_CACHE_ALLOC 2120
+#define NETDATA_CHART_PRIO_BCACHE_HIT_RATIO 2120
+#define NETDATA_CHART_PRIO_BCACHE_RATES 2121
+#define NETDATA_CHART_PRIO_BCACHE_SIZE 2122
+#define NETDATA_CHART_PRIO_BCACHE_USAGE 2123
+#define NETDATA_CHART_PRIO_BCACHE_OPS 2124
+#define NETDATA_CHART_PRIO_BCACHE_BYPASS 2125
+#define NETDATA_CHART_PRIO_BCACHE_CACHE_READ_RACES 2126
+
+#define NETDATA_CHART_PRIO_DISKSPACE_SPACE 2023
+#define NETDATA_CHART_PRIO_DISKSPACE_INODES 2024
+
+// NFS (server)
+
+#define NETDATA_CHART_PRIO_NFSD_READCACHE 2100
+#define NETDATA_CHART_PRIO_NFSD_FILEHANDLES 2101
+#define NETDATA_CHART_PRIO_NFSD_IO 2102
+#define NETDATA_CHART_PRIO_NFSD_THREADS 2103
+#define NETDATA_CHART_PRIO_NFSD_THREADS_FULLCNT 2104
+#define NETDATA_CHART_PRIO_NFSD_THREADS_HISTOGRAM 2105
+#define NETDATA_CHART_PRIO_NFSD_READAHEAD 2105
+#define NETDATA_CHART_PRIO_NFSD_NET 2107
+#define NETDATA_CHART_PRIO_NFSD_RPC 2108
+#define NETDATA_CHART_PRIO_NFSD_PROC2 2109
+#define NETDATA_CHART_PRIO_NFSD_PROC3 2110
+#define NETDATA_CHART_PRIO_NFSD_PROC4 2111
+#define NETDATA_CHART_PRIO_NFSD_PROC4OPS 2112
+
+// NFS (client)
+
+#define NETDATA_CHART_PRIO_NFS_NET 2207
+#define NETDATA_CHART_PRIO_NFS_RPC 2208
+#define NETDATA_CHART_PRIO_NFS_PROC2 2209
+#define NETDATA_CHART_PRIO_NFS_PROC3 2210
+#define NETDATA_CHART_PRIO_NFS_PROC4 2211
+
+// BTRFS
+
+#define NETDATA_CHART_PRIO_BTRFS_DISK 2300
+#define NETDATA_CHART_PRIO_BTRFS_DATA 2301
+#define NETDATA_CHART_PRIO_BTRFS_METADATA 2302
+#define NETDATA_CHART_PRIO_BTRFS_SYSTEM 2303
+
+// ZFS
+
+#define NETDATA_CHART_PRIO_ZFS_ARC_SIZE 2500
+#define NETDATA_CHART_PRIO_ZFS_L2_SIZE 2500
+#define NETDATA_CHART_PRIO_ZFS_READS 2510
+#define NETDATA_CHART_PRIO_ZFS_ACTUAL_HITS 2519
+#define NETDATA_CHART_PRIO_ZFS_ARC_SIZE_BREAKDOWN 2520
+#define NETDATA_CHART_PRIO_ZFS_IMPORTANT_OPS 2522
+#define NETDATA_CHART_PRIO_ZFS_MEMORY_OPS 2523
+#define NETDATA_CHART_PRIO_ZFS_IO 2700
+#define NETDATA_CHART_PRIO_ZFS_HITS 2520
+#define NETDATA_CHART_PRIO_ZFS_DHITS 2530
+#define NETDATA_CHART_PRIO_ZFS_DEMAND_DATA_HITS 2531
+#define NETDATA_CHART_PRIO_ZFS_PREFETCH_DATA_HITS 2532
+#define NETDATA_CHART_PRIO_ZFS_PHITS 2540
+#define NETDATA_CHART_PRIO_ZFS_MHITS 2550
+#define NETDATA_CHART_PRIO_ZFS_L2HITS 2560
+#define NETDATA_CHART_PRIO_ZFS_LIST_HITS 2600
+#define NETDATA_CHART_PRIO_ZFS_HASH_ELEMENTS 2800
+#define NETDATA_CHART_PRIO_ZFS_HASH_CHAINS 2810
+
+
+// SOFTIRQs
+
+#define NETDATA_CHART_PRIO_SOFTIRQS_PER_CORE 3000 // +1 per core
+
+// IPFW (freebsd)
+
+#define NETDATA_CHART_PRIO_IPFW_PACKETS 3001
+#define NETDATA_CHART_PRIO_IPFW_BYTES 3002
+#define NETDATA_CHART_PRIO_IPFW_ACTIVE 3003
+#define NETDATA_CHART_PRIO_IPFW_EXPIRED 3004
+#define NETDATA_CHART_PRIO_IPFW_MEM 3005
+
+
+// IPVS
+
+#define NETDATA_CHART_PRIO_IPVS_NET 3100
+#define NETDATA_CHART_PRIO_IPVS_SOCKETS 3101
+#define NETDATA_CHART_PRIO_IPVS_PACKETS 3102
+
+// Softnet
+
+#define NETDATA_CHART_PRIO_SOFTNET_PER_CORE 4101 // +1 per core
+
+// IP STACK
+
+#define NETDATA_CHART_PRIO_IP_ERRORS 4100
+#define NETDATA_CHART_PRIO_IP_TCP_CONNABORTS 4210
+#define NETDATA_CHART_PRIO_IP_TCP_SYN_QUEUE 4215
+#define NETDATA_CHART_PRIO_IP_TCP_ACCEPT_QUEUE 4216
+#define NETDATA_CHART_PRIO_IP_TCP_REORDERS 4220
+#define NETDATA_CHART_PRIO_IP_TCP_OFO 4250
+#define NETDATA_CHART_PRIO_IP_TCP_SYNCOOKIES 4260
+#define NETDATA_CHART_PRIO_IP_TCP_MEM 4290
+#define NETDATA_CHART_PRIO_IP_BCAST 4500
+#define NETDATA_CHART_PRIO_IP_BCAST_PACKETS 4510
+#define NETDATA_CHART_PRIO_IP_MCAST 4600
+#define NETDATA_CHART_PRIO_IP_MCAST_PACKETS 4610
+#define NETDATA_CHART_PRIO_IP_ECN 4700
+
+// IPv4
+
+#define NETDATA_CHART_PRIO_IPV4_SOCKETS 5100
+#define NETDATA_CHART_PRIO_IPV4_PACKETS 5130
+#define NETDATA_CHART_PRIO_IPV4_ERRORS 5150
+#define NETDATA_CHART_PRIO_IPV4_ICMP 5170
+#define NETDATA_CHART_PRIO_IPV4_TCP 5200
+#define NETDATA_CHART_PRIO_IPV4_TCP_SOCKETS 5201
+#define NETDATA_CHART_PRIO_IPV4_TCP_MEM 5290
+#define NETDATA_CHART_PRIO_IPV4_UDP 5300
+#define NETDATA_CHART_PRIO_IPV4_UDP_MEM 5390
+#define NETDATA_CHART_PRIO_IPV4_UDPLITE 5400
+#define NETDATA_CHART_PRIO_IPV4_RAW 5450
+#define NETDATA_CHART_PRIO_IPV4_FRAGMENTS 5460
+#define NETDATA_CHART_PRIO_IPV4_FRAGMENTS_MEM 5470
+
+// IPv6
+
+#define NETDATA_CHART_PRIO_IPV6_PACKETS 6200
+#define NETDATA_CHART_PRIO_IPV6_ECT 6210
+#define NETDATA_CHART_PRIO_IPV6_ERRORS 6300
+#define NETDATA_CHART_PRIO_IPV6_FRAGMENTS 6400
+#define NETDATA_CHART_PRIO_IPV6_FRAGSOUT 6401
+#define NETDATA_CHART_PRIO_IPV6_FRAGSIN 6402
+#define NETDATA_CHART_PRIO_IPV6_TCP 6500
+#define NETDATA_CHART_PRIO_IPV6_UDP 6600
+#define NETDATA_CHART_PRIO_IPV6_UDP_PACKETS 6601
+#define NETDATA_CHART_PRIO_IPV6_UDP_ERRORS 6610
+#define NETDATA_CHART_PRIO_IPV6_UDPLITE 6700
+#define NETDATA_CHART_PRIO_IPV6_UDPLITE_PACKETS 6701
+#define NETDATA_CHART_PRIO_IPV6_UDPLITE_ERRORS 6710
+#define NETDATA_CHART_PRIO_IPV6_RAW 6800
+#define NETDATA_CHART_PRIO_IPV6_BCAST 6840
+#define NETDATA_CHART_PRIO_IPV6_MCAST 6850
+#define NETDATA_CHART_PRIO_IPV6_MCAST_PACKETS 6851
+#define NETDATA_CHART_PRIO_IPV6_ICMP 6900
+#define NETDATA_CHART_PRIO_IPV6_ICMP_REDIR 6910
+#define NETDATA_CHART_PRIO_IPV6_ICMP_ERRORS 6920
+#define NETDATA_CHART_PRIO_IPV6_ICMP_ECHOS 6930
+#define NETDATA_CHART_PRIO_IPV6_ICMP_GROUPMEMB 6940
+#define NETDATA_CHART_PRIO_IPV6_ICMP_ROUTER 6950
+#define NETDATA_CHART_PRIO_IPV6_ICMP_NEIGHBOR 6960
+#define NETDATA_CHART_PRIO_IPV6_ICMP_LDV2 6970
+#define NETDATA_CHART_PRIO_IPV6_ICMP_TYPES 6980
+
+
+// Network interfaces
+
+#define NETDATA_CHART_PRIO_FIRST_NET_IFACE 7000 // 6 charts per interface
+#define NETDATA_CHART_PRIO_FIRST_NET_PACKETS 7001
+#define NETDATA_CHART_PRIO_FIRST_NET_ERRORS 7002
+#define NETDATA_CHART_PRIO_FIRST_NET_DROPS 7003
+#define NETDATA_CHART_PRIO_FIRST_NET_EVENTS 7006
+#define NETDATA_CHART_PRIO_CGROUP_NET_IFACE 43000
+
+// SCTP
+
+#define NETDATA_CHART_PRIO_SCTP 7000
+
+// QoS
+
+#define NETDATA_CHART_PRIO_TC_QOS 7000
+#define NETDATA_CHART_PRIO_TC_QOS_PACKETS 7010
+#define NETDATA_CHART_PRIO_TC_QOS_DROPPED 7020
+#define NETDATA_CHART_PRIO_TC_QOS_TOCKENS 7030
+#define NETDATA_CHART_PRIO_TC_QOS_CTOCKENS 7040
+
+
+// Netfilter
+
+#define NETDATA_CHART_PRIO_NETFILTER_SOCKETS 8700
+#define NETDATA_CHART_PRIO_NETFILTER_NEW 8701
+#define NETDATA_CHART_PRIO_NETFILTER_CHANGES 8702
+#define NETDATA_CHART_PRIO_NETFILTER_EXPECT 8703
+#define NETDATA_CHART_PRIO_NETFILTER_ERRORS 8705
+#define NETDATA_CHART_PRIO_NETFILTER_SEARCH 8710
+
+#define NETDATA_CHART_PRIO_NETFILTER_PACKETS 8906
+#define NETDATA_CHART_PRIO_NETFILTER_BYTES 8907
+
+// SYNPROXY
+
+#define NETDATA_CHART_PRIO_SYNPROXY_SYN_RECEIVED 8751
+#define NETDATA_CHART_PRIO_SYNPROXY_COOKIES 8752
+#define NETDATA_CHART_PRIO_SYNPROXY_CONN_OPEN 8753
+#define NETDATA_CHART_PRIO_SYNPROXY_ENTRIES 8754
+
+// CGROUPS
+
+#define NETDATA_CHART_PRIO_CGROUPS_SYSTEMD 19000 // many charts
+#define NETDATA_CHART_PRIO_CGROUPS_CONTAINERS 40000 // many charts
+
+// STATSD
+
+#define NETDATA_CHART_PRIO_STATSD_PRIVATE 90000 // many charts
+
+// INTERNAL NETDATA INFO
+
+#define NETDATA_CHART_PRIO_CHECKS 99999
+
+#define NETDATA_CHART_PRIO_NETDATA_DISKSPACE 132020
+#define NETDATA_CHART_PRIO_NETDATA_TC_CPU 135000
+#define NETDATA_CHART_PRIO_NETDATA_TC_TIME 135001
+
+
+#endif //NETDATA_ALL_H
diff --git a/collectors/apps.plugin/Makefile.am b/collectors/apps.plugin/Makefile.am
new file mode 100644
index 000000000..be0306492
--- /dev/null
+++ b/collectors/apps.plugin/Makefile.am
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
+
+dist_libconfig_DATA = \
+ apps_groups.conf \
+ $(NULL)
diff --git a/collectors/apps.plugin/Makefile.in b/collectors/apps.plugin/Makefile.in
new file mode 100644
index 000000000..38120c048
--- /dev/null
+++ b/collectors/apps.plugin/Makefile.in
@@ -0,0 +1,521 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors/apps.plugin
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(dist_libconfig_DATA) $(dist_noinst_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libconfigdir)"
+DATA = $(dist_libconfig_DATA) $(dist_noinst_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
+
+dist_libconfig_DATA = \
+ apps_groups.conf \
+ $(NULL)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/apps.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/apps.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-dist_libconfigDATA: $(dist_libconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_libconfig_DATA)'; test -n "$(libconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(libconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(libconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_libconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_libconfig_DATA)'; test -n "$(libconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(libconfigdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(libconfigdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_libconfigDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_libconfigDATA
+
+.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_libconfigDATA 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_libconfigDATA
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/collectors/apps.plugin/README.md b/collectors/apps.plugin/README.md
new file mode 100644
index 000000000..05680efe8
--- /dev/null
+++ b/collectors/apps.plugin/README.md
@@ -0,0 +1,372 @@
+# apps.plugin
+
+`apps.plugin` breaks down system resource usage to **processes**, **users** and **user groups**.
+
+To achieve this task, it iterates through the whole process tree, collecting resource usage information
+for every process found running.
+
+Since netdata needs to present this information in charts and track them through time,
+instead of presenting a `top` like list, `apps.plugin` uses a pre-defined list of **process groups**
+to which it assigns all running processes. This list is [customizable](apps_groups.conf) and netdata
+ships with a good default for most cases (to edit it on your system run `/etc/netdata/edit-config apps_groups.conf`).
+
+So, `apps.plugin` builds a process tree (much like `ps fax` does in Linux), and groups
+processes together (evaluating both child and parent processes) so that the result is always a list with
+a predefined set of members (of course, only process groups found running are reported).
+
+> If you find that `apps.plugin` categorizes standard applications as `other`, we would be
+> glad to accept pull requests improving the [defaults](apps_groups.conf) shipped with netdata.
+
+Unlike traditional process monitoring tools (like `top`), `apps.plugin` is able to account the resource
+utilization of exit processes. Their utilization is accounted at their currently running parents.
+So, `apps.plugin` is perfectly able to measure the resources used by shell scripts and other processes
+that fork/spawn other short lived processes hundreds of times per second.
+
+## Charts
+
+`apps.plugin` provides charts for 3 sections:
+
+1. Per application charts as **Applications** at netdata dashboards
+2. Per user charts as **Users** at netdata dashboards
+3. Per user group charts as **User Groups** at netdata dashboards
+
+Each of these sections provides the same number of charts:
+
+- CPU Utilization
+ - Total CPU usage
+ - User / System CPU usage
+- Disk I/O
+ - Physical Reads / Writes
+ - Logical Reads / Writes
+ - Open Unique Files (if a file is found open multiple times, it is counted just once)
+- Memory
+ - Real Memory Used (non shared)
+ - Virtual Memory Allocated
+ - Minor Page Faults (i.e. memory activity)
+- Processes
+ - Threads Running
+ - Processes Running
+ - Pipes Open
+- Swap Memory
+ - Swap Memory Used
+ - Major Page Faults (i.e. swap activity)
+- Network
+ - Sockets Open
+
+The above are reported:
+
+- For **Applications** per [target configured](apps_groups.conf).
+- For **Users** per username or UID (when the username is not available).
+- For **User Groups** per groupname or GID (when groupname is not available).
+
+## Performance
+
+`apps.plugin` is a complex piece of software and has a lot of work to do
+We are proud that `apps.plugin` is a lot faster compared to any other similar tool,
+while collecting a lot more information for the processes, however the fact is that
+this plugin requires more CPU resources than the netdata daemon itself.
+
+Under Linux, for each process running, `apps.plugin` reads several `/proc` files
+per process. Doing this work per-second, especially on hosts with several thousands
+of processes, may increase the CPU resources consumed by the plugin.
+
+In such cases, you many need to lower its data collection frequency.
+
+To do this, edit `/etc/netdata/netdata.conf` and find this section:
+
+```
+[plugin:apps]
+ # update every = 1
+ # command options =
+```
+
+Uncomment the line `update every` and set it to a higher number. If you just set it to ` 2 `,
+its CPU resources will be cut in half, and data collection will be once every 2 seconds.
+
+## Configuration
+
+The configuration file is `/etc/netdata/apps_groups.conf` (the default is [here](apps_groups.conf)).
+To edit it on your system run `/etc/netdata/edit-config apps_groups.conf`.
+
+The configuration file works accepts multiple lines, each having this format:
+
+```txt
+group: process1 process2 ...
+```
+
+Each group can be given multiple times, to add more processes to it.
+
+For the **Applications** section, only groups configured in this file are reported.
+All other processes will be reported as `other`.
+
+For each process given, its whole process tree will be grouped, not just the process matched.
+The plugin will include both parents and children.
+
+The process names are the ones returned by:
+
+ - `ps -e` or `cat /proc/PID/stat`
+ - in case of substring mode (see below): `/proc/PID/cmdline`
+
+To add process names with spaces, enclose them in quotes (single or double)
+example: ` 'Plex Media Serv' ` or ` "my other process" `.
+
+You can add an asterisk ` * ` at the beginning and/or the end of a process:
+
+ - `*name` *suffix* mode: will search for processes ending with `name` (at `/proc/PID/stat`)
+ - `name*` *prefix* mode: will search for processes beginning with `name` (at `/proc/PID/stat`)
+ - `*name*` *substring* mode: will search for `name` in the whole command line (at `/proc/PID/cmdline`)
+
+If you enter even just one *name* (substring), `apps.plugin` will process
+`/proc/PID/cmdline` for all processes (of course only once per process: when they are first seen).
+
+To add processes with single quotes, enclose them in double quotes: ` "process with this ' single quote" `
+
+To add processes with double quotes, enclose them in single quotes: ` 'process with this " double quote' `
+
+If a group or process name starts with a ` - `, the dimension will be hidden from the chart (cpu chart only).
+
+If a process starts with a ` + `, debugging will be enabled for it (debugging produces a lot of output - do not enable it in production systems).
+
+You can add any number of groups. Only the ones found running will affect the charts generated.
+However, producing charts with hundreds of dimensions may slow down your web browser.
+
+The order of the entries in this list is important: the first that matches a process is used, so put important
+ones at the top. Processes not matched by any row, will inherit it from their parents or children.
+
+The order also controls the order of the dimensions on the generated charts (although applications started
+after apps.plugin is started, will be appended to the existing list of dimensions the netdata daemon maintains).
+
+## Permissions
+
+`apps.plugin` requires additional privileges to collect all the information it needs.
+The problem is described in issue #157.
+
+When netdata is installed, `apps.plugin` is given the capabilities `cap_dac_read_search,cap_sys_ptrace+ep`.
+If this fails (i.e. `setcap` fails), `apps.plugin` is setuid to `root`.
+
+#### linux capabilities in containers
+
+There are a few cases, like `docker` and `virtuozzo` containers, where `setcap` succeeds, but the capabilities
+are silently ignored (in `lxc` containers `setcap` fails).
+
+In these cases ()`setcap` succeeds but capabilities do not work), you will have to setuid
+to root `apps.plugin` by running these commands:
+
+```sh
+chown root:netdata /usr/libexec/netdata/plugins.d/apps.plugin
+chmod 4750 /usr/libexec/netdata/plugins.d/apps.plugin
+```
+
+You will have to run these, every time you update netdata.
+
+## Security
+
+`apps.plugin` performs a hard-coded function of building the process tree in memory,
+iterating forever, collecting metrics for each running process and sending them to netdata.
+This is a one-way communication, from `apps.plugin` to netdata.
+
+So, since `apps.plugin` cannot be instructed by netdata for the actions it performs,
+we think it is pretty safe to allow it have these increased privileges.
+
+Keep in mind that `apps.plugin` will still run without escalated permissions,
+but it will not be able to collect all the information.
+
+## Application Badges
+
+You can create badges that you can embed anywhere you like, with URLs like this:
+
+```
+https://your.netdata.ip:19999/api/v1/badge.svg?chart=apps.processes&dimensions=myapp&value_color=green%3E0%7Cred
+```
+
+The color expression unescaped is this: `value_color=green>0|red`.
+
+Here is an example for the process group `sql` at `https://registry.my-netdata.io`:
+
+![image](https://registry.my-netdata.io/api/v1/badge.svg?chart=apps.processes&dimensions=sql&value_color=green%3E0%7Cred)
+
+Netdata is able give you a lot more badges for your app.
+Examples below for process group `sql`:
+
+- CPU usage: ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.cpu&dimensions=sql&value_color=green=0%7Corange%3C50%7Cred)
+- Disk Physical Reads ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.preads&dimensions=sql&value_color=green%3C100%7Corange%3C1000%7Cred)
+- Disk Physical Writes ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.pwrites&dimensions=sql&value_color=green%3C100%7Corange%3C1000%7Cred)
+- Disk Logical Reads ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.lreads&dimensions=sql&value_color=green%3C100%7Corange%3C1000%7Cred)
+- Disk Logical Writes ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.lwrites&dimensions=sql&value_color=green%3C100%7Corange%3C1000%7Cred)
+- Open Files ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.files&dimensions=sql&value_color=green%3E30%7Cred)
+- Real Memory ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.mem&dimensions=sql&value_color=green%3C100%7Corange%3C200%7Cred)
+- Virtual Memory ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.vmem&dimensions=sql&value_color=green%3C100%7Corange%3C1000%7Cred)
+- Swap Memory ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.swap&dimensions=sql&value_color=green=0%7Cred)
+- Minor Page Faults ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.minor_faults&dimensions=sql&value_color=green%3C100%7Corange%3C1000%7Cred)
+- Processes ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.processes&dimensions=sql&value_color=green%3E0%7Cred)
+- Threads ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.threads&dimensions=sql&value_color=green%3E=28%7Cred)
+- Major Faults (swap activity) ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.major_faults&dimensions=sql&value_color=green=0%7Cred)
+- Open Pipes ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.pipes&dimensions=sql&value_color=green=0%7Cred)
+- Open Sockets ![image](http://registry.my-netdata.io/api/v1/badge.svg?chart=apps.sockets&dimensions=sql&value_color=green%3E=3%7Cred)
+
+
+For more information about badges check [Generating Badges](../../web/api/badges)
+
+## Comparison with console tools
+
+Ssh to a server running netdata and execute this:
+
+```sh
+while true; do ls -l /var/run >/dev/null; done
+```
+
+In most systems `/var/run` is a `tmpfs` device, so there is nothing that can stop this command
+from consuming entirely one of the CPU cores of the machine.
+
+As we will see below, **none** of the console performance monitoring tools can report that this
+command is using 100% CPU. They do report of course that the CPU is busy, but **they fail to
+identify the process that consumes so much CPU**.
+
+Here is what common Linux console monitoring tools report:
+
+#### top
+
+`top` reports that `bash` is using just 14%.
+
+If you check the total system CPU utilization, it says there is no idle CPU at all, but `top`
+fails to provide a breakdown of the CPU consumption in the system. The sum of the CPU utilization
+of all processes reported by `top`, is 15.6%.
+
+```
+top - 18:46:28 up 3 days, 20:14, 2 users, load average: 0.22, 0.05, 0.02
+Tasks: 76 total, 2 running, 74 sleeping, 0 stopped, 0 zombie
+%Cpu(s): 32.8 us, 65.6 sy, 0.0 ni, 0.0 id, 0.0 wa, 1.3 hi, 0.3 si, 0.0 st
+KiB Mem : 1016576 total, 244112 free, 52012 used, 720452 buff/cache
+KiB Swap: 0 total, 0 free, 0 used. 753712 avail Mem
+
+ PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
+12789 root 20 0 14980 4180 3020 S 14.0 0.4 0:02.82 bash
+ 9 root 20 0 0 0 0 S 1.0 0.0 0:22.36 rcuos/0
+ 642 netdata 20 0 132024 20112 2660 S 0.3 2.0 14:26.29 netdata
+12522 netdata 20 0 9508 2476 1828 S 0.3 0.2 0:02.26 apps.plugin
+ 1 root 20 0 67196 10216 7500 S 0.0 1.0 0:04.83 systemd
+ 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
+```
+
+#### htop
+
+Exactly like `top`, `htop` is providing an incomplete breakdown of the system CPU utilization.
+
+```
+ CPU[||||||||||||||||||||||||100.0%] Tasks: 27, 11 thr; 2 running
+ Mem[||||||||||||||||||||85.4M/993M] Load average: 1.16 0.88 0.90
+ Swp[ 0K/0K] Uptime: 3 days, 21:37:03
+
+ PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
+12789 root 20 0 15104 4484 3208 S 14.0 0.4 10:57.15 -bash
+ 7024 netdata 20 0 9544 2480 1744 S 0.7 0.2 0:00.88 /usr/libexec/netd
+ 7009 netdata 20 0 138M 21016 2712 S 0.7 2.1 0:00.89 /usr/sbin/netdata
+ 7012 netdata 20 0 138M 21016 2712 S 0.0 2.1 0:00.31 /usr/sbin/netdata
+ 563 root 20 0 308M 202M 202M S 0.0 20.4 1:00.81 /usr/lib/systemd/
+ 7019 netdata 20 0 138M 21016 2712 S 0.0 2.1 0:00.14 /usr/sbin/netdata
+```
+
+#### atop
+
+`atop` also fails to break down CPU usage.
+
+```
+ATOP - localhost 2016/12/10 20:11:27 ----------- 10s elapsed
+PRC | sys 1.13s | user 0.43s | #proc 75 | #zombie 0 | #exit 5383 |
+CPU | sys 67% | user 31% | irq 2% | idle 0% | wait 0% |
+CPL | avg1 1.34 | avg5 1.05 | avg15 0.96 | csw 51346 | intr 10508 |
+MEM | tot 992.8M | free 211.5M | cache 470.0M | buff 87.2M | slab 164.7M |
+SWP | tot 0.0M | free 0.0M | | vmcom 207.6M | vmlim 496.4M |
+DSK | vda | busy 0% | read 0 | write 4 | avio 1.50 ms |
+NET | transport | tcpi 16 | tcpo 15 | udpi 0 | udpo 0 |
+NET | network | ipi 16 | ipo 15 | ipfrw 0 | deliv 16 |
+NET | eth0 ---- | pcki 16 | pcko 15 | si 1 Kbps | so 4 Kbps |
+
+ PID SYSCPU USRCPU VGROW RGROW RDDSK WRDSK ST EXC S CPU CMD 1/600
+12789 0.98s 0.40s 0K 0K 0K 336K -- - S 14% bash
+ 9 0.08s 0.00s 0K 0K 0K 0K -- - S 1% rcuos/0
+ 7024 0.03s 0.00s 0K 0K 0K 0K -- - S 0% apps.plugin
+ 7009 0.01s 0.01s 0K 0K 0K 4K -- - S 0% netdata
+```
+
+#### glances
+
+And the same is true for `glances`. The system runs at 100%, but `glances` reports only 17%
+per process utilization.
+
+Note also, that being a `python` program, `glances` uses 1.6% CPU while it runs.
+
+
+```
+localhost Uptime: 3 days, 21:42:00
+
+CPU [100.0%] CPU 100.0% MEM 23.7% SWAP 0.0% LOAD 1-core
+MEM [ 23.7%] user: 30.9% total: 993M total: 0 1 min: 1.18
+SWAP [ 0.0%] system: 67.8% used: 236M used: 0 5 min: 1.08
+ idle: 0.0% free: 757M free: 0 15 min: 1.00
+
+NETWORK Rx/s Tx/s TASKS 75 (90 thr), 1 run, 74 slp, 0 oth
+eth0 168b 2Kb
+eth1 0b 0b CPU% MEM% PID USER NI S Command
+lo 0b 0b 13.5 0.4 12789 root 0 S -bash
+ 1.6 2.2 7025 root 0 R /usr/bin/python /u
+DISK I/O R/s W/s 1.0 0.0 9 root 0 S rcuos/0
+vda1 0 4K 0.3 0.2 7024 netdata 0 S /usr/libexec/netda
+ 0.3 0.0 7 root 0 S rcu_sched
+FILE SYS Used Total 0.3 2.1 7009 netdata 0 S /usr/sbin/netdata
+/ (vda1) 1.56G 29.5G 0.0 0.0 17 root 0 S oom_reaper
+```
+
+#### why this happens?
+
+All the console tools report usage based on the processes found running *at the moment they
+examine the process tree*. So, they see just one `ls` command, which is actually very quick
+with minor CPU utilization. But the shell, is spawning hundreds of them, one after another
+(much like shell scripts do).
+
+#### what netdata reports?
+
+The total CPU utilization of the system:
+
+![image](https://cloud.githubusercontent.com/assets/2662304/21076212/9198e5a6-bf2e-11e6-9bc0-6bdea25befb2.png)
+<br/>_**Figure 1**: The system overview section at netdata, just a few seconds after the command was run_
+
+And at the applications `apps.plugin` breaks down CPU usage per application:
+
+![image](https://cloud.githubusercontent.com/assets/2662304/21076220/c9687848-bf2e-11e6-8d81-348592c5aca2.png)
+<br/>_**Figure 2**: The Applications section at netdata, just a few seconds after the command was run_
+
+So, the `ssh` session is using 95% CPU time.
+
+Why `ssh`?
+
+`apps.plugin` groups all processes based on its configuration file
+[`/etc/netdata/apps_groups.conf`](apps_groups.conf)
+(to edit it on your system run `/etc/netdata/edit-config apps_groups.conf`).
+The default configuration has nothing for `bash`, but it has for `sshd`, so netdata accumulates
+all ssh sessions to a dimension on the charts, called `ssh`. This includes all the processes in
+the process tree of `sshd`, **including the exited children**.
+
+> Distributions based on `systemd`, provide another way to get cpu utilization per user session
+> or service running: control groups, or cgroups, commonly used as part of containers
+> `apps.plugin` does not use these mechanisms. The process grouping made by `apps.plugin` works
+> on any Linux, `systemd` based or not.
+
+#### a more technical description of how netdata works
+
+netdata reads `/proc/<pid>/stat` for all processes, once per second and extracts `utime` and
+`stime` (user and system cpu utilization), much like all the console tools do.
+
+But it [also extracts `cutime` and `cstime`](https://github.com/netdata/netdata/blob/62596cc6b906b1564657510ca9135c08f6d4cdda/src/apps_plugin.c#L636-L642)
+that account the user and system time of the exit children of each process. By keeping a map in
+memory of the whole process tree, it is capable of assigning the right time to every process,
+taking into account all its exited children.
+
+It is tricky, since a process may be running for 1 hour and once it exits, its parent should not
+receive the whole 1 hour of cpu time in just 1 second - you have to subtract the cpu time that has
+been reported for it prior to this iteration.
+
+It is even trickier, because walking through the entire process tree takes some time itself. So,
+if you sum the CPU utilization of all processes, you might have more CPU time than the reported
+total cpu time of the system. netdata solves this, by adapting the per process cpu utilization to
+the total of the system. [Netdata adds charts that document this normalization](https://london.my-netdata.io/default.html#menu_netdata_submenu_apps_plugin).
diff --git a/conf.d/apps_groups.conf b/collectors/apps.plugin/apps_groups.conf
index 4356e4910..c0d22fac9 100644
--- a/conf.d/apps_groups.conf
+++ b/collectors/apps.plugin/apps_groups.conf
@@ -107,15 +107,16 @@ timedb: prometheus *carbon-cache.py* *carbon-aggregator.py* *graphite/manage.py*
# -----------------------------------------------------------------------------
# email servers
-email: dovecot imapd pop3d amavis* master zmstat* zmmailboxdmgr qmgr oqmgr saslauthd opendkim clamd freshclam unbound tlsmgr postfwd2 postscreen postfix smtp* lmtp*
+email: dovecot imapd pop3d amavis* master zmstat* zmmailboxdmgr qmgr oqmgr saslauthd opendkim clamd freshclam unbound tlsmgr postfwd2 postscreen postfix smtp* lmtp* sendmail
# -----------------------------------------------------------------------------
# network, routing, VPN
ppp: ppp*
vpn: openvpn pptp* cjdroute gvpe tincd
-wifi: hostapd wpa_supplicant
+wifi: hostapd wpa_supplicant NetworkManager
routing: ospfd* ospf6d* bgpd isisd ripd ripngd pimd ldpd zebra vtysh bird*
+modem: ModemManager
# -----------------------------------------------------------------------------
# high availability and balancers
@@ -162,7 +163,7 @@ VMs: vbox* VBox* qemu*
# -----------------------------------------------------------------------------
# ssh servers and clients
-ssh: ssh* scp
+ssh: ssh* scp dropbear
# -----------------------------------------------------------------------------
# print servers and clients
@@ -172,7 +173,7 @@ print: cups* lpd lpq
# -----------------------------------------------------------------------------
# time servers and clients
-time: ntp* systemd-timesyncd
+time: ntp* systemd-timesyncd chronyd
# -----------------------------------------------------------------------------
# dhcp servers and clients
@@ -257,13 +258,14 @@ airflow: *airflow*
X: X Xorg xinit lightdm xdm pulseaudio gkrellm xfwm4 xfdesktop xfce* Thunar
X: xfsettingsd xfconfd gnome-* gdm gconf* dconf* xfconf* *gvfs gvfs* kdm slim
X: evolution-* firefox chromium opera vivaldi-bin epiphany WebKit*
+X: '*systemd --user*' chrome *chrome-sandbox* *google-chrome* *chromium* *firefox*
# -----------------------------------------------------------------------------
# Kernel / System
ksmd: ksmd
-system: systemd* udisks* udevd* *udevd connmand ipv6_addrconf dbus-* rtkit*
+system: systemd-* udisks* udevd* *udevd connmand ipv6_addrconf dbus-* rtkit*
system: inetd xinetd mdadm polkitd acpid uuidd packagekitd upowerd colord
system: accounts-daemon rngd haveged
@@ -280,3 +282,5 @@ rabbitmq: *rabbitmq*
sidekiq: *sidekiq*
java: java
ipfs: ipfs
+
+node: node
diff --git a/src/apps_plugin.c b/collectors/apps.plugin/apps_plugin.c
index 8595da6c2..f592e9fc8 100644
--- a/src/apps_plugin.c
+++ b/collectors/apps.plugin/apps_plugin.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
/*
* netdata apps.plugin
@@ -5,7 +6,61 @@
* Released under GPL v3+
*/
-#include "common.h"
+#include "../../libnetdata/libnetdata.h"
+
+// ----------------------------------------------------------------------------
+
+// callback required by fatal()
+void netdata_cleanup_and_exit(int ret) {
+ exit(ret);
+}
+
+// callbacks required by popen()
+void signals_block(void) {};
+void signals_unblock(void) {};
+void signals_reset(void) {};
+
+// callback required by eval()
+int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, calculated_number *result) {
+ (void)variable;
+ (void)hash;
+ (void)rc;
+ (void)result;
+ return 0;
+};
+
+// required by get_system_cpus()
+char *netdata_configured_host_prefix = "";
+
+
+// ----------------------------------------------------------------------------
+// debugging
+
+static int debug_enabled = 0;
+static inline void debug_log_int(const char *fmt, ... ) {
+ va_list args;
+
+ fprintf( stderr, "apps.plugin: ");
+ va_start( args, fmt );
+ vfprintf( stderr, fmt, args );
+ va_end( args );
+
+ fputc('\n', stderr);
+}
+
+#ifdef NETDATA_INTERNAL_CHECKS
+
+#define debug_log(fmt, args...) do { if(unlikely(debug_enabled)) debug_log_int(fmt, ##args); } while(0)
+
+#else
+
+static inline void debug_log_dummy(void) {}
+#define debug_log(fmt, args...) debug_log_dummy()
+
+#endif
+
+
+// ----------------------------------------------------------------------------
#ifdef __FreeBSD__
#include <sys/user.h>
@@ -57,21 +112,21 @@
// 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,
+ max_fds_cache_seconds = 60,
#endif
enable_users_charts = 1,
enable_groups_charts = 1,
include_exited_childs = 1;
-
-// will be changed to getenv(NETDATA_CONFIG_DIR) if it exists
-static char *config_dir = CONFIG_DIR;
+// will be changed to getenv(NETDATA_USER_CONFIG_DIR) if it exists
+static char *user_config_dir = CONFIG_DIR;
+static char *stock_config_dir = LIBCONFIG_DIR;
// ----------------------------------------------------------------------------
// internal flags
@@ -90,6 +145,9 @@ static size_t
global_iterations_counter = 1,
calls_counter = 0,
file_counter = 0,
+ filenames_allocated_counter = 0,
+ inodes_changed_counter = 0,
+ links_changed_counter = 0,
targets_assignment_counter = 0;
@@ -193,7 +251,7 @@ struct target {
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 debug_enabled;
int ends_with;
int starts_with; // if set, the compare string matches only the
// beginning of the command
@@ -218,6 +276,18 @@ size_t
// structure to store data for each process running
// see: man proc for the description of the fields
+struct pid_fd {
+ int fd;
+
+#ifndef __FreeBSD__
+ ino_t inode;
+ char *filename;
+ uint32_t link_hash;
+ size_t cache_iterations_counter;
+ size_t cache_iterations_reset;
+#endif
+};
+
struct pid_stat {
int32_t pid;
char comm[MAX_COMPARE_NAME + 1];
@@ -312,15 +382,15 @@ struct pid_stat {
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
+ struct pid_fd *fds; // array of fds it uses
+ size_t 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
+ unsigned 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
+ unsigned char updated:1; // 1 when the process is currently running
+ unsigned char merged:1; // 1 when it has been merged to its parent
+ unsigned 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
@@ -416,13 +486,6 @@ static int
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
@@ -452,8 +515,7 @@ static struct target *get_users_target(uid_t uid) {
w->next = users_root_target;
users_root_target = w;
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: added uid %u ('%s') target\n", w->uid, w->name);
+ debug_log("added uid %u ('%s') target", w->uid, w->name);
return w;
}
@@ -485,8 +547,7 @@ struct target *get_groups_target(gid_t gid)
w->next = groups_root_target;
groups_root_target = w;
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: added gid %u ('%s') target\n", w->gid, w->name);
+ debug_log("added gid %u ('%s') target", w->gid, w->name);
return w;
}
@@ -527,11 +588,11 @@ static struct target *get_apps_groups_target(const char *id, struct target *targ
break;
}
- if(unlikely(debug)) {
+ if(unlikely(debug_enabled)) {
if(unlikely(target))
- fprintf(stderr, "apps.plugin: REUSING TARGET NAME '%s' on ID '%s'\n", target->name, target->id);
+ debug_log("REUSING TARGET NAME '%s' on ID '%s'", target->name, target->id);
else
- fprintf(stderr, "apps.plugin: NEW TARGET NAME '%s' on ID '%s'\n", name, id);
+ debug_log("NEW TARGET NAME '%s' on ID '%s'", name, id);
}
}
@@ -564,34 +625,37 @@ static struct target *get_apps_groups_target(const char *id, struct target *targ
w->comparelen = strlen(w->compare);
w->hidden = thidden;
- w->debug = tdebug;
+#ifdef NETDATA_INTERNAL_CHECKS
+ w->debug_enabled = tdebug;
+#else
+ if(tdebug)
+ fprintf(stderr, "apps.plugin has been compiled without debugging\n");
+#endif
w->target = target;
// append it, to maintain the order in apps_groups.conf
if(last) last->next = w;
else apps_groups_root_target = w;
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: ADDING TARGET ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
- , w->id
- , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
- , w->target?w->target->name:w->name
- , (w->hidden)?"hidden":"-"
- , (w->debug)?"debug":"-"
- );
+ debug_log("ADDING TARGET ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s"
+ , w->id
+ , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
+ , w->target?w->target->name:w->name
+ , (w->hidden)?"hidden":"-"
+ , (w->debug_enabled)?"debug":"-"
+ );
return w;
}
// read the apps_groups.conf file
-static int read_apps_groups_conf(const char *file)
+static int read_apps_groups_conf(const char *path, const char *file)
{
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, file);
+ snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", path, file);
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
+ debug_log("process groups file: '%s'", filename);
// ----------------------------------------
@@ -654,14 +718,16 @@ static int read_apps_groups_conf(const char *file)
// ----------------------------------------------------------------------------
// struct pid_stat management
+static inline void init_pid_fds(struct pid_stat *p, size_t first, size_t size);
static inline struct pid_stat *get_pid_entry(pid_t pid) {
if(unlikely(all_pids[pid]))
return all_pids[pid];
struct pid_stat *p = callocz(sizeof(struct pid_stat), 1);
- p->fds = callocz(sizeof(int), MAX_SPARE_FDS);
+ p->fds = mallocz(sizeof(struct pid_fd) * MAX_SPARE_FDS);
p->fds_size = MAX_SPARE_FDS;
+ init_pid_fds(p, 0, p->fds_size);
if(likely(root_of_pids))
root_of_pids->prev = p;
@@ -685,8 +751,7 @@ static inline void del_pid_entry(pid_t pid) {
return;
}
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, p->comm);
+ debug_log("process %d %s exited, deleting it.", pid, p->comm);
if(root_of_pids == p)
root_of_pids = p->next;
@@ -694,7 +759,17 @@ static inline void del_pid_entry(pid_t pid) {
if(p->next) p->next->prev = p->prev;
if(p->prev) p->prev->next = p->next;
+ // free the filename
+#ifndef __FreeBSD__
+ {
+ size_t i;
+ for(i = 0; i < p->fds_size; i++)
+ if(p->fds[i].filename)
+ freez(p->fds[i].filename);
+ }
+#endif
freez(p->fds);
+
freez(p->fds_dirname);
freez(p->stat_filename);
freez(p->status_filename);
@@ -716,8 +791,8 @@ 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))) {
+ if(unlikely(debug_enabled || errno != ENOENT)) {
+ if(unlikely(debug_enabled || !(p->log_thrown & log))) {
p->log_thrown |= log;
switch(log) {
case PID_LOG_IO:
@@ -779,7 +854,7 @@ static inline void assign_target_to_pid(struct pid_stat *p) {
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(debug_enabled || (p->target && p->target->debug_enabled)) debug_log_int("\t\tcomparing '%s' with '%s'", w->compare, p->comm);
// find it - 4 cases:
// 1. the target is not a pattern
@@ -796,8 +871,8 @@ static inline void assign_target_to_pid(struct pid_stat *p) {
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);
+ if(debug_enabled || (p->target && p->target->debug_enabled))
+ debug_log_int("%s linked to target %s", p->comm, p->target->name);
break;
}
@@ -828,7 +903,7 @@ static inline int read_proc_pid_cmdline(struct pid_stat *p) {
p->cmdline_filename = strdupz(filename);
}
- int fd = open(p->cmdline_filename, O_RDONLY, 0666);
+ int fd = open(p->cmdline_filename, procfile_open_flags, 0666);
if(unlikely(fd == -1)) goto cleanup;
ssize_t i, bytes = read(fd, cmdline, MAX_CMDLINE);
@@ -838,18 +913,20 @@ static inline int read_proc_pid_cmdline(struct pid_stat *p) {
#endif
cmdline[bytes] = '\0';
- for(i = 0; i < bytes ; i++)
+ for(i = 0; i < bytes ; i++) {
if(unlikely(!cmdline[i])) cmdline[i] = ' ';
+ }
+ if(p->cmdline) freez(p->cmdline);
p->cmdline = strdupz(cmdline);
- if(unlikely(debug))
- fprintf(stderr, "Read file '%s' contents: %s\n", p->cmdline_filename, p->cmdline);
+ debug_log("Read file '%s' contents: %s", p->cmdline_filename, p->cmdline);
return 1;
cleanup:
// copy the command to the command line
+ if(p->cmdline) freez(p->cmdline);
p->cmdline = strdupz(p->comm);
return 0;
}
@@ -963,7 +1040,7 @@ static inline int read_proc_pid_status(struct pid_stat *p, void *ptr) {
p->gid = proc_info->ki_groups[0];
p->status_vmsize = proc_info->ki_size / 1024; // in kB
p->status_vmrss = proc_info->ki_rssize * pagesize / 1024; // in kB
- // FIXME: what about shared and swap memory on FreeBSD?
+ // TODO: what about shared and swap memory on FreeBSD?
return 1;
#else
(void)ptr;
@@ -1004,7 +1081,7 @@ static inline int read_proc_pid_status(struct pid_stat *p, void *ptr) {
arl_begin(p->status_arl);
for(l = 0; l < lines ;l++) {
- // fprintf(stderr, "CHECK: line %zu of %zu, key '%s' = '%s'\n", l, lines, procfile_lineword(ff, l, 0), procfile_lineword(ff, l, 1));
+ // debug_log("CHECK: line %zu of %zu, key '%s' = '%s'", l, lines, procfile_lineword(ff, l, 0), procfile_lineword(ff, l, 1));
arl_ptr.line = l;
if(unlikely(arl_check(p->status_arl,
procfile_lineword(ff, l, 0),
@@ -1013,7 +1090,7 @@ static inline int read_proc_pid_status(struct pid_stat *p, void *ptr) {
p->status_vmshared = p->status_rssfile + p->status_rssshmem;
- // fprintf(stderr, "%s uid %d, gid %d, VmSize %zu, VmRSS %zu, RssFile %zu, RssShmem %zu, shared %zu\n", p->comm, (int)p->uid, (int)p->gid, p->status_vmsize, p->status_vmrss, p->status_rssfile, p->status_rssshmem, p->status_vmshared);
+ // debug_log("%s uid %d, gid %d, VmSize %zu, VmRSS %zu, RssFile %zu, RssShmem %zu, shared %zu", p->comm, (int)p->uid, (int)p->gid, p->status_vmsize, p->status_vmrss, p->status_rssfile, p->status_rssshmem, p->status_vmshared);
return 1;
#endif
@@ -1072,11 +1149,11 @@ static inline int read_proc_pid_stat(struct pid_stat *p, void *ptr) {
#endif
if(strcmp(p->comm, comm) != 0) {
- if(unlikely(debug)) {
+ if(unlikely(debug_enabled)) {
if(p->comm[0])
- fprintf(stderr, "apps.plugin: \tpid %d (%s) changed name to '%s'\n", p->pid, p->comm, comm);
+ debug_log("\tpid %d (%s) changed name to '%s'", p->pid, p->comm, comm);
else
- fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", p->pid, comm);
+ debug_log("\tJust added %d (%s)", p->pid, comm);
}
strncpyz(p->comm, comm, MAX_COMPARE_NAME);
@@ -1152,8 +1229,8 @@ static inline int read_proc_pid_stat(struct pid_stat *p, void *ptr) {
}
#endif
- if(unlikely(debug || (p->target && p->target->debug)))
- fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT ", threads=%d\n", netdata_configured_host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
+ if(unlikely(debug_enabled || (p->target && p->target->debug_enabled)))
+ debug_log_int("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", 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;
@@ -1332,7 +1409,7 @@ int file_descriptor_compare(void* a, void* b) {
return strcmp(((struct file_descriptor *)a)->name, ((struct file_descriptor *)b)->name);
}
-int file_descriptor_iterator(avl *a) { if(a) {}; return 0; }
+// int file_descriptor_iterator(avl *a) { if(a) {}; return 0; }
avl_tree all_files_index = {
NULL,
@@ -1368,15 +1445,13 @@ static inline void file_descriptor_not_used(int id)
}
#endif /* NETDATA_INTERNAL_CHECKS */
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: decreasing slot %d (count = %d).\n", id, all_files[id].count);
+ debug_log("decreasing slot %d (count = %d).", id, all_files[id].count);
if(all_files[id].count > 0) {
all_files[id].count--;
if(!all_files[id].count) {
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: >> slot %d is empty.\n", id);
+ debug_log(" >> slot %d is empty.", id);
if(unlikely(file_descriptor_remove(&all_files[id]) != (void *)&all_files[id]))
error("INTERNAL ERROR: removal of unused fd from index, removed a different fd");
@@ -1398,8 +1473,7 @@ static inline void all_files_grow() {
int i;
// there is no empty slot
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
+ debug_log("extending fd array to %d entries", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
all_files = reallocz(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor));
@@ -1407,8 +1481,7 @@ static inline void all_files_grow() {
// since all pointers are now invalid
if(unlikely(old && old != (void *)all_files)) {
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: >> re-indexing.\n");
+ debug_log(" >> re-indexing.");
all_files_index.root = NULL;
for(i = 0; i < all_files_size; i++) {
@@ -1417,8 +1490,7 @@ static inline void all_files_grow() {
error("INTERNAL ERROR: duplicate indexing of fd during realloc.");
}
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: >> re-indexing done.\n");
+ debug_log(" >> re-indexing done.");
}
// initialize the newly added entries
@@ -1441,8 +1513,7 @@ static inline int file_descriptor_set_on_empty_slot(const char *name, uint32_t h
if(!all_files || all_files_len == all_files_size)
all_files_grow();
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: >> searching for empty slot.\n");
+ debug_log(" >> searching for empty slot.");
// search for an empty slot
@@ -1453,16 +1524,14 @@ static inline int file_descriptor_set_on_empty_slot(const char *name, uint32_t h
if(c == 0) continue;
if(!all_files[c].count) {
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: >> Examining slot %d.\n", c);
+ debug_log(" >> Examining slot %d.", c);
#ifdef NETDATA_INTERNAL_CHECKS
if(all_files[c].magic == 0x0BADCAFE && all_files[c].name && file_descriptor_find(all_files[c].name, all_files[c].hash))
- error("fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name);
+ error("fd on position %d is not cleared properly. It still has %s in it.", c, all_files[c].name);
#endif /* NETDATA_INTERNAL_CHECKS */
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: >> %s fd position %d for %s (last name: %s)\n", all_files[c].name?"re-using":"using", c, name, all_files[c].name);
+ debug_log(" >> %s fd position %d for %s (last name: %s)", all_files[c].name?"re-using":"using", c, name, all_files[c].name);
freez((void *)all_files[c].name);
all_files[c].name = NULL;
@@ -1479,8 +1548,7 @@ static inline int file_descriptor_set_on_empty_slot(const char *name, uint32_t h
}
// else we have an empty slot in 'c'
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: >> updating slot %d.\n", c);
+ debug_log(" >> updating slot %d.", c);
all_files[c].name = strdupz(name);
all_files[c].hash = hash;
@@ -1493,24 +1561,21 @@ static inline int file_descriptor_set_on_empty_slot(const char *name, uint32_t h
if(unlikely(file_descriptor_add(&all_files[c]) != (void *)&all_files[c]))
error("INTERNAL ERROR: duplicate indexing of fd.");
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
+ debug_log("using fd position %d (name: %s)", c, all_files[c].name);
return c;
}
-static inline int file_descriptor_find_or_add(const char *name)
-{
- uint32_t hash = simple_hash(name);
+static inline int file_descriptor_find_or_add(const char *name, uint32_t hash) {
+ if(unlikely(!hash))
+ hash = simple_hash(name);
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %u\n", name, hash);
+ debug_log("adding or finding name '%s' with hash %u", name, hash);
struct file_descriptor *fd = file_descriptor_find(name, hash);
if(fd) {
// found
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: >> found on slot %d\n", fd->pos);
+ debug_log(" >> found on slot %d", fd->pos);
fd->count++;
return fd->pos;
@@ -1530,47 +1595,65 @@ static inline int file_descriptor_find_or_add(const char *name)
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);
-
+ debug_log("UNKNOWN anonymous inode: %s", name);
type = FILETYPE_OTHER;
}
}
else if(likely(strcmp(name, "inotify") == 0)) type = FILETYPE_INOTIFY;
else {
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: FIXME: cannot understand linkname: %s\n", name);
-
+ debug_log("UNKNOWN linkname: %s", name);
type = FILETYPE_OTHER;
}
return file_descriptor_set_on_empty_slot(name, hash, type);
}
+static inline void clear_pid_fd(struct pid_fd *pfd) {
+ pfd->fd = 0;
+
+ #ifndef __FreeBSD__
+ pfd->link_hash = 0;
+ pfd->inode = 0;
+ pfd->cache_iterations_counter = 0;
+ pfd->cache_iterations_reset = 0;
+#endif
+}
+
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++;
+ struct pid_fd *pfd = p->fds, *pfdend = &p->fds[p->fds_size];
+ while(pfd < pfdend) {
+ pfd->fd = -(pfd->fd);
+ pfd++;
}
}
static inline void cleanup_negative_pid_fds(struct pid_stat *p) {
- int *fd = p->fds, *fdend = &p->fds[p->fds_size];
+ struct pid_fd *pfd = p->fds, *pfdend = &p->fds[p->fds_size];
+
+ while(pfd < pfdend) {
+ int fd = pfd->fd;
- while(fd < fdend) {
- if(unlikely(*fd < 0)) {
- file_descriptor_not_used(-(*fd));
- *fd++ = 0;
+ if(unlikely(fd < 0)) {
+ file_descriptor_not_used(-(fd));
+ clear_pid_fd(pfd);
}
- else
- fd++;
+
+ pfd++;
}
}
-static inline void zero_pid_fds(struct pid_stat *p, int first, int size) {
- int *fd = &p->fds[first], *end = &p->fds[first + size];
- while(fd < end) *fd++ = 0;
+static inline void init_pid_fds(struct pid_stat *p, size_t first, size_t size) {
+ struct pid_fd *pfd = &p->fds[first], *pfdend = &p->fds[first + size];
+ size_t i = first;
+
+ while(pfd < pfdend) {
+#ifndef __FreeBSD__
+ pfd->filename = NULL;
+#endif
+ clear_pid_fd(pfd);
+ pfd++;
+ i++;
+ }
}
static inline int read_pid_file_descriptors(struct pid_stat *p, void *ptr) {
@@ -1625,17 +1708,16 @@ static inline int read_pid_file_descriptors(struct pid_stat *p, void *ptr) {
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);
+ debug_log("extending fd memory slots for %s from %d to %d", p->comm, p->fds_size, fdid + MAX_SPARE_FDS);
- p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
+ p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(struct pid_fd));
// and initialize it
- zero_pid_fds(p, p->fds_size, (fdid + MAX_SPARE_FDS) - p->fds_size);
+ init_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)) {
+ if (unlikely(p->fds[fdid].fd == 0)) {
// we don't know this fd, get it
switch (fds->kf_type) {
@@ -1691,15 +1773,14 @@ static inline int read_pid_file_descriptors(struct pid_stat *p, void *ptr) {
// if another process already has this, we will get
// the same id
- p->fds[fdid] = file_descriptor_find_or_add(fdsname);
+ p->fds[fdid].fd = file_descriptor_find_or_add(fdsname, 0);
}
// 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
+ // of course, the actual file may have changed
else
- p->fds[fdid] = -p->fds[fdid];
+ p->fds[fdid].fd = -p->fds[fdid].fd;
bfdsbuf += fds->kf_structsize;
}
@@ -1714,7 +1795,6 @@ static inline int read_pid_file_descriptors(struct pid_stat *p, void *ptr) {
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
@@ -1733,53 +1813,103 @@ static inline int read_pid_file_descriptors(struct pid_stat *p, void *ptr) {
if(unlikely(fdid < 0)) continue;
// check if the fds array is small
- if(unlikely(fdid >= p->fds_size)) {
+ if(unlikely((size_t)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
- );
+ debug_log("extending fd memory slots for %s from %d to %d"
+ , p->comm
+ , p->fds_size
+ , fdid + MAX_SPARE_FDS
+ );
- p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
+ p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(struct pid_fd));
// and initialize it
- zero_pid_fds(p, p->fds_size, (fdid + MAX_SPARE_FDS) - p->fds_size);
- p->fds_size = fdid + MAX_SPARE_FDS;
+ init_pid_fds(p, p->fds_size, (fdid + MAX_SPARE_FDS) - p->fds_size);
+ p->fds_size = (size_t)fdid + MAX_SPARE_FDS;
}
- if(unlikely(p->fds[fdid] == 0)) {
- // we don't know this fd, get it
+ if(unlikely(p->fds[fdid].fd < 0 && de->d_ino != p->fds[fdid].inode)) {
+ // inodes do not match, clear the previous entry
+ inodes_changed_counter++;
+ file_descriptor_not_used(-p->fds[fdid].fd);
+ clear_pid_fd(&p->fds[fdid]);
+ }
- 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;
+ if(p->fds[fdid].fd < 0 && p->fds[fdid].cache_iterations_counter > 0) {
+ p->fds[fdid].fd = -p->fds[fdid].fd;
+ p->fds[fdid].cache_iterations_counter--;
+ continue;
+ }
+
+ if(unlikely(!p->fds[fdid].filename)) {
+ filenames_allocated_counter++;
+ char fdname[FILENAME_MAX + 1];
+ snprintfz(fdname, FILENAME_MAX, "%s/proc/%d/fd/%s", netdata_configured_host_prefix, p->pid, de->d_name);
+ p->fds[fdid].filename = strdupz(fdname);
+ }
+
+ file_counter++;
+ ssize_t l = readlink(p->fds[fdid].filename, linkname, FILENAME_MAX);
+ if(unlikely(l == -1)) {
+ // cannot read the link
+
+ if(debug_enabled || (p->target && p->target->debug_enabled))
+ error("Cannot read link %s", p->fds[fdid].filename);
+
+ if(unlikely(p->fds[fdid].fd < 0)) {
+ file_descriptor_not_used(-p->fds[fdid].fd);
+ clear_pid_fd(&p->fds[fdid]);
}
- else
- linkname[l] = '\0';
- file_counter++;
+ continue;
+ }
+ else
+ linkname[l] = '\0';
+
+ uint32_t link_hash = simple_hash(linkname);
+
+ if(unlikely(p->fds[fdid].fd < 0 && p->fds[fdid].link_hash != link_hash)) {
+ // the link changed
+ links_changed_counter++;
+ file_descriptor_not_used(-p->fds[fdid].fd);
+ clear_pid_fd(&p->fds[fdid]);
+ }
+
+ if(unlikely(p->fds[fdid].fd == 0)) {
+ // we don't know this fd, get it
// if another process already has this, we will get
// the same id
- p->fds[fdid] = file_descriptor_find_or_add(linkname);
+ p->fds[fdid].fd = file_descriptor_find_or_add(linkname, link_hash);
+ p->fds[fdid].inode = de->d_ino;
+ p->fds[fdid].link_hash = link_hash;
}
-
+ else {
// 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
+ p->fds[fdid].fd = -p->fds[fdid].fd;
+ }
- else
- p->fds[fdid] = -p->fds[fdid];
+ // caching control
+ // without this we read all the files on every iteration
+ if(max_fds_cache_seconds > 0) {
+ size_t spread = ((size_t)max_fds_cache_seconds > 10) ? 10 : (size_t)max_fds_cache_seconds;
+
+ // cache it for a few iterations
+ size_t max = ((size_t) max_fds_cache_seconds + (fdid % spread)) / (size_t) update_every;
+ p->fds[fdid].cache_iterations_reset++;
+
+ if(unlikely(p->fds[fdid].cache_iterations_reset % spread == (size_t) fdid % spread))
+ p->fds[fdid].cache_iterations_reset++;
+
+ if(unlikely((fdid <= 2 && p->fds[fdid].cache_iterations_reset > 5) ||
+ p->fds[fdid].cache_iterations_reset > max)) {
+ // for stdin, stdout, stderr (fdid <= 2) we have checked a few times, or if it goes above the max, goto max
+ p->fds[fdid].cache_iterations_reset = max;
+ }
+
+ p->fds[fdid].cache_iterations_counter = p->fds[fdid].cache_iterations_reset;
+ }
}
closedir(fds);
@@ -1791,12 +1921,12 @@ static inline int read_pid_file_descriptors(struct pid_stat *p, void *ptr) {
// ----------------------------------------------------------------------------
-static inline int print_process_and_parents(struct pid_stat *p, usec_t time) {
+static inline int debug_print_process_and_parents(struct pid_stat *p, usec_t time) {
char *prefix = "\\_ ";
int indent = 0;
if(p->parent)
- indent = print_process_and_parents(p->parent, p->stat_collected_usec);
+ indent = debug_print_process_and_parents(p->parent, p->stat_collected_usec);
else
prefix = " > ";
@@ -1830,12 +1960,12 @@ static inline int print_process_and_parents(struct pid_stat *p, usec_t time) {
return indent + 1;
}
-static inline void print_process_tree(struct pid_stat *p, char *msg) {
- fprintf(stderr, "%s: process %s (%d, %s) with parents:\n", msg, p->comm, p->pid, p->updated?"running":"exited");
- print_process_and_parents(p, p->stat_collected_usec);
+static inline void debug_print_process_tree(struct pid_stat *p, char *msg) {
+ debug_log("%s: process %s (%d, %s) with parents:", msg, p->comm, p->pid, p->updated?"running":"exited");
+ debug_print_process_and_parents(p, p->stat_collected_usec);
}
-static inline void find_lost_child_debug(struct pid_stat *pe, kernel_uint_t lost, int type) {
+static inline void debug_find_lost_child(struct pid_stat *pe, kernel_uint_t lost, int type) {
int found = 0;
struct pid_stat *p = NULL;
@@ -1938,8 +2068,8 @@ static inline void process_exited_processes() {
if(utime + stime + gtime + minflt + majflt == 0)
continue;
- if(unlikely(debug)) {
- fprintf(stderr, "Absorb %s (%d %s total resources: utime=" KERNEL_UINT_FORMAT " stime=" KERNEL_UINT_FORMAT " gtime=" KERNEL_UINT_FORMAT " minflt=" KERNEL_UINT_FORMAT " majflt=" KERNEL_UINT_FORMAT ")\n"
+ if(unlikely(debug_enabled)) {
+ debug_log("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 ")"
, p->comm
, p->pid
, p->updated?"running":"exited"
@@ -1949,7 +2079,7 @@ static inline void process_exited_processes() {
, minflt
, majflt
);
- print_process_tree(p, "Searching parents");
+ debug_print_process_tree(p, "Searching parents");
}
struct pid_stat *pp;
@@ -1958,59 +2088,57 @@ static inline void process_exited_processes() {
kernel_uint_t absorbed;
absorbed = remove_exited_child_from_parent(&utime, &pp->cutime);
- if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " utime (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, utime);
+ if(unlikely(debug_enabled && absorbed))
+ debug_log(" > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " utime (remaining: " KERNEL_UINT_FORMAT ")", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, utime);
absorbed = remove_exited_child_from_parent(&stime, &pp->cstime);
- if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " stime (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, stime);
+ if(unlikely(debug_enabled && absorbed))
+ debug_log(" > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " stime (remaining: " KERNEL_UINT_FORMAT ")", 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 " KERNEL_UINT_FORMAT " gtime (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, gtime);
+ if(unlikely(debug_enabled && absorbed))
+ debug_log(" > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " gtime (remaining: " KERNEL_UINT_FORMAT ")", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, gtime);
absorbed = remove_exited_child_from_parent(&minflt, &pp->cminflt);
- if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " minflt (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, minflt);
+ if(unlikely(debug_enabled && absorbed))
+ debug_log(" > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " minflt (remaining: " KERNEL_UINT_FORMAT ")", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, minflt);
absorbed = remove_exited_child_from_parent(&majflt, &pp->cmajflt);
- if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " majflt (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, majflt);
+ if(unlikely(debug_enabled && absorbed))
+ debug_log(" > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " majflt (remaining: " KERNEL_UINT_FORMAT ")", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, majflt);
}
if(unlikely(utime + stime + gtime + minflt + majflt > 0)) {
- if(unlikely(debug)) {
- if(utime) find_lost_child_debug(p, utime, 3);
- if(stime) find_lost_child_debug(p, stime, 4);
- if(gtime) find_lost_child_debug(p, gtime, 5);
- if(minflt) find_lost_child_debug(p, minflt, 1);
- if(majflt) find_lost_child_debug(p, majflt, 2);
+ if(unlikely(debug_enabled)) {
+ if(utime) debug_find_lost_child(p, utime, 3);
+ if(stime) debug_find_lost_child(p, stime, 4);
+ if(gtime) debug_find_lost_child(p, gtime, 5);
+ if(minflt) debug_find_lost_child(p, minflt, 1);
+ if(majflt) debug_find_lost_child(p, majflt, 2);
}
p->keep = 1;
- if(unlikely(debug))
- fprintf(stderr, " > remaining resources - KEEP - for another loop: %s (%d %s total resources: utime=" KERNEL_UINT_FORMAT " stime=" KERNEL_UINT_FORMAT " gtime=" KERNEL_UINT_FORMAT " minflt=" KERNEL_UINT_FORMAT " majflt=" KERNEL_UINT_FORMAT ")\n"
- , p->comm
- , p->pid
- , p->updated?"running":"exited"
- , utime
- , stime
- , gtime
- , minflt
- , majflt
- );
+ debug_log(" > 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 ")"
+ , p->comm
+ , p->pid
+ , p->updated?"running":"exited"
+ , utime
+ , stime
+ , gtime
+ , minflt
+ , majflt
+ );
for(pp = p->parent; pp ; pp = pp->parent) {
if(pp->updated) break;
pp->keep = 1;
- if(unlikely(debug))
- fprintf(stderr, " > - KEEP - parent for another loop: %s (%d %s)\n"
- , pp->comm
- , pp->pid
- , pp->updated?"running":"exited"
- );
+ debug_log(" > - KEEP - parent for another loop: %s (%d %s)"
+ , pp->comm
+ , pp->pid
+ , pp->updated?"running":"exited"
+ );
}
p->utime_raw = utime * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL);
@@ -2020,16 +2148,14 @@ static inline void process_exited_processes() {
p->majflt_raw = majflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL);
p->cutime_raw = p->cstime_raw = p->cgtime_raw = p->cminflt_raw = p->cmajflt_raw = 0;
- if(unlikely(debug))
- fprintf(stderr, "\n");
+ debug_log(" ");
}
- else if(unlikely(debug)) {
- fprintf(stderr, " > totally absorbed - DONE - %s (%d %s)\n"
+ else
+ debug_log(" > totally absorbed - DONE - %s (%d %s)"
, p->comm
, p->pid
, p->updated?"running":"exited"
- );
- }
+ );
}
}
@@ -2054,8 +2180,8 @@ static inline void link_all_processes_to_their_parents(void) {
p->parent = pp;
pp->children_count++;
- if(unlikely(debug || (p->target && p->target->debug)))
- fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) on target '%s' has parent %d (%s, %s). Parent: utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", gtime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", cgtime=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT "\n", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->gtime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cgtime, pp->cminflt, pp->cmajflt);
+ if(unlikely(debug_enabled || (p->target && p->target->debug_enabled)))
+ debug_log_int("child %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 "", 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;
@@ -2105,7 +2231,7 @@ static inline int collect_data_for_pid(pid_t pid, void *ptr) {
if(unlikely(!p || p->read)) return 0;
p->read = 1;
- // fprintf(stderr, "Reading process %d (%s), sortlist %d\n", p->pid, p->comm, p->sortlist);
+ // debug_log("Reading process %d (%s), sortlist %d", p->pid, p->comm, p->sortlist);
// --------------------------------------------------------------------
// /proc/<pid>/stat
@@ -2141,8 +2267,8 @@ static inline int collect_data_for_pid(pid_t pid, void *ptr) {
// --------------------------------------------------------------------
// done!
- if(unlikely(debug && include_exited_childs && all_pids_count && p->ppid && all_pids[p->ppid] && !all_pids[p->ppid]->read))
- fprintf(stderr, "Read process %d (%s) sortlisted %d, but its parent %d (%s) sortlisted %d, is not read\n", p->pid, p->comm, p->sortlist, all_pids[p->ppid]->pid, all_pids[p->ppid]->comm, all_pids[p->ppid]->sortlist);
+ if(unlikely(debug_enabled && include_exited_childs && all_pids_count && p->ppid && all_pids[p->ppid] && !all_pids[p->ppid]->read))
+ debug_log("Read process %d (%s) sortlisted %d, but its parent %d (%s) sortlisted %d, is not read", p->pid, p->comm, p->sortlist, all_pids[p->ppid]->pid, all_pids[p->ppid]->comm, all_pids[p->ppid]->sortlist);
// mark it as updated
p->updated = 1;
@@ -2302,18 +2428,18 @@ static int collect_data_for_all_processes(void) {
// check: update_apps_groups_statistics()
static void cleanup_exited_pids(void) {
- int c;
+ size_t c;
struct pid_stat *p = NULL;
for(p = root_of_pids; p ;) {
if(!p->updated && (!p->keep || p->keeploops > 0)) {
- if(unlikely(debug && (p->keep || p->keeploops)))
- fprintf(stderr, " > CLEANUP cannot keep exited process %d (%s) anymore - removing it.\n", p->pid, p->comm);
+ if(unlikely(debug_enabled && (p->keep || p->keeploops)))
+ debug_log(" > CLEANUP cannot keep exited process %d (%s) anymore - removing it.", 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;
+ if(p->fds[c].fd > 0) {
+ file_descriptor_not_used(p->fds[c].fd);
+ clear_pid_fd(&p->fds[c]);
}
pid_t r = p->pid;
@@ -2335,7 +2461,7 @@ static void apply_apps_groups_targets_inheritance(void) {
// inherit their target from their parent
int found = 1, loops = 0;
while(found) {
- if(unlikely(debug)) loops++;
+ if(unlikely(debug_enabled)) loops++;
found = 0;
for(p = root_of_pids; p ; p = p->next) {
// if this process does not have a target
@@ -2346,8 +2472,8 @@ static void apply_apps_groups_targets_inheritance(void) {
p->target = p->parent->target;
found++;
- if(debug || (p->target && p->target->debug))
- fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
+ if(debug_enabled || (p->target && p->target->debug_enabled))
+ debug_log_int("TARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
}
}
}
@@ -2357,7 +2483,7 @@ static void apply_apps_groups_targets_inheritance(void) {
int sortlist = 1;
found = 1;
while(found) {
- if(unlikely(debug)) loops++;
+ if(unlikely(debug_enabled)) loops++;
found = 0;
for(p = root_of_pids; p ; p = p->next) {
@@ -2382,16 +2508,15 @@ static void apply_apps_groups_targets_inheritance(void) {
if(unlikely(p->target && !p->parent->target)) {
p->parent->target = p->target;
- if(debug || (p->target && p->target->debug))
- fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).\n", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);
+ if(debug_enabled || (p->target && p->target->debug_enabled))
+ debug_log_int("TARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);
}
found++;
}
}
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: TARGET INHERITANCE: merged %d processes\n", found);
+ debug_log("TARGET INHERITANCE: merged %d processes", found);
}
// init goes always to default target
@@ -2403,7 +2528,7 @@ static void apply_apps_groups_targets_inheritance(void) {
all_pids[0]->target = apps_groups_default_target;
// give a default target on all top level processes
- if(unlikely(debug)) loops++;
+ if(unlikely(debug_enabled)) loops++;
for(p = root_of_pids; p ; p = p->next) {
// if the process is not merged itself
// then is is a top level process
@@ -2421,21 +2546,20 @@ static void apply_apps_groups_targets_inheritance(void) {
// give a target to all merged child processes
found = 1;
while(found) {
- if(unlikely(debug)) loops++;
+ if(unlikely(debug_enabled)) loops++;
found = 0;
for(p = root_of_pids; p ; p = p->next) {
if(unlikely(!p->target && p->merged && p->parent && p->parent->target)) {
p->target = p->parent->target;
found++;
- if(debug || (p->target && p->target->debug))
- fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
+ if(debug_enabled || (p->target && p->target->debug_enabled))
+ debug_log_int("TARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
}
}
}
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops);
+ debug_log("apply_apps_groups_targets_inheritance() made %d loops on the process tree", loops);
}
static size_t zero_all_targets(struct target *root) {
@@ -2570,9 +2694,10 @@ static inline void aggregate_pid_fds_on_targets(struct pid_stat *p) {
reallocate_target_fds(u);
reallocate_target_fds(g);
- int c, size = p->fds_size, *fds = p->fds;
+ size_t c, size = p->fds_size;
+ struct pid_fd *fds = p->fds;
for(c = 0; c < size ;c++) {
- int fd = fds[c];
+ int fd = fds[c].fd;
if(likely(fd <= 0 || fd >= all_files_size))
continue;
@@ -2628,8 +2753,8 @@ static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p,
w->processes++;
w->num_threads += p->num_threads;
- if(unlikely(debug || w->debug))
- fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", gtime=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", cgtime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT "\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+ if(unlikely(debug_enabled || w->debug_enabled))
+ debug_log_int("aggregating '%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 "", 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) {
@@ -2660,8 +2785,8 @@ static void calculate_netdata_statistics(void) {
if(likely(p->user_target && p->user_target->uid == p->uid))
w = p->user_target;
else {
- if(unlikely(debug && p->user_target))
- fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched user from %u (%s) to %u.\n", p->pid, p->comm, p->user_target->uid, p->user_target->name, p->uid);
+ if(unlikely(debug_enabled && p->user_target))
+ debug_log("pid %d (%s) switched user from %u (%s) to %u.", p->pid, p->comm, p->user_target->uid, p->user_target->name, p->uid);
w = p->user_target = get_users_target(p->uid);
}
@@ -2676,8 +2801,8 @@ static void calculate_netdata_statistics(void) {
if(likely(p->group_target && p->group_target->gid == p->gid))
w = p->group_target;
else {
- if(unlikely(debug && p->group_target))
- fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched group from %u (%s) to %u.\n", p->pid, p->comm, p->group_target->gid, p->group_target->name, p->gid);
+ if(unlikely(debug_enabled && p->group_target))
+ debug_log("pid %d (%s) switched group from %u (%s) to %u.", p->pid, p->comm, p->group_target->gid, p->group_target->name, p->gid);
w = p->group_target = get_groups_target(p->gid);
}
@@ -2698,8 +2823,6 @@ static void calculate_netdata_statistics(void) {
// ----------------------------------------------------------------------------
// update chart dimensions
-int print_calculated_number(char *str, calculated_number value) { (void)str; (void)value; return 0; }
-
static inline void send_BEGIN(const char *type, const char *id, usec_t usec) {
fprintf(stdout, "BEGIN %s.%s %llu\n", type, id, usec);
}
@@ -2751,6 +2874,9 @@ void send_resource_usage_to_netdata(usec_t dt) {
"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 filenames '' incremental 1 1\n"
+ "DIMENSION inode_changes '' incremental 1 1\n"
+ "DIMENSION link_changes '' incremental 1 1\n"
"DIMENSION pids '' absolute 1 1\n"
"DIMENSION fds '' absolute 1 1\n"
"DIMENSION targets '' absolute 1 1\n"
@@ -2793,6 +2919,9 @@ void send_resource_usage_to_netdata(usec_t dt) {
"BEGIN netdata.apps_sizes %llu\n"
"SET calls = %zu\n"
"SET files = %zu\n"
+ "SET filenames = %zu\n"
+ "SET inode_changes = %zu\n"
+ "SET link_changes = %zu\n"
"SET pids = %zu\n"
"SET fds = %d\n"
"SET targets = %zu\n"
@@ -2804,6 +2933,9 @@ void send_resource_usage_to_netdata(usec_t dt) {
, dt
, calls_counter
, file_counter
+ , filenames_allocated_counter
+ , inodes_changed_counter
+ , links_changed_counter
, all_pids_count
, all_files_len
, apps_groups_targets_count
@@ -2854,7 +2986,7 @@ static void normalize_utilization(struct target *root) {
// here we try to eliminate them by disabling childs processing either for specific dimensions
// or entirely. Of course, either way, we disable it just a single iteration.
- kernel_uint_t max_time = processors * hz * RATES_DETAIL;
+ kernel_uint_t max_time = processors * system_hz * RATES_DETAIL;
kernel_uint_t utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
if(global_utime > max_time) global_utime = max_time;
@@ -2932,7 +3064,7 @@ static void normalize_utilization(struct target *root) {
// if(gtime_fix_ratio < 0.0) gtime_fix_ratio = 0.0;
// if(cgtime_fix_ratio < 0.0) cgtime_fix_ratio = 0.0;
- // FIXME
+ // TODO
// we use cpu time to normalize page faults
// the problem is that to find the proper max values
// for page faults we have to parse /proc/vmstat
@@ -2957,14 +3089,12 @@ static void normalize_utilization(struct target *root) {
// the report
- if(unlikely(debug)) {
- fprintf(stderr,
+ debug_log(
"SYSTEM: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " "
"COLLECTED: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " cu=" KERNEL_UINT_FORMAT " cs=" KERNEL_UINT_FORMAT " cg=" KERNEL_UINT_FORMAT " "
"DELTA: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " "
"FIX: u=%0.2f s=%0.2f g=%0.2f cu=%0.2f cs=%0.2f cg=%0.2f "
"FINALLY: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " cu=" KERNEL_UINT_FORMAT " cs=" KERNEL_UINT_FORMAT " cg=" KERNEL_UINT_FORMAT " "
- "\n"
, global_utime
, global_stime
, global_gtime
@@ -2989,8 +3119,7 @@ static void normalize_utilization(struct target *root) {
, (kernel_uint_t)(cutime * cutime_fix_ratio)
, (kernel_uint_t)(cstime * cstime_fix_ratio)
, (kernel_uint_t)(cgtime * cgtime_fix_ratio)
- );
- }
+ );
}
#else // ALL_PIDS_ARE_READ_INSTANTLY == 1
static void normalize_utilization(struct target *root) {
@@ -3151,7 +3280,8 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
if (!w->exposed && w->processes) {
newly_added++;
w->exposed = 1;
- if (debug || w->debug) fprintf(stderr, "apps.plugin: %s just added - regenerating charts.\n", w->name);
+ if (debug_enabled || w->debug_enabled)
+ debug_log_int("%s just added - regenerating charts.", w->name);
}
}
@@ -3163,7 +3293,7 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
fprintf(stdout, "CHART %s.cpu '' '%s CPU Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu stacked 20001 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- fprintf(stdout, "DIMENSION %s '' absolute 1 %llu %s\n", w->name, hz * RATES_DETAIL / 100, w->hidden ? "hidden" : "");
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu %s\n", w->name, system_hz * RATES_DETAIL / 100, w->hidden ? "hidden" : "");
}
fprintf(stdout, "CHART %s.mem '' '%s Real Memory (w/o shared)' 'MB' mem %s.mem stacked 20003 %d\n", type, title, type, update_every);
@@ -3193,20 +3323,20 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
fprintf(stdout, "CHART %s.cpu_user '' '%s CPU User Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_user stacked 20020 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, system_hz * RATES_DETAIL / 100LLU);
}
fprintf(stdout, "CHART %s.cpu_system '' '%s CPU System Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20021 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, system_hz * RATES_DETAIL / 100LLU);
}
if(show_guest_time) {
fprintf(stdout, "CHART %s.cpu_guest '' '%s CPU Guest Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20022 %d\n", type, title, (processors * 100), processors, (processors > 1) ? "s" : "", type, update_every);
for (w = root; w; w = w->next) {
if(unlikely(w->exposed))
- fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, system_hz * RATES_DETAIL / 100LLU);
}
}
@@ -3315,7 +3445,6 @@ cleanup:
static void parse_args(int argc, char **argv)
{
int i, freq = 0;
- char *name = NULL;
for(i = 1; i < argc; i++) {
if(!freq) {
@@ -3341,10 +3470,26 @@ static void parse_args(int argc, char **argv)
}
if(strcmp("debug", argv[i]) == 0) {
- debug = 1;
- // debug_flags = 0xffffffff;
+#ifdef NETDATA_INTERNAL_CHECKS
+ debug_enabled = 1;
+#else
+ fprintf(stderr, "apps.plugin has been compiled without debugging\n");
+#endif
+ continue;
+ }
+
+#ifndef __FreeBSD__
+ if(strcmp("fds-cache-secs", argv[i]) == 0) {
+ if(argc <= i + 1) {
+ fprintf(stderr, "Parameter 'fds-cache-secs' requires a number as argument.\n");
+ exit(1);
+ }
+ i++;
+ max_fds_cache_seconds = str2i(argv[i]);
+ if(max_fds_cache_seconds < 0) max_fds_cache_seconds = 0;
continue;
}
+#endif
if(strcmp("no-childs", argv[i]) == 0 || strcmp("without-childs", argv[i]) == 0) {
include_exited_childs = 0;
@@ -3415,44 +3560,54 @@ static void parse_args(int argc, char **argv)
" without-files enable / disable reporting files, sockets, pipes\n"
" (default is enabled)\n"
"\n"
- " NAME read apps_NAME.conf instead of\n"
- " apps_groups.conf\n"
- " (default NAME=groups)\n"
+#ifndef __FreeBSD__
+ " fds-cache-secs N cache the files of processed for N seconds\n"
+ " caching is adaptive per file (when a file\n"
+ " is found, it starts at 0 and while the file\n"
+ " remains open, it is incremented up to the\n"
+ " max given)\n"
+ " (default is %d seconds)\n"
"\n"
+#endif
" version or -v or -V print program version and exit\n"
"\n"
, VERSION
+#ifndef __FreeBSD__
+ , max_fds_cache_seconds
+#endif
);
exit(1);
}
- if(!name) {
- name = argv[i];
- continue;
- }
-
error("Cannot understand option %s", argv[i]);
exit(1);
}
if(freq > 0) update_every = freq;
- if(!name) name = "groups";
- if(read_apps_groups_conf(name)) {
- error("Cannot read process groups '%s/apps_%s.conf'. There are no internal defaults. Failing.", config_dir, name);
- exit(1);
+ if(read_apps_groups_conf(user_config_dir, "groups")) {
+ info("Cannot read process groups configuration file '%s/apps_groups.conf'. Will try '%s/apps_groups.conf'", user_config_dir, stock_config_dir);
+
+ if(read_apps_groups_conf(stock_config_dir, "groups")) {
+ error("Cannot read process groups '%s/apps_groups.conf'. There are no internal defaults. Failing.", stock_config_dir);
+ exit(1);
+ }
+ else
+ info("Loaded config file '%s/apps_groups.conf'", stock_config_dir);
}
+ else
+ info("Loaded config file '%s/apps_groups.conf'", user_config_dir);
}
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);
+ if(debug_enabled) 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);
+ if(debug_enabled) info("I am not running with escalated privileges, uid = %u, euid = %u.", uid, euid);
return 0;
}
@@ -3463,7 +3618,7 @@ static int check_capabilities() {
error("Cannot get current capabilities.");
return 0;
}
- else if(debug)
+ else if(debug_enabled)
info("Received my capabilities from the system.");
int ret = 1;
@@ -3478,7 +3633,7 @@ static int check_capabilities() {
error("apps.plugin should run with CAP_DAC_READ_SEARCH.");
ret = 0;
}
- else if(debug)
+ else if(debug_enabled)
info("apps.plugin runs with CAP_DAC_READ_SEARCH.");
}
@@ -3492,7 +3647,7 @@ static int check_capabilities() {
error("apps.plugin should run with CAP_SYS_PTRACE.");
ret = 0;
}
- else if(debug)
+ else if(debug_enabled)
info("apps.plugin runs with CAP_SYS_PTRACE.");
}
@@ -3521,19 +3676,25 @@ int main(int argc, char **argv) {
error_log_errors_per_period = 100;
error_log_throttle_period = 3600;
+ // since apps.plugin runs as root, prevent it from opening symbolic links
+ procfile_open_flags = O_RDONLY|O_NOFOLLOW;
+
netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
- if(netdata_configured_host_prefix == NULL) {
- // info("NETDATA_HOST_PREFIX is not passed from netdata");
- netdata_configured_host_prefix = "";
+ if(verify_netdata_host_prefix() == -1) exit(1);
+
+ user_config_dir = getenv("NETDATA_USER_CONFIG_DIR");
+ if(user_config_dir == NULL) {
+ // info("NETDATA_CONFIG_DIR is not passed from netdata");
+ user_config_dir = CONFIG_DIR;
}
- // else info("Found NETDATA_HOST_PREFIX='%s'", netdata_configured_host_prefix);
+ // else info("Found NETDATA_USER_CONFIG_DIR='%s'", user_config_dir);
- config_dir = getenv("NETDATA_CONFIG_DIR");
- if(config_dir == NULL) {
+ stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
+ if(stock_config_dir == NULL) {
// info("NETDATA_CONFIG_DIR is not passed from netdata");
- config_dir = CONFIG_DIR;
+ stock_config_dir = LIBCONFIG_DIR;
}
- // else info("Found NETDATA_CONFIG_DIR='%s'", config_dir);
+ // else info("Found NETDATA_USER_CONFIG_DIR='%s'", user_config_dir);
#ifdef NETDATA_INTERNAL_CHECKS
if(debug_flags != 0) {
@@ -3561,14 +3722,14 @@ int main(int argc, char **argv) {
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; "
+ "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %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; "
+ "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; "
, uid, euid, argv[0], argv[0]
);
#endif
@@ -3630,8 +3791,7 @@ int main(int argc, char **argv) {
show_guest_time_old = show_guest_time;
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: done Loop No %zu\n", global_iterations_counter);
+ debug_log("done Loop No %zu", global_iterations_counter);
// restart check (14400 seconds)
if(now_monotonic_sec() - started_t > 14400) exit(0);
diff --git a/collectors/cgroups.plugin/Makefile.am b/collectors/cgroups.plugin/Makefile.am
new file mode 100644
index 000000000..eb3214ab2
--- /dev/null
+++ b/collectors/cgroups.plugin/Makefile.am
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+CLEANFILES = \
+ cgroup-name.sh \
+ $(NULL)
+
+include $(top_srcdir)/build/subst.inc
+SUFFIXES = .in
+
+dist_plugins_SCRIPTS = \
+ cgroup-name.sh \
+ cgroup-network-helper.sh \
+ $(NULL)
+
+dist_noinst_DATA = \
+ cgroup-name.sh.in \
+ README.md \
+ $(NULL)
diff --git a/charts.d/Makefile.in b/collectors/cgroups.plugin/Makefile.in
index ebd1af2be..49c3c9834 100644
--- a/charts.d/Makefile.in
+++ b/collectors/cgroups.plugin/Makefile.in
@@ -14,6 +14,8 @@
@SET_MAKE@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
@@ -79,18 +81,21 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-subdir = charts.d
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
- $(dist_charts_SCRIPTS) $(dist_charts_DATA)
+DIST_COMMON = $(top_srcdir)/build/subst.inc $(srcdir)/Makefile.in \
+ $(srcdir)/Makefile.am $(dist_plugins_SCRIPTS) \
+ $(dist_noinst_DATA)
+subdir = collectors/cgroups.plugin
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
- $(top_srcdir)/m4/ax_c_mallinfo.m4 \
- $(top_srcdir)/m4/ax_c_mallopt.m4 \
- $(top_srcdir)/m4/ax_check_compile_flag.m4 \
- $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
- $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/jemalloc.m4 \
- $(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
@@ -124,8 +129,8 @@ am__uninstall_files_from_dir = { \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
-am__installdirs = "$(DESTDIR)$(chartsdir)" "$(DESTDIR)$(chartsdir)"
-SCRIPTS = $(dist_charts_SCRIPTS)
+am__installdirs = "$(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
@@ -145,7 +150,7 @@ am__can_run_installinfo = \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
-DATA = $(dist_charts_DATA)
+DATA = $(dist_noinst_DATA)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
@@ -245,6 +250,7 @@ build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
+build_target = @build_target@
build_vendor = @build_vendor@
builddir = @builddir@
cachedir = @cachedir@
@@ -266,6 +272,7 @@ htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
+libconfigdir = @libconfigdir@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
@@ -292,42 +299,28 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
varlibdir = @varlibdir@
webdir = @webdir@
-
-#
-# Copyright (C) 2015 Alon Bar-Lev <alon.barlev@gmail.com>
-#
+AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
-dist_charts_SCRIPTS = \
+CLEANFILES = \
+ cgroup-name.sh \
+ $(NULL)
+
+SUFFIXES = .in
+dist_plugins_SCRIPTS = \
+ cgroup-name.sh \
+ cgroup-network-helper.sh \
$(NULL)
-dist_charts_DATA = \
+dist_noinst_DATA = \
+ cgroup-name.sh.in \
README.md \
- ap.chart.sh \
- apcupsd.chart.sh \
- apache.chart.sh \
- cpu_apps.chart.sh \
- cpufreq.chart.sh \
- example.chart.sh \
- exim.chart.sh \
- hddtemp.chart.sh \
- libreswan.chart.sh \
- load_average.chart.sh \
- mem_apps.chart.sh \
- mysql.chart.sh \
- nginx.chart.sh \
- nut.chart.sh \
- opensips.chart.sh \
- phpfpm.chart.sh \
- postfix.chart.sh \
- sensors.chart.sh \
- squid.chart.sh \
- tomcat.chart.sh \
$(NULL)
all: all-am
.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+.SUFFIXES: .in
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/build/subst.inc $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -336,9 +329,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
exit 1;; \
esac; \
done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu charts.d/Makefile'; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/cgroups.plugin/Makefile'; \
$(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --gnu charts.d/Makefile
+ $(AUTOMAKE) --gnu collectors/cgroups.plugin/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
@@ -348,6 +341,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:
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
@@ -357,12 +351,12 @@ $(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):
-install-dist_chartsSCRIPTS: $(dist_charts_SCRIPTS)
+install-dist_pluginsSCRIPTS: $(dist_plugins_SCRIPTS)
@$(NORMAL_INSTALL)
- @list='$(dist_charts_SCRIPTS)'; test -n "$(chartsdir)" || list=; \
+ @list='$(dist_plugins_SCRIPTS)'; test -n "$(pluginsdir)" || list=; \
if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(chartsdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(chartsdir)" || exit 1; \
+ 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; \
@@ -381,38 +375,17 @@ install-dist_chartsSCRIPTS: $(dist_charts_SCRIPTS)
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
- echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(chartsdir)$$dir'"; \
- $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(chartsdir)$$dir" || exit $$?; \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pluginsdir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pluginsdir)$$dir" || exit $$?; \
} \
; done
-uninstall-dist_chartsSCRIPTS:
+uninstall-dist_pluginsSCRIPTS:
@$(NORMAL_UNINSTALL)
- @list='$(dist_charts_SCRIPTS)'; test -n "$(chartsdir)" || exit 0; \
+ @list='$(dist_plugins_SCRIPTS)'; test -n "$(pluginsdir)" || exit 0; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 's,.*/,,;$(transform)'`; \
- dir='$(DESTDIR)$(chartsdir)'; $(am__uninstall_files_from_dir)
-install-dist_chartsDATA: $(dist_charts_DATA)
- @$(NORMAL_INSTALL)
- @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"; \
- done | $(am__base_list) | \
- while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(chartsdir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(chartsdir)" || exit $$?; \
- done
-
-uninstall-dist_chartsDATA:
- @$(NORMAL_UNINSTALL)
- @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)
+ dir='$(DESTDIR)$(pluginsdir)'; $(am__uninstall_files_from_dir)
tags TAGS:
ctags CTAGS:
@@ -454,7 +427,7 @@ check-am: all-am
check: check-am
all-am: Makefile $(SCRIPTS) $(DATA)
installdirs:
- for dir in "$(DESTDIR)$(chartsdir)" "$(DESTDIR)$(chartsdir)"; do \
+ for dir in "$(DESTDIR)$(pluginsdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -479,6 +452,7 @@ install-strip:
mostlyclean-generic:
clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -508,7 +482,7 @@ info: info-am
info-am:
-install-data-am: install-dist_chartsDATA install-dist_chartsSCRIPTS
+install-data-am: install-dist_pluginsSCRIPTS
install-dvi: install-dvi-am
@@ -552,23 +526,37 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-dist_chartsDATA uninstall-dist_chartsSCRIPTS
+uninstall-am: 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_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 \
- uninstall-dist_chartsDATA uninstall-dist_chartsSCRIPTS
-
+ install-data-am 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_pluginsSCRIPTS
+
+.in:
+ if sed \
+ -e 's#[@]localstatedir_POST@#$(localstatedir)#g' \
+ -e 's#[@]sbindir_POST@#$(sbindir)#g' \
+ -e 's#[@]sysconfdir_POST@#$(sysconfdir)#g' \
+ -e 's#[@]pythondir_POST@#$(pythondir)#g' \
+ -e 's#[@]configdir_POST@#$(configdir)#g' \
+ -e 's#[@]libconfigdir_POST@#$(libconfigdir)#g' \
+ -e 's#[@]cachedir_POST@#$(cachedir)#g' \
+ $< > $@.tmp; then \
+ mv "$@.tmp" "$@"; \
+ else \
+ rm -f "$@.tmp"; \
+ false; \
+ 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/collectors/cgroups.plugin/README.md b/collectors/cgroups.plugin/README.md
new file mode 100644
index 000000000..e78aa0440
--- /dev/null
+++ b/collectors/cgroups.plugin/README.md
@@ -0,0 +1,187 @@
+# cgroups.plugin
+
+You can monitor containers and virtual machines using **cgroups**.
+
+cgroups (or control groups), are a Linux kernel feature that provides accounting and resource usage limiting for processes. When cgroups are bundled with namespaces (i.e. isolation), they form what we usually call **containers**.
+
+cgroups are hierarchical, meaning that cgroups can contain child cgroups, which can contain more cgroups, etc. All accounting is reported (and resource usage limits are applied) also in a hierarchical way.
+
+To visualize cgroup metrics netdata provides configuration for cherry picking the cgroups of interest. By default (without any configuration) netdata should pick **systemd services**, all kinds of **containers** (lxc, docker, etc) and **virtual machines** spawn by managers that register them with cgroups (qemu, libvirt, etc).
+
+## configuring netdata for cgroups
+
+For each cgroup available in the system, netdata provides this configuration:
+
+```
+[plugin:cgroups]
+ enable cgroup XXX = yes | no
+```
+
+But it also provides a few patterns to provide a sane default (`yes` or `no`).
+
+Below we see, how this works.
+
+### how netdata finds the available cgroups
+
+Linux exposes resource usage reporting and provides dynamic configuration for cgroups, using virtual files (usually) under `/sys/fs/cgroup`. netdata reads `/proc/self/mountinfo` to detect the exact mount point of cgroups. netdata also allows manual configuration of this mount point, using these settings:
+
+```
+[plugin:cgroups]
+ check for new cgroups every = 10
+ path to /sys/fs/cgroup/cpuacct = /sys/fs/cgroup/cpuacct
+ path to /sys/fs/cgroup/blkio = /sys/fs/cgroup/blkio
+ path to /sys/fs/cgroup/memory = /sys/fs/cgroup/memory
+ path to /sys/fs/cgroup/devices = /sys/fs/cgroup/devices
+```
+
+netdata rescans these directories for added or removed cgroups every `check for new cgroups every` seconds.
+
+### hierarchical search for cgroups
+
+Since cgroups are hierarchical, for each of the directories shown above, netdata walks through the subdirectories recursively searching for cgroups (each subdirectory is another cgroup).
+
+For each of the directories found, netdata provides a configuration variable:
+
+```
+[plugin:cgroups]
+ search for cgroups under PATH = yes | no
+```
+
+To provide a sane default for this setting, netdata uses the following pattern list (patterns starting with `!` give a negative match and their order is important: the first matching a path will be used):
+
+```
+[plugin:cgroups]
+ search for cgroups in subpaths matching = !*/init.scope !*-qemu !/init.scope !/system !/systemd !/user !/user.slice *
+```
+
+So, we disable checking for **child cgroups** in systemd internal cgroups ([systemd services are monitored by netdata](https://github.com/netdata/netdata/wiki/monitoring-systemd-services)), user cgroups (normally used for desktop and remote user sessions), qemu virtual machines (child cgroups of virtual machines) and `init.scope`. All others are enabled.
+
+
+### enabled cgroups
+
+To check if the cgroup is enabled, netdata uses this setting:
+
+```
+[plugin:cgroups]
+ enable cgroup NAME = yes | no
+```
+
+To provide a sane default, netdata uses the following pattern list (it checks the pattern against the path of the cgroup):
+
+```
+[plugin:cgroups]
+ enable by default cgroups matching = !*/init.scope *.scope !*/vcpu* !*/emulator !*.mount !*.partition !*.service !*.slice !*.swap !*.user !/ !/docker !/libvirt !/lxc !/lxc/*/ns !/lxc/*/ns/* !/machine !/qemu !/system !/systemd !/user *
+```
+
+The above provides the default `yes` or `no` setting for the cgroup. However, there is an additional step. In many cases the cgroups found in the `/sys/fs/cgroup` hierarchy are just random numbers and in many cases these numbers are ephemeral: they change across reboots or sessions.
+
+So, we need to somehow map the paths of the cgroups to names, to provide consistent netdata configuration (i.e. there is no point to say `enable cgroup 1234 = yes | no`, if `1234` is a random number that changes over time - we need a name for the cgroup first, so that `enable cgroup NAME = yes | no` will be consistent).
+
+For this mapping netdata provides 2 configuration options:
+
+```
+[plugin:cgroups]
+ run script to rename cgroups matching = *.scope *docker* *lxc* *qemu* !/ !*.mount !*.partition !*.service !*.slice !*.swap !*.user *
+ script to get cgroup names = /usr/libexec/netdata/plugins.d/cgroup-name.sh
+```
+
+The whole point for the additional pattern list, is to limit the number of times the script will be called. Without this pattern list, the script might be called thousands of times, depending on the number of cgroups available in the system.
+
+The above pattern list is matched against the path of the cgroup. For matched cgroups, netdata calls the script [cgroup-name.sh](https://github.com/netdata/netdata/blob/master/collectors/cgroups.plugin/cgroup-name.sh.in) to get its name. This script queries `docker`, or applies heuristics to find give a name for the cgroup.
+
+## Monitoring systemd services
+
+netdata monitors **systemd services**. Example:
+
+![image](https://cloud.githubusercontent.com/assets/2662304/21964372/20cd7b84-db53-11e6-98a2-b9c986b082c0.png)
+
+Support per distribution:
+
+system|systemd services<br/>charts shown|`tree`<br/>`/sys/fs/cgroup`|comments
+:-------:|:-------:|:-------:|:------------
+Arch Linux|YES| |
+Gentoo|NO| |can be enabled, see below
+Ubuntu 16.04 LTS|YES| |
+Ubuntu 16.10|YES|[here](http://pastebin.com/PiWbQEXy)|
+Fedora 25|YES|[here](http://pastebin.com/ax0373wF)|
+Debian 8|NO| |can be enabled, see below
+AMI|NO|[here](http://pastebin.com/FrxmptjL)|not a systemd system
+Centos 7.3.1611|NO|[here](http://pastebin.com/SpzgezAg)|can be enabled, see below
+
+#### how to enable cgroup accounting on systemd systems that is by default disabled
+
+You can verify there is no accounting enabled, by running `systemd-cgtop`. The program will show only resources for cgroup ` / `, but all services will show nothing.
+
+To enable cgroup accounting, execute this:
+
+```sh
+sed -e 's|^#Default\(.*\)Accounting=.*$|Default\1Accounting=yes|g' /etc/systemd/system.conf >/tmp/system.conf
+```
+
+To see the changes it made, run this:
+
+```
+# diff /etc/systemd/system.conf /tmp/system.conf
+40,44c40,44
+< #DefaultCPUAccounting=no
+< #DefaultIOAccounting=no
+< #DefaultBlockIOAccounting=no
+< #DefaultMemoryAccounting=no
+< #DefaultTasksAccounting=yes
+---
+> DefaultCPUAccounting=yes
+> DefaultIOAccounting=yes
+> DefaultBlockIOAccounting=yes
+> DefaultMemoryAccounting=yes
+> DefaultTasksAccounting=yes
+```
+
+If you are happy with the changes, run:
+
+```sh
+# copy the file to the right location
+sudo cp /tmp/system.conf /etc/systemd/system.conf
+
+# restart systemd to take it into account
+sudo systemctl daemon-reexec
+```
+
+(`systemctl daemon-reload` does not reload the configuration of the server - so you have to execute `systemctl daemon-reexec`).
+
+Now, when you run `systemd-cgtop`, services will start reporting usage (if it does not, restart a service - any service - to wake it up). Refresh your netdata dashboard, and you will have the charts too.
+
+In case memory accounting is missing, you will need to enable it at your kernel, by appending the following kernel boot options and rebooting:
+
+```
+cgroup_enable=memory swapaccount=1
+```
+
+You can add the above, directly at the `linux` line in your `/boot/grub/grub.cfg` or appending them to the `GRUB_CMDLINE_LINUX` in `/etc/default/grub` (in which case you will have to run `update-grub` before rebooting). On DigitalOcean debian images you may have to set it at `/etc/default/grub.d/50-cloudimg-settings.cfg`.
+
+---
+
+## Monitoring ephemeral containers
+
+netdata monitors containers automatically when it is installed at the host, or when it is installed in a container that has access to the `/proc` and `/sys` filesystems of the host.
+
+netdata prior to v1.6 had 2 issues when such containers were monitored:
+
+1. network interface alarms where triggering when containers were stopped
+
+2. charts were never cleaned up, so after some time dozens of containers were showing up on the dashboard, and they were occupying memory.
+
+
+### the current netdata
+
+network interfaces and cgroups (containers) are now self-cleaned.
+
+So, when a network interface or container stops, netdata might log a few errors in error.log complaining about files it cannot find, but immediately:
+
+1. it will detect this is a removed container or network interface
+2. it will freeze/pause all alarms for them
+3. it will mark their charts as obsolete
+4. obsolete charts are not be offered on new dashboard sessions (so hit F5 and the charts are gone)
+5. existing dashboard sessions will continue to see them, but of course they will not refresh
+6. obsolete charts will be removed from memory, 1 hour after the last user viewed them (configurable with `[global].cleanup obsolete charts after seconds = 3600` (at netdata.conf).
+7. when obsolete charts are removed from memory they are also deleted from disk (configurable with `[global].delete obsolete charts files = yes`)
+
diff --git a/plugins.d/cgroup-name.sh b/collectors/cgroups.plugin/cgroup-name.sh
index 3c8ad7205..6bf8b8b03 100755..100644
--- a/plugins.d/cgroup-name.sh
+++ b/collectors/cgroups.plugin/cgroup-name.sh
@@ -3,7 +3,7 @@
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
+# SPDX-License-Identifier: GPL-3.0-or-later
#
# Script to find a better name for cgroups
#
@@ -51,8 +51,10 @@ debug() {
# -----------------------------------------------------------------------------
-[ -z "${NETDATA_CONFIG_DIR}" ] && NETDATA_CONFIG_DIR="$(dirname "${0}")/../../../../etc/netdata"
-CONFIG="${NETDATA_CONFIG_DIR}/cgroups-names.conf"
+[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="/usr/local/etc/netdata"
+[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="/usr/local/lib/netdata/conf.d"
+
+DOCKER_HOST="${DOCKER_HOST:=/var/run/docker.sock}"
CGROUP="${1}"
NAME=
@@ -63,16 +65,21 @@ if [ -z "${CGROUP}" ]
fatal "called without a cgroup name. Nothing to do."
fi
-if [ -f "${CONFIG}" ]
+for CONFIG in "${NETDATA_USER_CONFIG_DIR}/cgroups-names.conf" "${NETDATA_STOCK_CONFIG_DIR}/cgroups-names.conf"
+do
+ if [ -f "${CONFIG}" ]
then
- NAME="$(grep "^${CGROUP} " "${CONFIG}" | sed "s/[[:space:]]\+/ /g" | cut -d ' ' -f 2)"
- if [ -z "${NAME}" ]
- then
- info "cannot find cgroup '${CGROUP}' in '${CONFIG}'."
+ NAME="$(grep "^${CGROUP} " "${CONFIG}" | sed "s/[[:space:]]\+/ /g" | cut -d ' ' -f 2)"
+ if [ -z "${NAME}" ]
+ then
+ info "cannot find cgroup '${CGROUP}' in '${CONFIG}'."
+ else
+ break
+ fi
+ #else
+ # info "configuration file '${CONFIG}' is not available."
fi
-#else
-# info "configuration file '${CONFIG}' is not available."
-fi
+done
function docker_get_name_classic {
local id="${1}"
@@ -83,13 +90,13 @@ function docker_get_name_classic {
function docker_get_name_api {
local id="${1}"
- if [ ! -S "/var/run/docker.sock" ]
+ if [ ! -S "${DOCKER_HOST}" ]
then
- warning "Can't find /var/run/docker.sock"
+ warning "Can't find ${DOCKER_HOST}"
return 1
fi
info "Running API command: /containers/${id}/json"
- JSON=$(echo -e "GET /containers/${id}/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock | grep '^{.*')
+ JSON=$(echo -e "GET /containers/${id}/json HTTP/1.0\r\n" | nc -U ${DOCKER_HOST} | grep '^{.*')
NAME=$(echo $JSON | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
return 0
}
diff --git a/collectors/cgroups.plugin/cgroup-name.sh.in b/collectors/cgroups.plugin/cgroup-name.sh.in
new file mode 100755
index 000000000..53696a4bf
--- /dev/null
+++ b/collectors/cgroups.plugin/cgroup-name.sh.in
@@ -0,0 +1,196 @@
+#!/usr/bin/env bash
+
+# netdata
+# real-time performance and health monitoring, done right!
+# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# Script to find a better name for cgroups
+#
+
+export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin"
+export LC_ALL=C
+
+# -----------------------------------------------------------------------------
+
+PROGRAM_NAME="$(basename "${0}")"
+
+logdate() {
+ date "+%Y-%m-%d %H:%M:%S"
+}
+
+log() {
+ local status="${1}"
+ shift
+
+ echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}"
+
+}
+
+warning() {
+ log WARNING "${@}"
+}
+
+error() {
+ log ERROR "${@}"
+}
+
+info() {
+ log INFO "${@}"
+}
+
+fatal() {
+ log FATAL "${@}"
+ exit 1
+}
+
+debug=0
+debug() {
+ [ $debug -eq 1 ] && log DEBUG "${@}"
+}
+
+# -----------------------------------------------------------------------------
+
+[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@"
+[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="@libconfigdir_POST@"
+
+DOCKER_HOST="${DOCKER_HOST:=/var/run/docker.sock}"
+CGROUP="${1}"
+NAME=
+
+# -----------------------------------------------------------------------------
+
+if [ -z "${CGROUP}" ]
+ then
+ fatal "called without a cgroup name. Nothing to do."
+fi
+
+for CONFIG in "${NETDATA_USER_CONFIG_DIR}/cgroups-names.conf" "${NETDATA_STOCK_CONFIG_DIR}/cgroups-names.conf"
+do
+ if [ -f "${CONFIG}" ]
+ then
+ NAME="$(grep "^${CGROUP} " "${CONFIG}" | sed "s/[[:space:]]\+/ /g" | cut -d ' ' -f 2)"
+ if [ -z "${NAME}" ]
+ then
+ info "cannot find cgroup '${CGROUP}' in '${CONFIG}'."
+ else
+ break
+ fi
+ #else
+ # info "configuration file '${CONFIG}' is not available."
+ fi
+done
+
+function docker_get_name_classic {
+ local id="${1}"
+ info "Running command: docker ps --filter=id=\"${id}\" --format=\"{{.Names}}\""
+ NAME="$( docker ps --filter=id="${id}" --format="{{.Names}}" )"
+ return 0
+}
+
+function docker_get_name_api {
+ local id="${1}"
+ if [ ! -S "${DOCKER_HOST}" ]
+ then
+ warning "Can't find ${DOCKER_HOST}"
+ return 1
+ fi
+ info "Running API command: /containers/${id}/json"
+ JSON=$(echo -e "GET /containers/${id}/json HTTP/1.0\r\n" | nc -U ${DOCKER_HOST} | grep '^{.*')
+ NAME=$(echo $JSON | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
+ return 0
+}
+
+function docker_get_name {
+ local id="${1}"
+ if hash docker 2>/dev/null
+ then
+ docker_get_name_classic "${id}"
+ else
+ docker_get_name_api "${id}" || docker_get_name_classic "${id}"
+ fi
+ if [ -z "${NAME}" ]
+ then
+ warning "cannot find the name of docker container '${id}'"
+ NAME="${id:0:12}"
+ else
+ info "docker container '${id}' is named '${NAME}'"
+ fi
+}
+
+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}"
+
+ if [ ! -z "${DOCKERID}" -a \( ${#DOCKERID} -eq 64 -o ${#DOCKERID} -eq 12 \) ]
+ then
+ docker_get_name "${DOCKERID}"
+ else
+ error "a docker id cannot be extracted from docker cgroup '${CGROUP}'."
+ fi
+ elif [[ "${CGROUP}" =~ ^.*kubepods[_/].*[_/]pod[a-fA-F0-9-]+[_/][a-fA-F0-9]+$ ]]
+ then
+ # kubernetes
+
+ DOCKERID="$( echo "${CGROUP}" | sed "s|^.*kubepods[_/].*[_/]pod[a-fA-F0-9-]\+[_/]\([a-fA-F0-9]\+\)$|\1|" )"
+ # echo "DOCKERID=${DOCKERID}"
+
+ if [ ! -z "${DOCKERID}" -a \( ${#DOCKERID} -eq 64 -o ${#DOCKERID} -eq 12 \) ]
+ then
+ docker_get_name "${DOCKERID}"
+ else
+ error "a docker id cannot be extracted from kubernetes cgroup '${CGROUP}'."
+ fi
+ elif [[ "${CGROUP}" =~ machine.slice[_/].*\.service ]]
+ then
+ # systemd-nspawn
+
+ NAME="$(echo ${CGROUP} | sed 's/.*machine.slice[_\/]\(.*\)\.service/\1/g')"
+
+ 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')"
+ NAME="qemu_$(echo ${CGROUP} | sed 's/machine.slice_machine.*-qemu//; s/\/x2d[[:digit:]]*//; s/\/x2d//g; s/\.scope//g')"
+
+ elif [[ "${CGROUP}" =~ machine_.*\.libvirt-qemu ]]
+ then
+ # libvirtd / qemu virtual machines
+ NAME="qemu_$(echo ${CGROUP} | sed 's/^machine_//; s/\.libvirt-qemu$//; s/-/_/;')"
+
+ elif [[ "${CGROUP}" =~ qemu.slice_([0-9]+).scope && -d /etc/pve ]]
+ then
+ # Proxmox VMs
+
+ FILENAME="/etc/pve/qemu-server/${BASH_REMATCH[1]}.conf"
+ if [[ -f $FILENAME && -r $FILENAME ]]
+ then
+ NAME="qemu_$(grep -e '^name: ' "/etc/pve/qemu-server/${BASH_REMATCH[1]}.conf" | head -1 | sed -rn 's|\s*name\s*:\s*(.*)?$|\1|p')"
+ else
+ error "proxmox config file missing ${FILENAME} or netdata does not have read access. Please ensure netdata is a member of www-data group."
+ fi
+ elif [[ "${CGROUP}" =~ lxc_([0-9]+) && -d /etc/pve ]]
+ then
+ # Proxmox Containers (LXC)
+
+ FILENAME="/etc/pve/lxc/${BASH_REMATCH[1]}.conf"
+ if [[ -f ${FILENAME} && -r ${FILENAME} ]]
+ then
+ NAME=$(grep -e '^hostname: ' /etc/pve/lxc/${BASH_REMATCH[1]}.conf | head -1 | sed -rn 's|\s*hostname\s*:\s*(.*)?$|\1|p')
+ else
+ error "proxmox config file missing ${FILENAME} or netdata does not have read access. Please ensure netdata is a member of www-data group."
+ fi
+ fi
+
+ [ -z "${NAME}" ] && NAME="${CGROUP}"
+ [ ${#NAME} -gt 100 ] && NAME="${NAME:0:100}"
+fi
+
+info "cgroup '${CGROUP}' is called '${NAME}'"
+echo "${NAME}"
diff --git a/plugins.d/cgroup-network-helper.sh b/collectors/cgroups.plugin/cgroup-network-helper.sh
index f07059986..666f02fc8 100755
--- a/plugins.d/cgroup-network-helper.sh
+++ b/collectors/cgroups.plugin/cgroup-network-helper.sh
@@ -1,10 +1,11 @@
#!/usr/bin/env bash
+# shellcheck disable=SC1117
# cgroup-network-helper.sh
# detect container and virtual machine interfaces
#
# (C) 2017 Costa Tsaousis
-# GPL v3+
+# SPDX-License-Identifier: GPL-3.0-or-later
#
# This script is called as root (by cgroup-network), with either a pid, or a cgroup path.
# It tries to find all the network interfaces that belong to the same cgroup.
@@ -23,6 +24,7 @@
# -----------------------------------------------------------------------------
# the system path is cleared by cgroup-network
+# shellcheck source=/dev/null
[ -f /etc/profile ] && source /etc/profile
export LC_ALL=C
@@ -66,7 +68,7 @@ debug() {
# -----------------------------------------------------------------------------
# check for BASH v4+ (required for associative arrays)
-[ $(( ${BASH_VERSINFO[0]} )) -lt 4 ] && \
+[ $(( BASH_VERSINFO[0] )) -lt 4 ] && \
fatal "BASH version 4 or later is required (this is ${BASH_VERSION})."
# -----------------------------------------------------------------------------
@@ -86,7 +88,7 @@ do
shift
done
-if [ -z "${pid}" -a -z "${cgroup}" ]
+if [ -z "${pid}" ] && [ -z "${cgroup}" ]
then
fatal "Either --pid or --cgroup is required"
fi
@@ -103,7 +105,7 @@ set_source() {
# cgroup-network can detect veth interfaces by itself (written in C).
# If you seek for a shell version of what it does, check this:
-# https://github.com/firehol/netdata/issues/474#issuecomment-317866709
+# https://github.com/netdata/netdata/issues/474#issuecomment-317866709
# -----------------------------------------------------------------------------
@@ -115,7 +117,7 @@ proc_pid_fdinfo_iff() {
debug "Searching for tun/tap interfaces for pid ${p}..."
set_source "fdinfo"
- grep ^iff:.* "${NETDATA_HOST_PREFIX}/proc/${p}/fdinfo"/* 2>/dev/null | cut -f 2
+ grep "^iff:.*" "${NETDATA_HOST_PREFIX}/proc/${p}/fdinfo"/* 2>/dev/null | cut -f 2
}
find_tun_tap_interfaces_for_cgroup() {
@@ -128,7 +130,7 @@ find_tun_tap_interfaces_for_cgroup() {
local p
for p in $(< "${c}/emulator/cgroup.procs" )
do
- proc_pid_fdinfo_iff ${p}
+ proc_pid_fdinfo_iff "${p}"
done
fi
}
@@ -154,11 +156,14 @@ virsh_find_all_interfaces_for_cgroup() {
local c="${1}" # the cgroup path
# the virsh command
- local virsh="$(which virsh 2>/dev/null || command -v virsh 2>/dev/null)"
+ local virsh
+ # shellcheck disable=SC2230
+ virsh="$(which virsh 2>/dev/null || command -v virsh 2>/dev/null)"
if [ ! -z "${virsh}" ]
then
- local d="$(virsh_cgroup_to_domain_name "${c}")"
+ local d
+ d="$(virsh_cgroup_to_domain_name "${c}")"
if [ ! -z "${d}" ]
then
@@ -167,7 +172,7 @@ virsh_find_all_interfaces_for_cgroup() {
# match only 'network' interfaces from virsh output
set_source "virsh"
- "${virsh}" -r domiflist ${d} |\
+ "${virsh}" -r domiflist "${d}" |\
sed -n \
-e "s|^\([^[:space:]]\+\)[[:space:]]\+network[[:space:]]\+\([^[:space:]]\+\)[[:space:]]\+[^[:space:]]\+[[:space:]]\+[^[:space:]]\+$|\1 \1_\2|p" \
-e "s|^\([^[:space:]]\+\)[[:space:]]\+bridge[[:space:]]\+\([^[:space:]]\+\)[[:space:]]\+[^[:space:]]\+[[:space:]]\+[^[:space:]]\+$|\1 \1_\2|p"
@@ -188,7 +193,7 @@ find_all_interfaces_of_pid_or_cgroup() {
then
# we have been called with a pid
- proc_pid_fdinfo_iff ${p}
+ proc_pid_fdinfo_iff "${p}"
elif [ ! -z "${c}" ]
then
@@ -219,6 +224,7 @@ declare -A devs=()
# store all interfaces found in the associative array
# this will also give the unique devices, as seen by the host
last_src=
+# shellcheck disable=SC2162
while read host_device guest_device
do
[ -z "${host_device}" ] && continue
@@ -231,8 +237,9 @@ do
# when we run in debug, show the source
debug "Found host device '${host_device}', guest device '${guest_device}', detected via '${last_src}'"
- [ -z "${devs[${host_device}]}" -o "${devs[${host_device}]}" = "${host_device}" ] && \
+ if [ -z "${devs[${host_device}]}" ] || [ "${devs[${host_device}]}" = "${host_device}" ]; then
devs[${host_device}]="${guest_device}"
+ fi
done < <( find_all_interfaces_of_pid_or_cgroup "${pid}" "${cgroup}" )
diff --git a/src/cgroup-network.c b/collectors/cgroups.plugin/cgroup-network.c
index 0e2d5163a..0cf2a2633 100644
--- a/src/cgroup-network.c
+++ b/collectors/cgroups.plugin/cgroup-network.c
@@ -1,5 +1,6 @@
-#include "common.h"
-#include <libgen.h>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "libnetdata/libnetdata.h"
#ifdef HAVE_SETNS
#ifndef _GNU_SOURCE
@@ -8,8 +9,6 @@
#include <sched.h>
#endif
-char *host_prefix = "";
-
char environment_variable2[FILENAME_MAX + 50] = "";
char *environment[] = {
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin",
@@ -19,14 +18,28 @@ char *environment[] = {
// ----------------------------------------------------------------------------
-// callback required by fatal()
+// callback required by fatal()
void netdata_cleanup_and_exit(int ret) {
exit(ret);
}
-void health_reload(void) {};
-void rrdhost_save_all(void) {};
+// callbacks required by popen()
+void signals_block(void) {};
+void signals_unblock(void) {};
+void signals_reset(void) {};
+
+// callback required by eval()
+int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, calculated_number *result) {
+ (void)variable;
+ (void)hash;
+ (void)rc;
+ (void)result;
+ return 0;
+};
+
+// required by get_system_cpus()
+char *netdata_configured_host_prefix = "";
// ----------------------------------------------------------------------------
@@ -41,8 +54,10 @@ struct iface {
};
unsigned int read_iface_iflink(const char *prefix, const char *iface) {
+ if(!prefix) prefix = "";
+
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/iflink", prefix?prefix:"", iface);
+ snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/iflink", prefix, iface);
unsigned long long iflink = 0;
int ret = read_single_number_file(filename, &iflink);
@@ -52,8 +67,10 @@ unsigned int read_iface_iflink(const char *prefix, const char *iface) {
}
unsigned int read_iface_ifindex(const char *prefix, const char *iface) {
+ if(!prefix) prefix = "";
+
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/ifindex", prefix?prefix:"", iface);
+ snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/ifindex", prefix, iface);
unsigned long long ifindex = 0;
int ret = read_single_number_file(filename, &ifindex);
@@ -63,10 +80,12 @@ unsigned int read_iface_ifindex(const char *prefix, const char *iface) {
}
struct iface *read_proc_net_dev(const char *prefix) {
+ if(!prefix) prefix = "";
+
procfile *ff = NULL;
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", prefix?prefix:"", "/proc/net/dev");
+ snprintfz(filename, FILENAME_MAX, "%s%s", prefix, (*prefix)?"/proc/1/net/dev":"/proc/net/dev");
ff = procfile_open(filename, " \t,:|", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
error("Cannot open file '%s'", filename);
@@ -163,12 +182,14 @@ static void continue_as_child(void) {
}
int proc_pid_fd(const char *prefix, const char *ns, pid_t pid) {
+ if(!prefix) prefix = "";
+
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/%d/%s", prefix?prefix:"", (int)pid, ns);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/%s", prefix, (int)pid, ns);
int fd = open(filename, O_RDONLY);
if(fd == -1)
- error("Cannot open file '%s'", filename);
+ error("Cannot open proc_pid_fd() file '%s'", filename);
return fd;
}
@@ -193,6 +214,8 @@ static struct ns {
};
int switch_namespace(const char *prefix, pid_t pid) {
+ if(!prefix) prefix = "";
+
#ifdef HAVE_SETNS
int i;
@@ -207,8 +230,8 @@ int switch_namespace(const char *prefix, pid_t pid) {
// 2 passes - found it at nsenter source code
// this is related CLONE_NEWUSER functionality
- // FIXME: this code cannot switch user namespace
- // Fortunately, we don't need it.
+ // This code cannot switch user namespace (it can all the other namespaces)
+ // Fortunately, we don't need to switch user namespaces.
int pass, errors = 0;
for(pass = 0; pass < 2 ;pass++) {
@@ -272,9 +295,15 @@ int switch_namespace(const char *prefix, pid_t pid) {
}
pid_t read_pid_from_cgroup_file(const char *filename) {
- FILE *fp = fopen(filename, "r");
+ int fd = open(filename, procfile_open_flags);
+ if(fd == -1) {
+ error("Cannot open pid_from_cgroup() file '%s'.", filename);
+ return 0;
+ }
+
+ FILE *fp = fdopen(fd, "r");
if(!fp) {
- error("Cannot read file '%s'.", filename);
+ error("Cannot upgrade fd to fp for file '%s'.", filename);
return 0;
}
@@ -387,14 +416,13 @@ int send_devices(void) {
// since it switches namespaces, so after this call, everything is different!
void detect_veth_interfaces(pid_t pid) {
- struct iface *host, *cgroup, *h, *c;
- const char *prefix = getenv("NETDATA_HOST_PREFIX");
+ struct iface *host = NULL, *cgroup = NULL, *h, *c;
- host = read_proc_net_dev(prefix);
+ host = read_proc_net_dev(netdata_configured_host_prefix);
if(!host) {
errno = 0;
error("cannot read host interface list.");
- return;
+ goto cleanup;
}
if(!eligible_ifaces(host)) {
@@ -403,7 +431,7 @@ void detect_veth_interfaces(pid_t pid) {
goto cleanup;
}
- if(switch_namespace(prefix, pid)) {
+ if(switch_namespace(netdata_configured_host_prefix, pid)) {
errno = 0;
error("cannot switch to the namespace of pid %u", (unsigned int) pid);
goto cleanup;
@@ -433,6 +461,7 @@ void detect_veth_interfaces(pid_t pid) {
}
cleanup:
+ free_host_ifaces(cgroup);
free_host_ifaces(host);
}
@@ -444,17 +473,18 @@ void call_the_helper(pid_t pid, const char *cgroup) {
if(setresuid(0, 0, 0) == -1)
error("setresuid(0, 0, 0) failed.");
- char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
+ char command[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
if(cgroup)
- snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --cgroup '%s'", cgroup);
+ snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --cgroup '%s'", cgroup);
else
- snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --pid %d", pid);
+ snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --pid %d", pid);
- info("running: %s", buffer);
+ info("running: %s", command);
pid_t cgroup_pid;
- FILE *fp = mypopene(buffer, &cgroup_pid, environment);
+ FILE *fp = mypopene(command, &cgroup_pid, environment);
if(fp) {
+ char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
char *s;
while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) {
trim(s);
@@ -475,7 +505,7 @@ void call_the_helper(pid_t pid, const char *cgroup) {
mypclose(fp, cgroup_pid);
}
else
- error("cannot execute cgroup-network helper script: %s", buffer);
+ error("cannot execute cgroup-network helper script: %s", command);
}
int is_valid_path_symbol(char c) {
@@ -588,22 +618,23 @@ int main(int argc, char **argv) {
program_version = VERSION;
error_log_syslog = 0;
+ // since cgroup-network runs as root, prevent it from opening symbolic links
+ procfile_open_flags = O_RDONLY|O_NOFOLLOW;
// ------------------------------------------------------------------------
// make sure NETDATA_HOST_PREFIX is safe
- host_prefix = getenv("NETDATA_HOST_PREFIX");
- if(!host_prefix || !*host_prefix)
- host_prefix = "";
+ netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
+ if(verify_netdata_host_prefix() == -1) exit(1);
- if(host_prefix[0] != '\0' && verify_path(host_prefix) == -1)
- fatal("invalid NETDATA_HOST_PREFIX '%s'", host_prefix);
+ if(netdata_configured_host_prefix[0] != '\0' && verify_path(netdata_configured_host_prefix) == -1)
+ fatal("invalid NETDATA_HOST_PREFIX '%s'", netdata_configured_host_prefix);
// ------------------------------------------------------------------------
// build a safe environment for our script
// the first environment variable is a fixed PATH=
- snprintfz(environment_variable2, sizeof(environment_variable2) - 1, "NETDATA_HOST_PREFIX=%s", host_prefix);
+ snprintfz(environment_variable2, sizeof(environment_variable2) - 1, "NETDATA_HOST_PREFIX=%s", netdata_configured_host_prefix);
// ------------------------------------------------------------------------
diff --git a/src/sys_fs_cgroup.c b/collectors/cgroups.plugin/sys_fs_cgroup.c
index f6e613c4b..9c0fd7f43 100644
--- a/src/sys_fs_cgroup.c
+++ b/collectors/cgroups.plugin/sys_fs_cgroup.c
@@ -1,11 +1,14 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "sys_fs_cgroup.h"
+
+#define PLUGIN_CGROUPS_NAME "cgroups.plugin"
+#define PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME "systemd"
+#define PLUGIN_CGROUPS_MODULE_CGROUPS_NAME "/sys/fs/cgroup"
// ----------------------------------------------------------------------------
// cgroup globals
-#define CHART_PRIORITY_SYSTEMD_SERVICES 19000
-#define CHART_PRIORITY_CONTAINERS 40000
-
static long system_page_size = 4096; // system will be queried via sysconf() in configuration()
static int cgroup_enable_cpuacct_stat = CONFIG_BOOLEAN_AUTO;
@@ -71,7 +74,7 @@ void read_cgroup_plugin_configuration() {
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);
+ cgroup_check_for_new_every = (int)config_get_number("plugin:cgroups", "check for new cgroups every", (long long)cgroup_check_for_new_every * (long long)cgroup_update_every);
if(cgroup_check_for_new_every < cgroup_update_every)
cgroup_check_for_new_every = cgroup_update_every;
@@ -751,53 +754,55 @@ static inline void read_cgroup_network_interfaces(struct cgroup *cg) {
debug(D_CGROUP, "looking for the network interfaces of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title);
pid_t cgroup_pid;
- char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
+ char command[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
- snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s --cgroup '%s%s'", cgroups_network_interface_script, cgroup_cpuacct_base, cg->id);
+ snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s --cgroup '%s%s'", cgroups_network_interface_script, cgroup_cpuacct_base, cg->id);
- debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
- FILE *fp = mypopen(buffer, &cgroup_pid);
- if(fp) {
- char *s;
- while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) {
- trim(s);
+ debug(D_CGROUP, "executing command '%s' for cgroup '%s'", command, cg->id);
+ FILE *fp = mypopen(command, &cgroup_pid);
+ if(!fp) {
+ error("CGROUP: cannot popen(\"%s\", \"r\").", command);
+ return;
+ }
- if(*s && *s != '\n') {
- char *t = s;
- while(*t && *t != ' ') t++;
- if(*t == ' ') {
- *t = '\0';
- t++;
- }
+ char *s;
+ char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
+ while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) {
+ trim(s);
+
+ if(*s && *s != '\n') {
+ char *t = s;
+ while(*t && *t != ' ') t++;
+ if(*t == ' ') {
+ *t = '\0';
+ t++;
+ }
- if(!*s) {
- error("CGROUP: empty host interface returned by script");
- continue;
- }
+ if(!*s) {
+ error("CGROUP: empty host interface returned by script");
+ continue;
+ }
- if(!*t) {
- error("CGROUP: empty guest interface returned by script");
- continue;
- }
+ if(!*t) {
+ error("CGROUP: empty guest interface returned by script");
+ continue;
+ }
- struct cgroup_network_interface *i = callocz(1, sizeof(struct cgroup_network_interface));
- i->host_device = strdupz(s);
- i->container_device = strdupz(t);
- i->next = cg->interfaces;
- cg->interfaces = i;
+ struct cgroup_network_interface *i = callocz(1, sizeof(struct cgroup_network_interface));
+ i->host_device = strdupz(s);
+ i->container_device = strdupz(t);
+ i->next = cg->interfaces;
+ cg->interfaces = i;
- info("CGROUP: cgroup '%s' has network interface '%s' as '%s'", cg->id, i->host_device, i->container_device);
+ info("CGROUP: cgroup '%s' has network interface '%s' as '%s'", cg->id, i->host_device, i->container_device);
- // register a device rename to proc_net_dev.c
- netdev_rename_device_add(i->host_device, i->container_device, cg->chart_id);
- }
+ // register a device rename to proc_net_dev.c
+ netdev_rename_device_add(i->host_device, i->container_device, cg->chart_id);
}
-
- mypclose(fp, cgroup_pid);
- // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
}
- else
- error("CGROUP: cannot popen(\"%s\", \"r\").", buffer);
+
+ mypclose(fp, cgroup_pid);
+ // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
}
static inline void free_cgroup_network_interfaces(struct cgroup *cg) {
@@ -845,14 +850,15 @@ static inline void cgroup_get_chart_name(struct cgroup *cg) {
debug(D_CGROUP, "looking for the name of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title);
pid_t cgroup_pid;
- char buffer[CGROUP_CHARTID_LINE_MAX + 1];
+ char command[CGROUP_CHARTID_LINE_MAX + 1];
- snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s' '%s'", cgroups_rename_script, cg->chart_id, cg->id);
+ snprintfz(command, CGROUP_CHARTID_LINE_MAX, "exec %s '%s' '%s'", cgroups_rename_script, cg->chart_id, cg->id);
- debug(D_CGROUP, "executing command \"%s\" for cgroup '%s'", buffer, cg->id);
- FILE *fp = mypopen(buffer, &cgroup_pid);
+ debug(D_CGROUP, "executing command \"%s\" for cgroup '%s'", command, cg->id);
+ FILE *fp = mypopen(command, &cgroup_pid);
if(fp) {
- // debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id);
+ // debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", command, cg->id);
+ char buffer[CGROUP_CHARTID_LINE_MAX + 1];
char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp);
// debug(D_CGROUP, "closing command for cgroup '%s'", cg->id);
mypclose(fp, cgroup_pid);
@@ -872,7 +878,7 @@ static inline void cgroup_get_chart_name(struct cgroup *cg) {
}
}
else
- error("CGROUP: cannot popen(\"%s\", \"r\").", buffer);
+ error("CGROUP: cannot popen(\"%s\", \"r\").", command);
}
static inline struct cgroup *cgroup_add(const char *id) {
@@ -1460,9 +1466,9 @@ void update_systemd_services_charts(
, "services.cpu"
, title
, "%"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1484,9 +1490,9 @@ void update_systemd_services_charts(
, (cgroup_used_memory_without_cache) ? "Systemd Services Used Memory without Cache"
: "Systemd Services Used Memory"
, "MB"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 10
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 10
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1507,9 +1513,9 @@ void update_systemd_services_charts(
, "services.mem_rss"
, "Systemd Services RSS Memory"
, "MB"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 20
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 20
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1528,9 +1534,9 @@ void update_systemd_services_charts(
, "services.mem_mapped"
, "Systemd Services Mapped Memory"
, "MB"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 30
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 30
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1549,9 +1555,9 @@ void update_systemd_services_charts(
, "services.mem_cache"
, "Systemd Services Cache Memory"
, "MB"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 40
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 40
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1570,9 +1576,9 @@ void update_systemd_services_charts(
, "services.mem_writeback"
, "Systemd Services Writeback Memory"
, "MB"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 50
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 50
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1591,9 +1597,9 @@ void update_systemd_services_charts(
, "services.mem_pgfault"
, "Systemd Services Memory Minor Page Faults"
, "MB/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 60
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 60
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1611,9 +1617,9 @@ void update_systemd_services_charts(
, "services.mem_pgmajfault"
, "Systemd Services Memory Major Page Faults"
, "MB/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 70
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 70
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1632,9 +1638,9 @@ void update_systemd_services_charts(
, "services.mem_pgpgin"
, "Systemd Services Memory Charging Activity"
, "MB/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 80
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 80
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1653,9 +1659,9 @@ void update_systemd_services_charts(
, "services.mem_pgpgout"
, "Systemd Services Memory Uncharging Activity"
, "MB/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 90
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 90
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1676,9 +1682,9 @@ void update_systemd_services_charts(
, "services.mem_failcnt"
, "Systemd Services Memory Limit Failures"
, "MB"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 110
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 110
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1699,9 +1705,9 @@ void update_systemd_services_charts(
, "services.swap_usage"
, "Systemd Services Swap Memory Used"
, "MB"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 100
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 100
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1722,9 +1728,9 @@ void update_systemd_services_charts(
, "services.io_read"
, "Systemd Services Disk Read Bandwidth"
, "KB/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 120
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 120
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1743,9 +1749,9 @@ void update_systemd_services_charts(
, "services.io_write"
, "Systemd Services Disk Write Bandwidth"
, "KB/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 130
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 130
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1766,9 +1772,9 @@ void update_systemd_services_charts(
, "services.io_ops_read"
, "Systemd Services Disk Read Operations"
, "operations/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 140
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 140
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1787,9 +1793,9 @@ void update_systemd_services_charts(
, "services.io_ops_write"
, "Systemd Services Disk Write Operations"
, "operations/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 150
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 150
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1810,9 +1816,9 @@ void update_systemd_services_charts(
, "services.throttle_io_read"
, "Systemd Services Throttle Disk Read Bandwidth"
, "KB/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 160
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 160
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1831,9 +1837,9 @@ void update_systemd_services_charts(
, "services.throttle_io_write"
, "Systemd Services Throttle Disk Write Bandwidth"
, "KB/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 170
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 170
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1854,9 +1860,9 @@ void update_systemd_services_charts(
, "services.throttle_io_ops_read"
, "Systemd Services Throttle Disk Read Operations"
, "operations/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 180
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 180
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1875,9 +1881,9 @@ void update_systemd_services_charts(
, "services.throttle_io_ops_write"
, "Systemd Services Throttle Disk Write Operations"
, "operations/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 190
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 190
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1898,9 +1904,9 @@ void update_systemd_services_charts(
, "services.queued_io_ops_read"
, "Systemd Services Queued Disk Read Operations"
, "operations/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 200
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 200
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1919,9 +1925,9 @@ void update_systemd_services_charts(
, "services.queued_io_ops_write"
, "Systemd Services Queued Disk Write Operations"
, "operations/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 210
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 210
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1942,9 +1948,9 @@ void update_systemd_services_charts(
, "services.merged_io_ops_read"
, "Systemd Services Merged Disk Read Operations"
, "operations/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 220
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 220
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1963,9 +1969,9 @@ void update_systemd_services_charts(
, "services.merged_io_ops_write"
, "Systemd Services Merged Disk Write Operations"
, "operations/s"
- , "cgroup"
- , "systemd"
- , CHART_PRIORITY_SYSTEMD_SERVICES + 230
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 230
, update_every
, RRDSET_TYPE_STACKED
);
@@ -1983,7 +1989,7 @@ void update_systemd_services_charts(
if(likely(do_cpu && cg->cpuacct_stat.updated)) {
if(unlikely(!cg->rd_cpu))
- cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, hz, RRD_ALGORITHM_INCREMENTAL);
+ cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_cpu, cg->rd_cpu, cg->cpuacct_stat.user + cg->cpuacct_stat.system);
}
@@ -2245,15 +2251,15 @@ void update_cgroup_charts(int update_every) {
, "cgroup.cpu"
, title
, "%"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_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);
+ rrddim_add(cg->st_cpu, "user", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_cpu, "system", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_cpu);
@@ -2278,9 +2284,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.cpu_per_core"
, title
, "%"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 100
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 100
, update_every
, RRDSET_TYPE_STACKED
);
@@ -2312,9 +2318,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.mem"
, title
, "MB"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 210
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 210
, update_every
, RRDSET_TYPE_STACKED
);
@@ -2332,7 +2338,7 @@ void update_cgroup_charts(int update_every) {
rrdset_next(cg->st_mem);
rrddim_set(cg->st_mem, "cache", cg->memory.cache);
- rrddim_set(cg->st_mem, "rss", cg->memory.rss);
+ rrddim_set(cg->st_mem, "rss", (cg->memory.rss > cg->memory.rss_huge)?(cg->memory.rss - cg->memory.rss_huge):0);
if(cg->memory.detailed_has_swap)
rrddim_set(cg->st_mem, "swap", cg->memory.swap);
@@ -2352,9 +2358,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.writeback"
, title
, "MB"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 300
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 300
, update_every
, RRDSET_TYPE_AREA
);
@@ -2384,9 +2390,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.mem_activity"
, title
, "MB/s"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 400
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 400
, update_every
, RRDSET_TYPE_LINE
);
@@ -2412,9 +2418,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.pgfaults"
, title
, "MB/s"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 500
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 500
, update_every
, RRDSET_TYPE_LINE
);
@@ -2442,9 +2448,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.mem_usage"
, title
, "MB"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 200
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 200
, update_every
, RRDSET_TYPE_STACKED
);
@@ -2472,9 +2478,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.mem_failcnt"
, title
, "count"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 250
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 250
, update_every
, RRDSET_TYPE_LINE
);
@@ -2500,9 +2506,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.io"
, title
, "KB/s"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 1200
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 1200
, update_every
, RRDSET_TYPE_AREA
);
@@ -2530,9 +2536,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.serviced_ops"
, title
, "operations/s"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 1200
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 1200
, update_every
, RRDSET_TYPE_LINE
);
@@ -2560,9 +2566,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.throttle_io"
, title
, "KB/s"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 1200
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 1200
, update_every
, RRDSET_TYPE_AREA
);
@@ -2590,9 +2596,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.throttle_serviced_ops"
, title
, "operations/s"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 1200
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 1200
, update_every
, RRDSET_TYPE_LINE
);
@@ -2620,9 +2626,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.queued_ops"
, title
, "operations"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 2000
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 2000
, update_every
, RRDSET_TYPE_LINE
);
@@ -2650,9 +2656,9 @@ void update_cgroup_charts(int update_every) {
, "cgroup.merged_ops"
, title
, "operations/s"
- , "cgroup"
- , "default"
- , CHART_PRIORITY_CONTAINERS + 2100
+ , PLUGIN_CGROUPS_NAME
+ , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
+ , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 2100
, update_every
, RRDSET_TYPE_LINE
);
@@ -2741,7 +2747,7 @@ void *cgroups_main(void *ptr) {
, NULL
, "NetData CGroups Plugin CPU usage"
, "milliseconds/s"
- , "cgroup"
+ , PLUGIN_CGROUPS_NAME
, "stats"
, 132000
, cgroup_update_every
diff --git a/collectors/cgroups.plugin/sys_fs_cgroup.h b/collectors/cgroups.plugin/sys_fs_cgroup.h
new file mode 100644
index 000000000..09ce5e3fb
--- /dev/null
+++ b/collectors/cgroups.plugin/sys_fs_cgroup.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_SYS_FS_CGROUP_H
+#define NETDATA_SYS_FS_CGROUP_H 1
+
+#include "../../daemon/common.h"
+
+#if (TARGET_OS == OS_LINUX)
+
+#define NETDATA_PLUGIN_HOOK_LINUX_CGROUPS \
+ { \
+ .name = "PLUGIN[cgroups]", \
+ .config_section = CONFIG_SECTION_PLUGINS, \
+ .config_name = "cgroups", \
+ .enabled = 1, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = cgroups_main \
+ },
+
+extern void *cgroups_main(void *ptr);
+
+#include "../proc.plugin/plugin_proc.h"
+
+#else // (TARGET_OS == OS_LINUX)
+
+#define NETDATA_PLUGIN_HOOK_LINUX_CGROUPS
+
+#endif // (TARGET_OS == OS_LINUX)
+
+#endif //NETDATA_SYS_FS_CGROUP_H
diff --git a/collectors/charts.d.plugin/Makefile.am b/collectors/charts.d.plugin/Makefile.am
new file mode 100644
index 000000000..e2e00258f
--- /dev/null
+++ b/collectors/charts.d.plugin/Makefile.am
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+CLEANFILES = \
+ charts.d.plugin \
+ $(NULL)
+
+include $(top_srcdir)/build/subst.inc
+SUFFIXES = .in
+
+dist_libconfig_DATA = \
+ charts.d.conf \
+ $(NULL)
+
+dist_plugins_SCRIPTS = \
+ charts.d.dryrun-helper.sh \
+ charts.d.plugin \
+ loopsleepms.sh.inc \
+ $(NULL)
+
+dist_noinst_DATA = \
+ charts.d.plugin.in \
+ README.md \
+ $(NULL)
+
+dist_charts_SCRIPTS = \
+ $(NULL)
+
+dist_charts_DATA = \
+ $(NULL)
+
+userchartsconfigdir=$(configdir)/charts.d
+dist_userchartsconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
+chartsconfigdir=$(libconfigdir)/charts.d
+dist_chartsconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
+include ap/Makefile.inc
+include apache/Makefile.inc
+include apcupsd/Makefile.inc
+include cpu_apps/Makefile.inc
+include cpufreq/Makefile.inc
+include example/Makefile.inc
+include exim/Makefile.inc
+include hddtemp/Makefile.inc
+include libreswan/Makefile.inc
+include load_average/Makefile.inc
+include mem_apps/Makefile.inc
+include mysql/Makefile.inc
+include nginx/Makefile.inc
+include nut/Makefile.inc
+include opensips/Makefile.inc
+include phpfpm/Makefile.inc
+include postfix/Makefile.inc
+include sensors/Makefile.inc
+include squid/Makefile.inc
+include tomcat/Makefile.inc
diff --git a/collectors/charts.d.plugin/Makefile.in b/collectors/charts.d.plugin/Makefile.in
new file mode 100644
index 000000000..23e2edebb
--- /dev/null
+++ b/collectors/charts.d.plugin/Makefile.in
@@ -0,0 +1,953 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(top_srcdir)/build/subst.inc $(srcdir)/ap/Makefile.inc \
+ $(srcdir)/apache/Makefile.inc $(srcdir)/apcupsd/Makefile.inc \
+ $(srcdir)/cpu_apps/Makefile.inc $(srcdir)/cpufreq/Makefile.inc \
+ $(srcdir)/example/Makefile.inc $(srcdir)/exim/Makefile.inc \
+ $(srcdir)/hddtemp/Makefile.inc \
+ $(srcdir)/libreswan/Makefile.inc \
+ $(srcdir)/load_average/Makefile.inc \
+ $(srcdir)/mem_apps/Makefile.inc $(srcdir)/mysql/Makefile.inc \
+ $(srcdir)/nginx/Makefile.inc $(srcdir)/nut/Makefile.inc \
+ $(srcdir)/opensips/Makefile.inc $(srcdir)/phpfpm/Makefile.inc \
+ $(srcdir)/postfix/Makefile.inc $(srcdir)/sensors/Makefile.inc \
+ $(srcdir)/squid/Makefile.inc $(srcdir)/tomcat/Makefile.inc \
+ $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(dist_charts_SCRIPTS) $(dist_plugins_SCRIPTS) \
+ $(dist_charts_DATA) $(dist_chartsconfig_DATA) \
+ $(dist_libconfig_DATA) $(dist_noinst_DATA) \
+ $(dist_userchartsconfig_DATA)
+subdir = collectors/charts.d.plugin
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(chartsdir)" "$(DESTDIR)$(pluginsdir)" \
+ "$(DESTDIR)$(chartsdir)" "$(DESTDIR)$(chartsconfigdir)" \
+ "$(DESTDIR)$(libconfigdir)" "$(DESTDIR)$(userchartsconfigdir)"
+SCRIPTS = $(dist_charts_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_charts_DATA) $(dist_chartsconfig_DATA) \
+ $(dist_libconfig_DATA) $(dist_noinst_DATA) \
+ $(dist_userchartsconfig_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+CLEANFILES = \
+ charts.d.plugin \
+ $(NULL)
+
+SUFFIXES = .in
+dist_libconfig_DATA = \
+ charts.d.conf \
+ $(NULL)
+
+dist_plugins_SCRIPTS = \
+ charts.d.dryrun-helper.sh \
+ charts.d.plugin \
+ loopsleepms.sh.inc \
+ $(NULL)
+
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA = charts.d.plugin.in README.md $(NULL) ap/README.md \
+ ap/Makefile.inc apache/README.md apache/Makefile.inc \
+ apcupsd/README.md apcupsd/Makefile.inc cpu_apps/README.md \
+ cpu_apps/Makefile.inc cpufreq/README.md cpufreq/Makefile.inc \
+ example/README.md example/Makefile.inc exim/README.md \
+ exim/Makefile.inc hddtemp/README.md hddtemp/Makefile.inc \
+ libreswan/README.md libreswan/Makefile.inc \
+ load_average/README.md load_average/Makefile.inc \
+ mem_apps/README.md mem_apps/Makefile.inc mysql/README.md \
+ mysql/Makefile.inc nginx/README.md nginx/Makefile.inc \
+ nut/README.md nut/Makefile.inc opensips/README.md \
+ opensips/Makefile.inc phpfpm/README.md phpfpm/Makefile.inc \
+ postfix/README.md postfix/Makefile.inc sensors/README.md \
+ sensors/Makefile.inc squid/README.md squid/Makefile.inc \
+ tomcat/README.md tomcat/Makefile.inc
+dist_charts_SCRIPTS = \
+ $(NULL)
+
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+dist_charts_DATA = $(NULL) ap/ap.chart.sh apache/apache.chart.sh \
+ apcupsd/apcupsd.chart.sh cpu_apps/cpu_apps.chart.sh \
+ cpufreq/cpufreq.chart.sh example/example.chart.sh \
+ exim/exim.chart.sh hddtemp/hddtemp.chart.sh \
+ libreswan/libreswan.chart.sh \
+ load_average/load_average.chart.sh mem_apps/mem_apps.chart.sh \
+ mysql/mysql.chart.sh nginx/nginx.chart.sh nut/nut.chart.sh \
+ opensips/opensips.chart.sh phpfpm/phpfpm.chart.sh \
+ postfix/postfix.chart.sh sensors/sensors.chart.sh \
+ squid/squid.chart.sh tomcat/tomcat.chart.sh
+userchartsconfigdir = $(configdir)/charts.d
+dist_userchartsconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
+chartsconfigdir = $(libconfigdir)/charts.d
+dist_chartsconfig_DATA = $(top_srcdir)/installer/.keep $(NULL) \
+ ap/ap.conf apache/apache.conf apcupsd/apcupsd.conf \
+ cpu_apps/cpu_apps.conf cpufreq/cpufreq.conf \
+ example/example.conf exim/exim.conf hddtemp/hddtemp.conf \
+ libreswan/libreswan.conf load_average/load_average.conf \
+ mem_apps/mem_apps.conf mysql/mysql.conf nginx/nginx.conf \
+ nut/nut.conf opensips/opensips.conf phpfpm/phpfpm.conf \
+ postfix/postfix.conf sensors/sensors.conf squid/squid.conf \
+ tomcat/tomcat.conf
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .in
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/build/subst.inc $(srcdir)/ap/Makefile.inc $(srcdir)/apache/Makefile.inc $(srcdir)/apcupsd/Makefile.inc $(srcdir)/cpu_apps/Makefile.inc $(srcdir)/cpufreq/Makefile.inc $(srcdir)/example/Makefile.inc $(srcdir)/exim/Makefile.inc $(srcdir)/hddtemp/Makefile.inc $(srcdir)/libreswan/Makefile.inc $(srcdir)/load_average/Makefile.inc $(srcdir)/mem_apps/Makefile.inc $(srcdir)/mysql/Makefile.inc $(srcdir)/nginx/Makefile.inc $(srcdir)/nut/Makefile.inc $(srcdir)/opensips/Makefile.inc $(srcdir)/phpfpm/Makefile.inc $(srcdir)/postfix/Makefile.inc $(srcdir)/sensors/Makefile.inc $(srcdir)/squid/Makefile.inc $(srcdir)/tomcat/Makefile.inc $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/charts.d.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/charts.d.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(top_srcdir)/build/subst.inc $(srcdir)/ap/Makefile.inc $(srcdir)/apache/Makefile.inc $(srcdir)/apcupsd/Makefile.inc $(srcdir)/cpu_apps/Makefile.inc $(srcdir)/cpufreq/Makefile.inc $(srcdir)/example/Makefile.inc $(srcdir)/exim/Makefile.inc $(srcdir)/hddtemp/Makefile.inc $(srcdir)/libreswan/Makefile.inc $(srcdir)/load_average/Makefile.inc $(srcdir)/mem_apps/Makefile.inc $(srcdir)/mysql/Makefile.inc $(srcdir)/nginx/Makefile.inc $(srcdir)/nut/Makefile.inc $(srcdir)/opensips/Makefile.inc $(srcdir)/phpfpm/Makefile.inc $(srcdir)/postfix/Makefile.inc $(srcdir)/sensors/Makefile.inc $(srcdir)/squid/Makefile.inc $(srcdir)/tomcat/Makefile.inc:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-dist_chartsSCRIPTS: $(dist_charts_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @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; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(chartsdir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(chartsdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dist_chartsSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_charts_SCRIPTS)'; test -n "$(chartsdir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(chartsdir)'; $(am__uninstall_files_from_dir)
+install-dist_pluginsSCRIPTS: $(dist_plugins_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @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; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pluginsdir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pluginsdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dist_pluginsSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_plugins_SCRIPTS)'; test -n "$(pluginsdir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(pluginsdir)'; $(am__uninstall_files_from_dir)
+install-dist_chartsDATA: $(dist_charts_DATA)
+ @$(NORMAL_INSTALL)
+ @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"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(chartsdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(chartsdir)" || exit $$?; \
+ done
+
+uninstall-dist_chartsDATA:
+ @$(NORMAL_UNINSTALL)
+ @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)
+install-dist_chartsconfigDATA: $(dist_chartsconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @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"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(chartsconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(chartsconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_chartsconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_chartsconfig_DATA)'; test -n "$(chartsconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(chartsconfigdir)'; $(am__uninstall_files_from_dir)
+install-dist_libconfigDATA: $(dist_libconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_libconfig_DATA)'; test -n "$(libconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(libconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(libconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_libconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_libconfig_DATA)'; test -n "$(libconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(libconfigdir)'; $(am__uninstall_files_from_dir)
+install-dist_userchartsconfigDATA: $(dist_userchartsconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_userchartsconfig_DATA)'; test -n "$(userchartsconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(userchartsconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(userchartsconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(userchartsconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(userchartsconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_userchartsconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_userchartsconfig_DATA)'; test -n "$(userchartsconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(userchartsconfigdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(chartsdir)" "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(chartsdir)" "$(DESTDIR)$(chartsconfigdir)" "$(DESTDIR)$(libconfigdir)" "$(DESTDIR)$(userchartsconfigdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_chartsDATA install-dist_chartsSCRIPTS \
+ install-dist_chartsconfigDATA install-dist_libconfigDATA \
+ install-dist_pluginsSCRIPTS install-dist_userchartsconfigDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_chartsDATA uninstall-dist_chartsSCRIPTS \
+ uninstall-dist_chartsconfigDATA uninstall-dist_libconfigDATA \
+ uninstall-dist_pluginsSCRIPTS \
+ uninstall-dist_userchartsconfigDATA
+
+.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-dist_chartsconfigDATA \
+ install-dist_libconfigDATA install-dist_pluginsSCRIPTS \
+ install-dist_userchartsconfigDATA 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_chartsDATA uninstall-dist_chartsSCRIPTS \
+ uninstall-dist_chartsconfigDATA uninstall-dist_libconfigDATA \
+ uninstall-dist_pluginsSCRIPTS \
+ uninstall-dist_userchartsconfigDATA
+
+.in:
+ if sed \
+ -e 's#[@]localstatedir_POST@#$(localstatedir)#g' \
+ -e 's#[@]sbindir_POST@#$(sbindir)#g' \
+ -e 's#[@]sysconfdir_POST@#$(sysconfdir)#g' \
+ -e 's#[@]pythondir_POST@#$(pythondir)#g' \
+ -e 's#[@]configdir_POST@#$(configdir)#g' \
+ -e 's#[@]libconfigdir_POST@#$(libconfigdir)#g' \
+ -e 's#[@]cachedir_POST@#$(cachedir)#g' \
+ $< > $@.tmp; then \
+ mv "$@.tmp" "$@"; \
+ else \
+ rm -f "$@.tmp"; \
+ false; \
+ 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.
+.NOEXPORT:
diff --git a/collectors/charts.d.plugin/README.md b/collectors/charts.d.plugin/README.md
new file mode 100644
index 000000000..b224bffe3
--- /dev/null
+++ b/collectors/charts.d.plugin/README.md
@@ -0,0 +1,193 @@
+# charts.d.plugin
+
+`charts.d.plugin` is a netdata external plugin. It is an **orchestrator** for data collection modules written in `BASH` v4+.
+
+1. It runs as an independent process `ps fax` shows it
+2. It is started and stopped automatically by netdata
+3. It communicates with netdata via a unidirectional pipe (sending data to the netdata daemon)
+4. Supports any number of data collection **modules**
+
+`charts.d.plugin` has been designed so that the actual script that will do data collection will be permanently in
+memory, collecting data with as little overheads as possible
+(i.e. initialize once, repeatedly collect values with minimal overhead).
+
+`charts.d.plugin` looks for scripts in `/usr/lib/netdata/charts.d`.
+The scripts should have the filename suffix: `.chart.sh`.
+
+## Configuration
+
+`charts.d.plugin` itself can be configured using the configuration file `/etc/netdata/charts.d.conf`
+(to edit it on your system run `/etc/netdata/edit-config charts.d.conf`). This file is also a BASH script.
+
+In this file, you can place statements like this:
+
+```
+enable_all_charts="yes"
+X="yes"
+Y="no"
+```
+
+where `X` and `Y` are the names of individual charts.d collector scripts.
+When set to `yes`, charts.d will evaluate the collector script (see below).
+When set to `no`, charts.d will ignore the collector script.
+
+The variable `enable_all_charts` sets the default enable/disable state for all charts.
+
+## A charts.d module
+
+A `charts.d.plugin` module is a BASH script defining a few functions.
+
+For a module called `X`, the following criteria must be met:
+
+1. The module script must be called `X.chart.sh` and placed in `/usr/libexec/netdata/charts.d`.
+
+2. If the module needs a configuration, it should be called `X.conf` and placed in `/etc/netdata/charts.d`.
+ The configuration file `X.conf` is also a BASH script itself.
+ To edit the default files supplied by netdata run `/etc/netdata/edit-config charts.d/X.conf`,
+ where `X` is the name of the module.
+
+3. All functions and global variables defined in the script and its configuration, must begin with `X_`.
+
+4. The following functions must be defined:
+
+ - `X_check()` - returns 0 or 1 depending on whether the module is able to run or not
+ (following the standard Linux command line return codes: 0 = OK, the collector can operate and 1 = FAILED,
+ the collector cannot be used).
+
+ - `X_create()` - creates the netdata charts, following the standard netdata plugin guides as described in
+ **[External Plugins](../plugins.d/)** (commands `CHART` and `DIMENSION`).
+ The return value does matter: 0 = OK, 1 = FAILED.
+
+ - `X_update()` - collects the values for the defined charts, following the standard netdata plugin guides
+ as described in **[External Plugins](../plugins.d/)** (commands `BEGIN`, `SET`, `END`).
+ The return value also matters: 0 = OK, 1 = FAILED.
+
+5. The following global variables are available to be set:
+ - `X_update_every` - is the data collection frequency for the module script, in seconds.
+
+The module script may use more functions or variables. But all of them must begin with `X_`.
+
+The standard netdata plugin variables are also available (check **[External Plugins](../plugins.d/)**).
+
+### X_check()
+
+The purpose of the BASH function `X_check()` is to check if the module can collect data (or check its config).
+
+For example, if the module is about monitoring a local mysql database, the `X_check()` function may attempt to
+connect to a local mysql database to find out if it can read the values it needs.
+
+`X_check()` is run only once for the lifetime of the module.
+
+### X_create()
+
+The purpose of the BASH function `X_create()` is to create the charts and dimensions using the standard netdata
+plugin guides (**[External Plugins](../plugins.d/)**).
+
+`X_create()` will be called just once and only after `X_check()` was successful.
+You can however call it yourself when there is need for it (for example to add a new dimension to an existing chart).
+
+A non-zero return value will disable the collector.
+
+### X_update()
+
+`X_update()` will be called repeatedly every `X_update_every` seconds, to collect new values and send them to netdata,
+following the netdata plugin guides (**[External Plugins](../plugins.d/)**).
+
+The function will be called with one parameter: microseconds since the last time it was run. This value should be
+appended to the `BEGIN` statement of every chart updated by the collector script.
+
+A non-zero return value will disable the collector.
+
+### Useful functions charts.d provides
+
+Module scripts can use the following charts.d functions:
+
+#### require_cmd command
+
+`require_cmd()` will check if a command is available in the running system.
+
+For example, your `X_check()` function may use it like this:
+
+```sh
+mysql_check() {
+ require_cmd mysql || return 1
+ return 0
+}
+```
+
+Using the above, if the command `mysql` is not available in the system, the `mysql` module will be disabled.
+
+#### fixid "string"
+
+`fixid()` will get a string and return a properly formatted id for a chart or dimension.
+
+This is an expensive function that should not be used in `X_update()`.
+You can keep the generated id in a BASH associative array to have the values availables in `X_update()`, like this:
+
+```sh
+declare -A X_ids=()
+X_create() {
+ local name="a very bad name for id"
+
+ X_ids[$name]="$(fixid "$name")"
+}
+
+X_update() {
+ local microseconds="$1"
+
+ ...
+ local name="a very bad name for id"
+ ...
+
+ echo "BEGIN ${X_ids[$name]} $microseconds"
+ ...
+}
+```
+
+### Debugging your collectors
+
+You can run `charts.d.plugin` by hand with something like this:
+
+```sh
+# become user netdata
+sudo su -s /bin/sh netdata
+
+# run the plugin in debug mode
+/usr/libexec/netdata/plugins.d/charts.d.plugin debug 1 X Y Z
+```
+
+Charts.d will run in `debug` mode, with an update frequency of `1`, evaluating only the collector scripts
+`X`, `Y` and `Z`. You can define zero or more module scripts. If none is defined, charts.d will evaluate all
+module scripts available.
+
+Keep in mind that if your configs are not in `/etc/netdata`, you should do the following before running
+`charts.d.plugin`:
+
+```sh
+export NETDATA_USER_CONFIG_DIR="/path/to/etc/netdata"
+```
+
+Also, remember that netdata runs `chart.d.plugin` as user `netdata` (or any other user netdata is configured to run as).
+
+
+## Running multiple instances of charts.d.plugin
+
+`charts.d.plugin` will call the `X_update()` function one after another. This means that a delay in collector `X`
+will also delay the collection of `Y` and `Z`.
+
+You can have multiple `charts.d.plugin` running to overcome this problem.
+
+This is what you need to do:
+
+1. Decide a new name for the new charts.d instance: example `charts2.d`.
+
+2. Create/edit the files `/etc/netdata/charts.d.conf` and `/etc/netdata/charts2.d.conf` and enable / disable the
+ module you want each to run. Remember to set `enable_all_charts="no"` to both of them, and enable the individual
+ modules for each.
+
+3. link `/usr/libexec/netdata/plugins.d/charts.d.plugin` to `/usr/libexec/netdata/plugins.d/charts2.d.plugin`.
+ Netdata will spawn a new charts.d process.
+
+Execute the above in this order, since netdata will (by default) attempt to start new plugins soon after they are
+created in `/usr/libexec/netdata/plugins.d/`.
+
diff --git a/collectors/charts.d.plugin/ap/Makefile.inc b/collectors/charts.d.plugin/ap/Makefile.inc
new file mode 100644
index 000000000..a2dd375ac
--- /dev/null
+++ b/collectors/charts.d.plugin/ap/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += ap/ap.chart.sh
+dist_chartsconfig_DATA += ap/ap.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += ap/README.md ap/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/ap/README.md b/collectors/charts.d.plugin/ap/README.md
new file mode 100644
index 000000000..eb4e80707
--- /dev/null
+++ b/collectors/charts.d.plugin/ap/README.md
@@ -0,0 +1,84 @@
+# Access Point Plugin (ap)
+
+The `ap` collector visualizes data related to access points.
+
+## Example netdata charts
+
+![image](https://cloud.githubusercontent.com/assets/2662304/12377654/9f566e88-bd2d-11e5-855a-e0ba96b8fd98.png)
+
+## How it works
+
+It does the following:
+
+1. Runs `iw dev` searching for interfaces that have `type AP`.
+
+ From the same output it collects the SSIDs each AP supports by looking for lines `ssid NAME`.
+
+ Example:
+```sh
+# iw dev
+phy#0
+ Interface wlan0
+ ifindex 3
+ wdev 0x1
+ addr 7c:dd:90:77:34:2a
+ ssid TSAOUSIS
+ type AP
+ channel 7 (2442 MHz), width: 20 MHz, center1: 2442 MHz
+```
+
+
+2. For each interface found, it runs `iw INTERFACE station dump`.
+
+ From the output is collects:
+
+ - rx/tx bytes
+ - rx/tx packets
+ - tx retries
+ - tx failed
+ - signal strength
+ - rx/tx bitrate
+ - expected throughput
+
+ Example:
+
+```sh
+# iw wlan0 station dump
+Station 40:b8:37:5a:ed:5e (on wlan0)
+ inactive time: 910 ms
+ rx bytes: 15588897
+ rx packets: 127772
+ tx bytes: 52257763
+ tx packets: 95802
+ tx retries: 2162
+ tx failed: 28
+ signal: -43 dBm
+ signal avg: -43 dBm
+ tx bitrate: 65.0 MBit/s MCS 7
+ rx bitrate: 1.0 MBit/s
+ expected throughput: 32.125Mbps
+ authorized: yes
+ authenticated: yes
+ preamble: long
+ WMM/WME: yes
+ MFP: no
+ TDLS peer: no
+```
+
+3. For each interface found, it creates 6 charts:
+
+ - Number of Connected clients
+ - Bandwidth for all clients
+ - Packets for all clients
+ - Transmit Issues for all clients
+ - Average Signal among all clients
+ - Average Bitrate (including average expected throughput) among all clients
+
+## Configuration
+
+You can only set `ap_update_every=NUMBER` to `/etc/netdata/charts.d/ap.conf`, to give the data collection frequency.
+To edit this file on your system run `/etc/netdata/edit-config charts.d/ap.conf`.
+
+## Auto-detection
+
+The plugin is able to auto-detect if you are running access points on your linux box.
diff --git a/charts.d/ap.chart.sh b/collectors/charts.d.plugin/ap/ap.chart.sh
index ce2eefc9f..ccc36120c 100644
--- a/charts.d/ap.chart.sh
+++ b/collectors/charts.d.plugin/ap/ap.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# _update_every is a special variable - it holds the number of seconds
@@ -16,8 +17,8 @@ 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 '
+ local ev
+ ev=$(run iw dev | awk '
BEGIN {
i = "";
ssid = "";
@@ -102,7 +103,7 @@ ap_update() {
do
echo
echo "DEVICE ${dev}"
- iw ${dev} station dump
+ iw "${dev}" station dump
done | awk "
function zero_data() {
dev = \"\";
diff --git a/conf.d/charts.d/ap.conf b/collectors/charts.d.plugin/ap/ap.conf
index 38fc157ce..38fc157ce 100644
--- a/conf.d/charts.d/ap.conf
+++ b/collectors/charts.d.plugin/ap/ap.conf
diff --git a/collectors/charts.d.plugin/apache/Makefile.inc b/collectors/charts.d.plugin/apache/Makefile.inc
new file mode 100644
index 000000000..4b360eae0
--- /dev/null
+++ b/collectors/charts.d.plugin/apache/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += apache/apache.chart.sh
+dist_chartsconfig_DATA += apache/apache.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += apache/README.md apache/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/apache/README.md b/collectors/charts.d.plugin/apache/README.md
new file mode 100644
index 000000000..890cee984
--- /dev/null
+++ b/collectors/charts.d.plugin/apache/README.md
@@ -0,0 +1,127 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
+
+---
+
+# Apache Plugin (apache)
+
+The `apache` collector visualizes key performance data for an apache web server.
+
+## Example netdata charts
+
+For apache 2.2:
+
+![image](https://cloud.githubusercontent.com/assets/2662304/12530273/421c4d14-c1e2-11e5-9fb6-ca6d6dd3b1dd.png)
+
+For apache 2.4:
+
+![image](https://cloud.githubusercontent.com/assets/2662304/12530376/29ec26de-c1e6-11e5-9af1-e48aaf781795.png)
+
+## How it works
+
+It runs `curl "http://apache.host/server-status?auto` to fetch the current status of apache.
+
+It has been tested with apache 2.2 and apache 2.4. The latter also provides connections information (total and break down by status).
+
+Apache 2.2 response:
+
+```sh
+$ curl "http://127.0.0.1/server-status?auto"
+Total Accesses: 80057
+Total kBytes: 223017
+CPULoad: .018287
+Uptime: 64472
+ReqPerSec: 1.24173
+BytesPerSec: 3542.15
+BytesPerReq: 2852.59
+BusyWorkers: 1
+IdleWorkers: 49
+Scoreboard: _________________________......................................._W_______________________.......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
+```
+
+Apache 2.4 response:
+
+```sh
+$ curl "http://127.0.0.1/server-status?auto"
+127.0.0.1
+ServerVersion: Apache/2.4.18 (Unix)
+ServerMPM: event
+Server Built: Dec 14 2015 08:05:54
+CurrentTime: Saturday, 23-Jan-2016 14:42:06 EET
+RestartTime: Saturday, 23-Jan-2016 04:57:13 EET
+ParentServerConfigGeneration: 2
+ParentServerMPMGeneration: 1
+ServerUptimeSeconds: 35092
+ServerUptime: 9 hours 44 minutes 52 seconds
+Load1: 0.32
+Load5: 0.32
+Load15: 0.27
+Total Accesses: 32403
+Total kBytes: 34464
+CPUUser: 30.37
+CPUSystem: 29.55
+CPUChildrenUser: 0
+CPUChildrenSystem: 0
+CPULoad: .170751
+Uptime: 35092
+ReqPerSec: .923373
+BytesPerSec: 1005.67
+BytesPerReq: 1089.13
+BusyWorkers: 1
+IdleWorkers: 99
+ConnsTotal: 0
+ConnsAsyncWriting: 0
+ConnsAsyncKeepAlive: 0
+ConnsAsyncClosing: 0
+Scoreboard: __________________________________________________________________________________________W_________............................................................................................................................................................................................................................................................................................................
+```
+
+From the apache status output it collects:
+
+ - total accesses (incremental value, rendered as requests/s)
+ - total bandwidth (incremental value, rendered as bandwidth/s)
+ - requests per second (this appears to be calculated by apache as an average for its lifetime, while the one calculated by netdata using the total accesses counter is real-time)
+ - bytes per second (average for the lifetime of the apache server)
+ - bytes per request (average for the lifetime of the apache server)
+ - workers by status (`busy` and `idle`)
+ - total connections (currently active connections - offered by apache 2.4+)
+ - async connections per status (`keepalive`, `writing`, `closing` - offered by apache 2.4+)
+
+## Configuration
+
+The configuration is stored in `/etc/netdata/charts.d/apache.conf`.
+To edit this file on your system run `/etc/netdata/edit-config charts.d/apache.conf`.
+
+The internal default is:
+
+```sh
+# the URL your apache server is responding with mod_status information.
+apache_url="http://127.0.0.1:80/server-status?auto"
+
+# use this to set custom curl options you may need
+apache_curl_opts=
+
+# set this to a NUMBER to overwrite the update frequency
+# it is in seconds
+apache_update_every=
+```
+
+The default `apache_update_every` is configured in netdata.
+
+## Auto-detection
+
+If you have configured your apache server to offer server-status information on localhost clients, the defaults should work fine.
+
+## Apache Configuration
+
+Apache configuration differs between distributions. Please check your distribution's documentation for information on enabling apache's `mod_status` module.
+
+If you are able to run successfully, by hand this command:
+
+```sh
+curl "http://127.0.0.1:80/server-status?auto"
+```
+
+netdata will be able to do it too.
+
+Notice: You may need to have the default `000-default.conf ` website enabled in order for the status mod to work.
diff --git a/charts.d/apache.chart.sh b/collectors/charts.d.plugin/apache/apache.chart.sh
index a8ac08014..95876432f 100644
--- a/charts.d/apache.chart.sh
+++ b/collectors/charts.d.plugin/apache/apache.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# the URL to download apache status info
@@ -82,12 +83,11 @@ apache_detect() {
[ -z "${apache_key_idleworkers}" ] && error "missing 'IdleWorkers' from apache server: ${*}" && return 1
[ -z "${apache_key_scoreboard}" ] && error "missing 'Scoreboard' from apache server: ${*}" && return 1
- if [ ! -z "${apache_key_connstotal}" \
- -a ! -z "${apache_key_connsasyncwriting}" \
- -a ! -z "${apache_key_connsasynckeepalive}" \
- -a ! -z "${apache_key_connsasyncclosing}" \
- ]
- then
+ if [ ! -z "${apache_key_connstotal}" ] && \
+ [ ! -z "${apache_key_connsasyncwriting}" ] && \
+ [ ! -z "${apache_key_connsasynckeepalive}" ] && \
+ [ ! -z "${apache_key_connsasyncclosing}" ]
+ then
apache_has_conns=1
else
apache_has_conns=0
@@ -98,16 +98,20 @@ apache_detect() {
apache_get() {
local oIFS="${IFS}" ret
+ # shellcheck disable=2207
IFS=$':\n' apache_response=($(run curl -Ss ${apache_curl_opts} "${apache_url}"))
ret=$?
IFS="${oIFS}"
- [ $ret -ne 0 -o "${#apache_response[@]}" -eq 0 ] && return 1
+ if [ $ret -ne 0 ] || [ "${#apache_response[@]}" -eq 0 ]
+ then
+ return 1
+ fi
# the last line on the apache output is "Scoreboard"
# we use this label to detect that the output has a new word count
- if [ ${apache_keys_detected} -eq 0 -o "${apache_response[${apache_key_scoreboard}]}" != "Scoreboard" ]
- then
+ if [ ${apache_keys_detected} -eq 0 ] || [ "${apache_response[${apache_key_scoreboard}]}" != "Scoreboard" ]
+ then
apache_detect "${apache_response[@]}" || return 1
apache_keys_detected=1
fi
@@ -127,21 +131,20 @@ apache_get() {
apache_busyworkers="${apache_response[${apache_key_busyworkers}]}"
apache_idleworkers="${apache_response[${apache_key_idleworkers}]}"
- if [ -z "${apache_accesses}" \
- -o -z "${apache_kbytes}" \
- -o -z "${apache_reqpersec}" \
- -o -z "${apache_bytespersec}" \
- -o -z "${apache_bytesperreq}" \
- -o -z "${apache_busyworkers}" \
- -o -z "${apache_idleworkers}" \
- ]
- then
+ if [ -z "${apache_accesses}" ] || \
+ [ -z "${apache_kbytes}" ] || \
+ [ -z "${apache_reqpersec}" ] || \
+ [ -z "${apache_bytespersec}" ] || \
+ [ -z "${apache_bytesperreq}" ] || \
+ [ -z "${apache_busyworkers}" ]
+ [ -z "${apache_idleworkers}" ]
+ then
error "empty values got from apache server: ${apache_response[*]}"
return 1
fi
if [ ${apache_has_conns} -eq 1 ]
- then
+ then
apache_connstotal="${apache_response[${apache_key_connstotal}]}"
apache_connsasyncwriting="${apache_response[${apache_key_connsasyncwriting}]}"
apache_connsasynckeepalive="${apache_response[${apache_key_connsasynckeepalive}]}"
@@ -155,8 +158,10 @@ apache_get() {
apache_check() {
apache_get
+ # shellcheck disable=2181
if [ $? -ne 0 ]
- then
+ then
+ # shellcheck disable=2154
error "cannot find stub_status on URL '${apache_url}'. Please set apache_url='http://apache.server:80/server-status?auto' in $confd/apache.conf"
return 1
fi
@@ -187,7 +192,7 @@ DIMENSION sent '' incremental 8 1
EOF
if [ ${apache_has_conns} -eq 1 ]
- then
+ then
cat <<EOF2
CHART apache_local.connections '' "apache Connections" "connections" connections apache.connections line $((apache_priority + 2)) $apache_update_every
DIMENSION connections '' absolute 1 1
@@ -203,7 +208,6 @@ EOF2
# _update is called continuously, to collect the values
apache_update() {
- local reqs net
# the first argument to this function is the microseconds since last update
# pass this parameter to the BEGIN statement (see bellow).
@@ -237,7 +241,7 @@ END
VALUESEOF
if [ ${apache_has_conns} -eq 1 ]
- then
+ then
cat <<VALUESEOF2
BEGIN apache_local.connections $1
SET connections = $((apache_connstotal))
diff --git a/conf.d/charts.d/apache.conf b/collectors/charts.d.plugin/apache/apache.conf
index 50914cf32..50914cf32 100644
--- a/conf.d/charts.d/apache.conf
+++ b/collectors/charts.d.plugin/apache/apache.conf
diff --git a/collectors/charts.d.plugin/apcupsd/Makefile.inc b/collectors/charts.d.plugin/apcupsd/Makefile.inc
new file mode 100644
index 000000000..19cb9cad7
--- /dev/null
+++ b/collectors/charts.d.plugin/apcupsd/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += apcupsd/apcupsd.chart.sh
+dist_chartsconfig_DATA += apcupsd/apcupsd.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += apcupsd/README.md apcupsd/Makefile.inc
+
diff --git a/python.d/python_modules/bases/FrameworkServices/__init__.py b/collectors/charts.d.plugin/apcupsd/README.md
index e69de29bb..e69de29bb 100644
--- a/python.d/python_modules/bases/FrameworkServices/__init__.py
+++ b/collectors/charts.d.plugin/apcupsd/README.md
diff --git a/charts.d/apcupsd.chart.sh b/collectors/charts.d.plugin/apcupsd/apcupsd.chart.sh
index 9878fd36c..e26ef566a 100644
--- a/charts.d/apcupsd.chart.sh
+++ b/collectors/charts.d.plugin/apcupsd/apcupsd.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
apcupsd_ip=
@@ -43,11 +44,12 @@ apcupsd_check() {
for host in "${!apcupsd_sources[@]}"
do
run apcupsd_get "${apcupsd_sources[${host}]}" >/dev/null
+ # shellcheck disable=2181
if [ $? -ne 0 ]
then
error "cannot get information for apcupsd server ${host} on ${apcupsd_sources[${host}]}."
failed=$((failed + 1))
- elif [ $(apcupsd_get "${apcupsd_sources[${host}]}" | awk '/^STATUS.*/{ print $3 }') != "ONLINE" ]
+ elif [ "$(apcupsd_get "${apcupsd_sources[${host}]}" | awk '/^STATUS.*/{ print $3 }')" != "ONLINE" ]
then
error "APC UPS ${host} on ${apcupsd_sources[${host}]} is not online."
failed=$((failed + 1))
@@ -183,6 +185,7 @@ END {
print \"SET time = \" time;
print \"END\"
}"
+ # shellcheck disable=SC2181
if [ $? -ne 0 ]
then
failed=$((failed + 1))
diff --git a/conf.d/charts.d/apcupsd.conf b/collectors/charts.d.plugin/apcupsd/apcupsd.conf
index 679c0d61b..679c0d61b 100644
--- a/conf.d/charts.d/apcupsd.conf
+++ b/collectors/charts.d.plugin/apcupsd/apcupsd.conf
diff --git a/conf.d/charts.d.conf b/collectors/charts.d.plugin/charts.d.conf
index acb2a6fae..acb2a6fae 100644
--- a/conf.d/charts.d.conf
+++ b/collectors/charts.d.plugin/charts.d.conf
diff --git a/plugins.d/charts.d.dryrun-helper.sh b/collectors/charts.d.plugin/charts.d.dryrun-helper.sh
index 8142f9882..67496c1bd 100755
--- a/plugins.d/charts.d.dryrun-helper.sh
+++ b/collectors/charts.d.plugin/charts.d.dryrun-helper.sh
@@ -1,4 +1,7 @@
#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# shellcheck disable=SC2181
# will stop the script for any error
set -e
@@ -10,8 +13,8 @@ conf="$3"
can_diff=1
-tmp1="`mktemp`"
-tmp2="`mktemp`"
+tmp1="$(mktemp)"
+tmp2="$(mktemp)"
myset() {
set | grep -v "^_=" | grep -v "^PIPESTATUS=" | grep -v "^BASH_LINENO="
@@ -36,6 +39,7 @@ myset >"$tmp1"
# include the plugin and its config
if [ -f "$conf" ]
then
+ # shellcheck source=/dev/null
. "$conf"
if [ $? -ne 0 ]
then
@@ -45,6 +49,7 @@ then
fi
fi
+# shellcheck source=/dev/null
. "$chart"
if [ $? -ne 0 ]
then
diff --git a/plugins.d/charts.d.plugin b/collectors/charts.d.plugin/charts.d.plugin
index 9bd03fd47..1c6e8c5c9 100755..100644
--- a/plugins.d/charts.d.plugin
+++ b/collectors/charts.d.plugin/charts.d.plugin
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
@@ -116,14 +117,15 @@ info "started from '$PROGRAM_FILE' with options: $*"
# netdata exposes a few environment variables for us
[ -z "${NETDATA_PLUGINS_DIR}" ] && NETDATA_PLUGINS_DIR="$(dirname "${0}")"
-[ -z "${NETDATA_CONFIG_DIR}" ] && NETDATA_CONFIG_DIR="$(dirname "${0}")/../../../../etc/netdata"
+[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="/usr/local/etc/netdata"
+[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="/usr/local/lib/netdata/conf.d"
pluginsd="${NETDATA_PLUGINS_DIR}"
-confd="${NETDATA_CONFIG_DIR}"
+stockconfd="${NETDATA_STOCK_CONFIG_DIR}/${PROGRAM_NAME}"
+userconfd="${NETDATA_USER_CONFIG_DIR}/${PROGRAM_NAME}"
+olduserconfd="${NETDATA_USER_CONFIG_DIR}"
chartsd="$pluginsd/../charts.d"
-myconfig="$confd/$PROGRAM_NAME.conf"
-
minimum_update_frequency="${NETDATA_UPDATE_EVERY-1}"
update_every=${minimum_update_frequency} # this will be overwritten by the command line
@@ -230,22 +232,33 @@ mysleep="sleep"
# if found and included, this file overwrites loopsleepms()
# and current_time_ms() with a high resolution timer function
# for precise looping.
-. "$pluginsd/loopsleepms.sh.inc"
+source "$pluginsd/loopsleepms.sh.inc"
+[ $? -ne 0 ] && error "Failed to load '$pluginsd/loopsleepms.sh.inc'."
# -----------------------------------------------------------------------------
# load my configuration
-if [ -f "$myconfig" ]
+for myconfig in "${NETDATA_STOCK_CONFIG_DIR}/${PROGRAM_NAME}.conf" "${NETDATA_USER_CONFIG_DIR}/${PROGRAM_NAME}.conf"
+do
+ if [ -f "$myconfig" ]
then
- . "$myconfig"
- [ $? -ne 0 ] && fatal "cannot load $myconfig"
+ source "$myconfig"
+ if [ $? -ne 0 ]
+ then
+ error "Config file '$myconfig' loaded with errors."
+ else
+ info "Configuration file '$myconfig' loaded."
+ fi
+ else
+ warning "Configuration file '$myconfig' not found."
+ fi
+done
+
+# make sure time_divisor is right
+time_divisor=$((time_divisor))
+[ $time_divisor -lt 10 ] && time_divisor=10
+[ $time_divisor -gt 100 ] && time_divisor=100
- time_divisor=$((time_divisor))
- [ $time_divisor -lt 10 ] && time_divisor=10
- [ $time_divisor -gt 100 ] && time_divisor=100
-else
- info "configuration file '$myconfig' not found. Using defaults."
-fi
# we check for the timeout command, after we load our
# configuration, so that the user may overwrite the
@@ -296,7 +309,7 @@ run() {
{
printf "$(logdate): ${PROGRAM_NAME}: ${status}: ${MODULE_NAME}: command '"
printf "%q " "${@}"
- printf "' failed:\n --- BEGIN TRACE ---\n"
+ printf "' failed with code ${ret}:\n --- BEGIN TRACE ---\n"
cat "${TMP_DIR}/run.${pid}"
printf " --- END TRACE ---\n"
} >&2
@@ -411,7 +424,7 @@ all_enabled_charts() {
if [ ! "${enabled}" = "${required}" ]
then
- info "is disabled. Add a line with $chart=$required in $myconfig to enable it (or remove the line that disables it)."
+ info "is disabled. Add a line with $chart=$required in '${NETDATA_USER_CONFIG_DIR}/${PROGRAM_NAME}.conf' to enable it (or remove the line that disables it)."
else
debug "is enabled for auto-detection."
local charts="$charts $chart"
@@ -447,18 +460,18 @@ all_enabled_charts() {
fi
# check its config
- #if [ -f "$confd/$chart.conf" ]
+ #if [ -f "$userconfd/$chart.conf" ]
#then
- # if [ ! -z "$( cat "$confd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
+ # if [ ! -z "$( cat "$userconfd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
# then
- # error "module's $chart config $confd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
+ # error "module's $chart config $userconfd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
# continue
# fi
#fi
#if [ $dryrunner -eq 1 ]
# then
- # "$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$confd/$chart.conf" >/dev/null
+ # "$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$userconfd/$chart.conf" >/dev/null
# if [ $? -ne 0 ]
# then
# error "module's $chart did not pass the dry run check. This means it uses global variables not starting with $chart. Disabling it."
@@ -486,18 +499,35 @@ do
debug "loading module: '$chartsd/$chart.chart.sh'"
- . "$chartsd/$chart.chart.sh"
+ source "$chartsd/$chart.chart.sh"
+ [ $? -ne 0 ] && warning "Module '$chartsd/$chart.chart.sh' loaded with errors."
- if [ -f "$confd/$PROGRAM_NAME/$chart.conf" ]
+ # first load the stock config
+ if [ -f "$stockconfd/$chart.conf" ]
then
- debug "loading module configuration: '$confd/$PROGRAM_NAME/$chart.conf'"
- . "$confd/$PROGRAM_NAME/$chart.conf"
- elif [ -f "$confd/$chart.conf" ]
+ debug "loading module configuration: '$stockconfd/$chart.conf'"
+ source "$stockconfd/$chart.conf"
+ [ $? -ne 0 ] && warning "Config file '$stockconfd/$chart.conf' loaded with errors."
+ else
+ debug "not found module configuration: '$stockconfd/$chart.conf'"
+ fi
+
+ # then load the user config (it overwrites the stock)
+ if [ -f "$userconfd/$chart.conf" ]
then
- debug "loading module configuration: '$confd/$chart.conf'"
- . "$confd/$chart.conf"
+ debug "loading module configuration: '$userconfd/$chart.conf'"
+ source "$userconfd/$chart.conf"
+ [ $? -ne 0 ] && warning "Config file '$userconfd/$chart.conf' loaded with errors."
else
- warning "configuration file '$confd/$PROGRAM_NAME/$chart.conf' not found. Using defaults."
+ debug "not found module configuration: '$userconfd/$chart.conf'"
+
+ if [ -f "$olduserconfd/$chart.conf" ]
+ then
+ # support for very old netdata that had the charts.d module configs in /etc/netdata
+ info "loading module configuration from obsolete location: '$olduserconfd/$chart.conf'"
+ source "$olduserconfd/$chart.conf"
+ [ $? -ne 0 ] && warning "Config file '$olduserconfd/$chart.conf' loaded with errors."
+ fi
fi
eval "dt=\$$chart$suffix_update_every"
diff --git a/collectors/charts.d.plugin/charts.d.plugin.in b/collectors/charts.d.plugin/charts.d.plugin.in
new file mode 100755
index 000000000..3477894d8
--- /dev/null
+++ b/collectors/charts.d.plugin/charts.d.plugin.in
@@ -0,0 +1,743 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# netdata
+# real-time performance and health monitoring, done right!
+# (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
+# GPL v3+
+#
+# charts.d.plugin allows easy development of BASH plugins
+#
+# if you need to run parallel charts.d processes, link this file to a different name
+# in the same directory, with a .plugin suffix and netdata will start both of them,
+# each will have a different config file and modules configuration directory.
+#
+
+export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
+
+PROGRAM_FILE="$0"
+PROGRAM_NAME="$(basename $0)"
+PROGRAM_NAME="${PROGRAM_NAME/.plugin}"
+MODULE_NAME="main"
+
+# -----------------------------------------------------------------------------
+# create temp dir
+
+debug=0
+TMP_DIR=
+chartsd_cleanup() {
+ trap '' EXIT QUIT HUP INT TERM
+
+ if [ ! -z "$TMP_DIR" -a -d "$TMP_DIR" ]
+ then
+ [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: cleaning up temporary directory $TMP_DIR ..."
+ rm -rf "$TMP_DIR"
+ fi
+ exit 0
+}
+trap chartsd_cleanup EXIT QUIT HUP INT TERM
+
+if [ $UID = "0" ]
+then
+ TMP_DIR="$( mktemp -d /var/run/netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
+else
+ TMP_DIR="$( mktemp -d /tmp/.netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
+fi
+
+logdate() {
+ date "+%Y-%m-%d %H:%M:%S"
+}
+
+log() {
+ local status="${1}"
+ shift
+
+ echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${MODULE_NAME}: ${*}"
+
+}
+
+warning() {
+ log WARNING "${@}"
+}
+
+error() {
+ log ERROR "${@}"
+}
+
+info() {
+ log INFO "${@}"
+}
+
+fatal() {
+ log FATAL "${@}"
+ echo "DISABLE"
+ exit 1
+}
+
+debug() {
+ [ $debug -eq 1 ] && log DEBUG "${@}"
+}
+
+# -----------------------------------------------------------------------------
+# check a few commands
+
+require_cmd() {
+ local x=$(which "${1}" 2>/dev/null || command -v "${1}" 2>/dev/null)
+ if [ -z "${x}" -o ! -x "${x}" ]
+ then
+ warning "command '${1}' is not found in ${PATH}."
+ eval "${1^^}_CMD=\"\""
+ return 1
+ fi
+
+ eval "${1^^}_CMD=\"${x}\""
+ return 0
+}
+
+require_cmd date || exit 1
+require_cmd sed || exit 1
+require_cmd basename || exit 1
+require_cmd dirname || exit 1
+require_cmd cat || exit 1
+require_cmd grep || exit 1
+require_cmd egrep || exit 1
+require_cmd mktemp || exit 1
+require_cmd awk || exit 1
+require_cmd timeout || exit 1
+require_cmd curl || exit 1
+
+# -----------------------------------------------------------------------------
+
+[ $(( ${BASH_VERSINFO[0]} )) -lt 4 ] && fatal "BASH version 4 or later is required, but found version: ${BASH_VERSION}. Please upgrade."
+
+info "started from '$PROGRAM_FILE' with options: $*"
+
+# -----------------------------------------------------------------------------
+# internal defaults
+# netdata exposes a few environment variables for us
+
+[ -z "${NETDATA_PLUGINS_DIR}" ] && NETDATA_PLUGINS_DIR="$(dirname "${0}")"
+[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@"
+[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="@libconfigdir_POST@"
+
+pluginsd="${NETDATA_PLUGINS_DIR}"
+stockconfd="${NETDATA_STOCK_CONFIG_DIR}/${PROGRAM_NAME}"
+userconfd="${NETDATA_USER_CONFIG_DIR}/${PROGRAM_NAME}"
+olduserconfd="${NETDATA_USER_CONFIG_DIR}"
+chartsd="$pluginsd/../charts.d"
+
+minimum_update_frequency="${NETDATA_UPDATE_EVERY-1}"
+update_every=${minimum_update_frequency} # this will be overwritten by the command line
+
+# work around for non BASH shells
+charts_create="_create"
+charts_update="_update"
+charts_check="_check"
+charts_undescore="_"
+
+# when making iterations, charts.d can loop more frequently
+# to prevent plugins missing iterations.
+# this is a percentage relative to update_every to align its
+# iterations.
+# The minimum is 10%, the maximum 100%.
+# So, if update_every is 1 second and time_divisor is 50,
+# charts.d will iterate every 500ms.
+# Charts will be called to collect data only if the time
+# passed since the last time the collected data is equal or
+# above their update_every.
+time_divisor=50
+
+# number of seconds to run without restart
+# after this time, charts.d.plugin will exit
+# netdata will restart it
+restart_timeout=$((3600 * 4))
+
+# check if the charts.d plugins are using global variables
+# they should not.
+# It does not currently support BASH v4 arrays, so it is
+# disabled
+dryrunner=0
+
+# check for timeout command
+check_for_timeout=1
+
+# the default enable/disable value for all charts
+enable_all_charts="yes"
+
+# -----------------------------------------------------------------------------
+# parse parameters
+
+check=0
+chart_only=
+while [ ! -z "$1" ]
+do
+ if [ "$1" = "check" ]
+ then
+ check=1
+ shift
+ continue
+ fi
+
+ if [ "$1" = "debug" -o "$1" = "all" ]
+ then
+ debug=1
+ shift
+ continue
+ fi
+
+ if [ -f "$chartsd/$1.chart.sh" ]
+ then
+ debug=1
+ chart_only="$( echo $1.chart.sh | sed "s/\.chart\.sh$//g" )"
+ shift
+ continue
+ fi
+
+ if [ -f "$chartsd/$1" ]
+ then
+ debug=1
+ chart_only="$( echo $1 | sed "s/\.chart\.sh$//g" )"
+ shift
+ continue
+ fi
+
+ # number check
+ n="$1"
+ x=$(( n ))
+ if [ "$x" = "$n" ]
+ then
+ shift
+ update_every=$x
+ [ $update_every -lt $minimum_update_frequency ] && update_every=$minimum_update_frequency
+ continue
+ fi
+
+ fatal "Cannot understand parameter $1. Aborting."
+done
+
+
+# -----------------------------------------------------------------------------
+# loop control
+
+# default sleep function
+LOOPSLEEPMS_HIGHRES=0
+now_ms=
+current_time_ms_default() {
+ now_ms="$(date +'%s')000"
+}
+current_time_ms="current_time_ms_default"
+current_time_ms_accuracy=1
+mysleep="sleep"
+
+# if found and included, this file overwrites loopsleepms()
+# and current_time_ms() with a high resolution timer function
+# for precise looping.
+source "$pluginsd/loopsleepms.sh.inc"
+[ $? -ne 0 ] && error "Failed to load '$pluginsd/loopsleepms.sh.inc'."
+
+# -----------------------------------------------------------------------------
+# load my configuration
+
+for myconfig in "${NETDATA_STOCK_CONFIG_DIR}/${PROGRAM_NAME}.conf" "${NETDATA_USER_CONFIG_DIR}/${PROGRAM_NAME}.conf"
+do
+ if [ -f "$myconfig" ]
+ then
+ source "$myconfig"
+ if [ $? -ne 0 ]
+ then
+ error "Config file '$myconfig' loaded with errors."
+ else
+ info "Configuration file '$myconfig' loaded."
+ fi
+ else
+ warning "Configuration file '$myconfig' not found."
+ fi
+done
+
+# make sure time_divisor is right
+time_divisor=$((time_divisor))
+[ $time_divisor -lt 10 ] && time_divisor=10
+[ $time_divisor -gt 100 ] && time_divisor=100
+
+
+# we check for the timeout command, after we load our
+# configuration, so that the user may overwrite the
+# timeout command we use, providing a function that
+# can emulate the timeout command we need:
+# > timeout SECONDS command ...
+if [ $check_for_timeout -eq 1 ]
+ then
+ require_cmd timeout || exit 1
+fi
+
+# -----------------------------------------------------------------------------
+# internal checks
+
+# netdata passes the requested update frequency as the first argument
+update_every=$(( update_every + 1 - 1)) # makes sure it is a number
+test $update_every -eq 0 && update_every=1 # if it is zero, make it 1
+
+# check the charts.d directory
+[ ! -d "$chartsd" ] && fatal "cannot find charts directory '$chartsd'"
+
+# -----------------------------------------------------------------------------
+# library functions
+
+fixid() {
+ echo "$*" |\
+ tr -c "[A-Z][a-z][0-9]" "_" |\
+ sed -e "s|^_\+||g" -e "s|_\+$||g" -e "s|_\+|_|g" |\
+ tr "[A-Z]" "[a-z]"
+}
+
+run() {
+ local ret pid="${BASHPID}" t
+
+ if [ "z${1}" = "z-t" -a "${2}" != "0" ]
+ then
+ t="${2}"
+ shift 2
+ timeout ${t} "${@}" 2>"${TMP_DIR}/run.${pid}"
+ ret=$?
+ else
+ "${@}" 2>"${TMP_DIR}/run.${pid}"
+ ret=$?
+ fi
+
+ if [ ${ret} -ne 0 ]
+ then
+ {
+ printf "$(logdate): ${PROGRAM_NAME}: ${status}: ${MODULE_NAME}: command '"
+ printf "%q " "${@}"
+ printf "' failed with code ${ret}:\n --- BEGIN TRACE ---\n"
+ cat "${TMP_DIR}/run.${pid}"
+ printf " --- END TRACE ---\n"
+ } >&2
+ fi
+ rm "${TMP_DIR}/run.${pid}"
+
+ return ${ret}
+}
+
+# convert any floating point number
+# to integer, give a multiplier
+# the result is stored in ${FLOAT2INT_RESULT}
+# so that no fork is necessary
+# the multiplier must be a power of 10
+float2int() {
+ local f m="$2" a b l v=($1)
+ f=${v[0]}
+
+ # the length of the multiplier - 1
+ l=$(( ${#m} - 1 ))
+
+ # check if the number is in scientific notation
+ if [[ ${f} =~ ^[[:space:]]*(-)?[0-9.]+(e|E)(\+|-)[0-9]+ ]]
+ then
+ # convert it to decimal
+ # unfortunately, this fork cannot be avoided
+ # if you know of a way to avoid it, please let me know
+ f=$(printf "%0.${l}f" ${f})
+ fi
+
+ # split the floating point number
+ # in integer (a) and decimal (b)
+ a=${f/.*/}
+ b=${f/*./}
+
+ # if the integer part is missing
+ # set it to zero
+ [ -z "${a}" ] && a="0"
+
+ # strip leading zeros from the integer part
+ # base 10 convertion
+ a=$((10#$a))
+
+ # check the length of the decimal part
+ # against the length of the multiplier
+ if [ ${#b} -gt ${l} ]
+ then
+ # too many digits - take the most significant
+ b=${b:0:${l}}
+
+ elif [ ${#b} -lt ${l} ]
+ then
+ # too few digits - pad with zero on the right
+ local z="00000000000000000000000" r=$((l - ${#b}))
+ b="${b}${z:0:${r}}"
+ fi
+
+ # strip leading zeros from the decimal part
+ # base 10 convertion
+ b=$((10#$b))
+
+ # store the result
+ FLOAT2INT_RESULT=$(( (a * m) + b ))
+}
+
+
+# -----------------------------------------------------------------------------
+# charts check functions
+
+all_charts() {
+ cd "$chartsd"
+ [ $? -ne 0 ] && error "cannot cd to $chartsd" && return 1
+
+ ls *.chart.sh | sed "s/\.chart\.sh$//g"
+}
+
+declare -A charts_enable_keyword=(
+ ['apache']="force"
+ ['cpu_apps']="force"
+ ['cpufreq']="force"
+ ['example']="force"
+ ['exim']="force"
+ ['hddtemp']="force"
+ ['load_average']="force"
+ ['mem_apps']="force"
+ ['mysql']="force"
+ ['nginx']="force"
+ ['phpfpm']="force"
+ ['postfix']="force"
+ ['sensors']="force"
+ ['squid']="force"
+ ['tomcat']="force"
+ )
+
+all_enabled_charts() {
+ local charts= enabled= required=
+
+ # find all enabled charts
+
+ for chart in $( all_charts )
+ do
+ MODULE_NAME="${chart}"
+
+ eval "enabled=\$$chart"
+ if [ -z "${enabled}" ]
+ then
+ enabled="${enable_all_charts}"
+ fi
+
+ required="${charts_enable_keyword[${chart}]}"
+ [ -z "${required}" ] && required="yes"
+
+ if [ ! "${enabled}" = "${required}" ]
+ then
+ info "is disabled. Add a line with $chart=$required in '${NETDATA_USER_CONFIG_DIR}/${PROGRAM_NAME}.conf' to enable it (or remove the line that disables it)."
+ else
+ debug "is enabled for auto-detection."
+ local charts="$charts $chart"
+ fi
+ done
+ MODULE_NAME="main"
+
+ local charts2=
+ for chart in $charts
+ do
+ MODULE_NAME="${chart}"
+
+ # check the enabled charts
+ local check="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_check()" )"
+ if [ -z "$check" ]
+ then
+ error "module '$chart' does not seem to have a $chart$charts_check() function. Disabling it."
+ continue
+ fi
+
+ local create="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_create()" )"
+ if [ -z "$create" ]
+ then
+ error "module '$chart' does not seem to have a $chart$charts_create() function. Disabling it."
+ continue
+ fi
+
+ local update="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_update()" )"
+ if [ -z "$update" ]
+ then
+ error "module '$chart' does not seem to have a $chart$charts_update() function. Disabling it."
+ continue
+ fi
+
+ # check its config
+ #if [ -f "$userconfd/$chart.conf" ]
+ #then
+ # if [ ! -z "$( cat "$userconfd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
+ # then
+ # error "module's $chart config $userconfd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
+ # continue
+ # fi
+ #fi
+
+ #if [ $dryrunner -eq 1 ]
+ # then
+ # "$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$userconfd/$chart.conf" >/dev/null
+ # if [ $? -ne 0 ]
+ # then
+ # error "module's $chart did not pass the dry run check. This means it uses global variables not starting with $chart. Disabling it."
+ # continue
+ # fi
+ #fi
+
+ local charts2="$charts2 $chart"
+ done
+ MODULE_NAME="main"
+
+ echo $charts2
+ debug "enabled charts: $charts2"
+}
+
+# -----------------------------------------------------------------------------
+# load the charts
+
+suffix_retries="_retries"
+suffix_update_every="_update_every"
+active_charts=
+for chart in $( all_enabled_charts )
+do
+ MODULE_NAME="${chart}"
+
+ debug "loading module: '$chartsd/$chart.chart.sh'"
+
+ source "$chartsd/$chart.chart.sh"
+ [ $? -ne 0 ] && warning "Module '$chartsd/$chart.chart.sh' loaded with errors."
+
+ # first load the stock config
+ if [ -f "$stockconfd/$chart.conf" ]
+ then
+ debug "loading module configuration: '$stockconfd/$chart.conf'"
+ source "$stockconfd/$chart.conf"
+ [ $? -ne 0 ] && warning "Config file '$stockconfd/$chart.conf' loaded with errors."
+ else
+ debug "not found module configuration: '$stockconfd/$chart.conf'"
+ fi
+
+ # then load the user config (it overwrites the stock)
+ if [ -f "$userconfd/$chart.conf" ]
+ then
+ debug "loading module configuration: '$userconfd/$chart.conf'"
+ source "$userconfd/$chart.conf"
+ [ $? -ne 0 ] && warning "Config file '$userconfd/$chart.conf' loaded with errors."
+ else
+ debug "not found module configuration: '$userconfd/$chart.conf'"
+
+ if [ -f "$olduserconfd/$chart.conf" ]
+ then
+ # support for very old netdata that had the charts.d module configs in /etc/netdata
+ info "loading module configuration from obsolete location: '$olduserconfd/$chart.conf'"
+ source "$olduserconfd/$chart.conf"
+ [ $? -ne 0 ] && warning "Config file '$olduserconfd/$chart.conf' loaded with errors."
+ fi
+ fi
+
+ eval "dt=\$$chart$suffix_update_every"
+ dt=$(( dt + 1 - 1 )) # make sure it is a number
+ if [ $dt -lt $update_every ]
+ then
+ eval "$chart$suffix_update_every=$update_every"
+ fi
+
+ $chart$charts_check
+ if [ $? -eq 0 ]
+ then
+ debug "module '$chart' activated"
+ active_charts="$active_charts $chart"
+ else
+ error "module's '$chart' check() function reports failure."
+ fi
+done
+MODULE_NAME="main"
+debug "activated modules: $active_charts"
+
+
+# -----------------------------------------------------------------------------
+# check overwrites
+
+# enable work time reporting
+debug_time=
+test $debug -eq 1 && debug_time=tellwork
+
+# if we only need a specific chart, remove all the others
+if [ ! -z "${chart_only}" ]
+then
+ debug "requested to run only for: '${chart_only}'"
+ check_charts=
+ for chart in $active_charts
+ do
+ if [ "$chart" = "$chart_only" ]
+ then
+ check_charts="$chart"
+ break
+ fi
+ done
+ active_charts="$check_charts"
+fi
+debug "activated charts: $active_charts"
+
+# stop if we just need a pre-check
+if [ $check -eq 1 ]
+then
+ info "CHECK RESULT"
+ info "Will run the charts: $active_charts"
+ exit 0
+fi
+
+# -----------------------------------------------------------------------------
+
+cd "${TMP_DIR}" || exit 1
+
+# -----------------------------------------------------------------------------
+# create charts
+
+run_charts=
+for chart in $active_charts
+do
+ MODULE_NAME="${chart}"
+
+ debug "calling '$chart$charts_create()'..."
+ $chart$charts_create
+ if [ $? -eq 0 ]
+ then
+ run_charts="$run_charts $chart"
+ debug "'$chart' initialized."
+ else
+ error "module's '$chart' function '$chart$charts_create()' reports failure."
+ fi
+done
+MODULE_NAME="main"
+debug "run_charts='$run_charts'"
+
+
+# -----------------------------------------------------------------------------
+# update dimensions
+
+[ -z "$run_charts" ] && fatal "No charts to collect data from."
+
+declare -A charts_last_update=() charts_update_every=() charts_retries=() charts_next_update=() charts_run_counter=() charts_serial_failures=()
+global_update() {
+ local exit_at \
+ c=0 dt ret last_ms exec_start_ms exec_end_ms \
+ chart now_charts=() next_charts=($run_charts) \
+ next_ms x seconds millis
+
+ # return the current time in ms in $now_ms
+ ${current_time_ms}
+
+ exit_at=$(( now_ms + (restart_timeout * 1000) ))
+
+ for chart in $run_charts
+ do
+ eval "charts_update_every[$chart]=\$$chart$suffix_update_every"
+ test -z "${charts_update_every[$chart]}" && charts_update_every[$chart]=$update_every
+
+ eval "charts_retries[$chart]=\$$chart$suffix_retries"
+ test -z "${charts_retries[$chart]}" && charts_retries[$chart]=10
+
+ charts_last_update[$chart]=$((now_ms - (now_ms % (charts_update_every[$chart] * 1000) ) ))
+ charts_next_update[$chart]=$(( charts_last_update[$chart] + (charts_update_every[$chart] * 1000) ))
+ charts_run_counter[$chart]=0
+ charts_serial_failures[$chart]=0
+
+ echo "CHART netdata.plugin_chartsd_$chart '' 'Execution time for $chart plugin' 'milliseconds / run' charts.d netdata.plugin_charts area 145000 ${charts_update_every[$chart]}"
+ echo "DIMENSION run_time 'run time' absolute 1 1"
+ done
+
+ # the main loop
+ while [ "${#next_charts[@]}" -gt 0 ]
+ do
+ c=$((c + 1))
+ now_charts=("${next_charts[@]}")
+ next_charts=()
+
+ # return the current time in ms in $now_ms
+ ${current_time_ms}
+
+ for chart in "${now_charts[@]}"
+ do
+ MODULE_NAME="${chart}"
+
+ if [ ${now_ms} -ge ${charts_next_update[$chart]} ]
+ then
+ last_ms=${charts_last_update[$chart]}
+ dt=$(( (now_ms - last_ms) ))
+
+ charts_last_update[$chart]=${now_ms}
+
+ while [ ${charts_next_update[$chart]} -lt ${now_ms} ]
+ do
+ charts_next_update[$chart]=$(( charts_next_update[$chart] + (charts_update_every[$chart] * 1000) ))
+ done
+
+ # the first call should not give a duration
+ # so that netdata calibrates to current time
+ dt=$(( dt * 1000 ))
+ charts_run_counter[$chart]=$(( charts_run_counter[$chart] + 1 ))
+ if [ ${charts_run_counter[$chart]} -eq 1 ]
+ then
+ dt=
+ fi
+
+ exec_start_ms=$now_ms
+ $chart$charts_update $dt
+ ret=$?
+
+ # return the current time in ms in $now_ms
+ ${current_time_ms}; exec_end_ms=$now_ms
+
+ echo "BEGIN netdata.plugin_chartsd_$chart $dt"
+ echo "SET run_time = $(( exec_end_ms - exec_start_ms ))"
+ echo "END"
+
+ if [ $ret -eq 0 ]
+ then
+ charts_serial_failures[$chart]=0
+ next_charts+=($chart)
+ else
+ charts_serial_failures[$chart]=$(( charts_serial_failures[$chart] + 1 ))
+
+ if [ ${charts_serial_failures[$chart]} -gt ${charts_retries[$chart]} ]
+ then
+ error "module's '$chart' update() function reported failure ${charts_serial_failures[$chart]} times. Disabling it."
+ else
+ error "module's '$chart' update() function reports failure. Will keep trying for a while."
+ next_charts+=($chart)
+ fi
+ fi
+ else
+ next_charts+=($chart)
+ fi
+ done
+ MODULE_NAME="${chart}"
+
+ # wait the time you are required to
+ next_ms=$((now_ms + (update_every * 1000 * 100) ))
+ for x in "${charts_next_update[@]}"; do [ ${x} -lt ${next_ms} ] && next_ms=${x}; done
+ next_ms=$((next_ms - now_ms))
+
+ if [ ${LOOPSLEEPMS_HIGHRES} -eq 1 -a ${next_ms} -gt 0 ]
+ then
+ next_ms=$(( next_ms + current_time_ms_accuracy ))
+ seconds=$(( next_ms / 1000 ))
+ millis=$(( next_ms % 1000 ))
+ if [ ${millis} -lt 10 ]
+ then
+ millis="00${millis}"
+ elif [ ${millis} -lt 100 ]
+ then
+ millis="0${millis}"
+ fi
+
+ debug "sleeping for ${seconds}.${millis} seconds."
+ ${mysleep} ${seconds}.${millis}
+ else
+ debug "sleeping for ${update_every} seconds."
+ ${mysleep} $update_every
+ fi
+
+ test ${now_ms} -ge ${exit_at} && exit 0
+ done
+
+ fatal "nothing left to do, exiting..."
+}
+
+global_update
diff --git a/collectors/charts.d.plugin/cpu_apps/Makefile.inc b/collectors/charts.d.plugin/cpu_apps/Makefile.inc
new file mode 100644
index 000000000..a35f82837
--- /dev/null
+++ b/collectors/charts.d.plugin/cpu_apps/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += cpu_apps/cpu_apps.chart.sh
+dist_chartsconfig_DATA += cpu_apps/cpu_apps.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += cpu_apps/README.md cpu_apps/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/cpu_apps/README.md b/collectors/charts.d.plugin/cpu_apps/README.md
new file mode 100644
index 000000000..cd8adf0a2
--- /dev/null
+++ b/collectors/charts.d.plugin/cpu_apps/README.md
@@ -0,0 +1,2 @@
+> THIS MODULE IS OBSOLETE.
+> USE APPS.PLUGIN.
diff --git a/charts.d/cpu_apps.chart.sh b/collectors/charts.d.plugin/cpu_apps/cpu_apps.chart.sh
index 8e075831a..869464afe 100644
--- a/charts.d/cpu_apps.chart.sh
+++ b/collectors/charts.d.plugin/cpu_apps/cpu_apps.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash disable=SC2154,SC1072,SC1073,SC2009,SC2162,SC2006,SC2002,SC2086,SC1117
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# THIS PLUGIN IS OBSOLETE
# USE apps.plugin INSTEAD
diff --git a/conf.d/charts.d/cpu_apps.conf b/collectors/charts.d.plugin/cpu_apps/cpu_apps.conf
index 850cd0c6f..850cd0c6f 100644
--- a/conf.d/charts.d/cpu_apps.conf
+++ b/collectors/charts.d.plugin/cpu_apps/cpu_apps.conf
diff --git a/collectors/charts.d.plugin/cpufreq/Makefile.inc b/collectors/charts.d.plugin/cpufreq/Makefile.inc
new file mode 100644
index 000000000..682379133
--- /dev/null
+++ b/collectors/charts.d.plugin/cpufreq/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += cpufreq/cpufreq.chart.sh
+dist_chartsconfig_DATA += cpufreq/cpufreq.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += cpufreq/README.md cpufreq/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/cpufreq/README.md b/collectors/charts.d.plugin/cpufreq/README.md
new file mode 100644
index 000000000..d82951aac
--- /dev/null
+++ b/collectors/charts.d.plugin/cpufreq/README.md
@@ -0,0 +1,2 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
diff --git a/charts.d/cpufreq.chart.sh b/collectors/charts.d.plugin/cpufreq/cpufreq.chart.sh
index 1c41c38f2..1fc6caabf 100644
--- a/charts.d/cpufreq.chart.sh
+++ b/collectors/charts.d.plugin/cpufreq/cpufreq.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# if this chart is called X.chart.sh, then all functions and global variables
@@ -19,7 +20,7 @@ cpufreq_update_every=
cpufreq_priority=10000
cpufreq_find_all_files() {
- find $1 -maxdepth $cpufreq_sys_depth -name scaling_cur_freq 2>/dev/null
+ find "$1" -maxdepth $cpufreq_sys_depth -name scaling_cur_freq 2>/dev/null
}
# _check is called once, to find out if this chart should be enabled or not
@@ -29,30 +30,30 @@ cpufreq_check() {
# - 0 to enable the chart
# - 1 to disable the chart
- [ -z "$( cpufreq_find_all_files $cpufreq_sys_dir )" ] && return 1
+ [ -z "$( cpufreq_find_all_files "$cpufreq_sys_dir" )" ] && return 1
return 0
}
# _create is called once, to create the charts
cpufreq_create() {
- local dir= file= id= i=
+ local dir file id i
# we create a script with the source of the
# cpufreq_update() function
# - the highest speed we can achieve -
- [ $cpufreq_source_update -eq 1 ] && echo >$TMP_DIR/cpufreq.sh "cpufreq_update() {"
+ [ $cpufreq_source_update -eq 1 ] && echo >"$TMP_DIR/cpufreq.sh" "cpufreq_update() {"
echo "CHART cpu.cpufreq '' 'CPU Clock' 'MHz' 'cpufreq' '' line $((cpufreq_priority + 1)) $cpufreq_update_every"
- echo >>$TMP_DIR/cpufreq.sh "echo \"BEGIN cpu.cpufreq \$1\""
+ echo >>"$TMP_DIR/cpufreq.sh" "echo \"BEGIN cpu.cpufreq \$1\""
i=0
- for file in $( cpufreq_find_all_files $cpufreq_sys_dir | sort -u )
+ for file in $( cpufreq_find_all_files "$cpufreq_sys_dir" | sort -u )
do
i=$(( i + 1 ))
- dir=$( dirname $file )
+ dir=$( dirname "$file" )
cpu=
- [ -f $dir/affected_cpus ] && cpu=$( cat $dir/affected_cpus )
+ [ -f "$dir/affected_cpus" ] && cpu=$( cat "$dir/affected_cpus" )
[ -z "$cpu" ] && cpu="$i.a"
id="$( fixid "cpu$cpu" )"
@@ -60,14 +61,15 @@ cpufreq_create() {
debug "file='$file', dir='$dir', cpu='$cpu', id='$id'"
echo "DIMENSION $id '$id' absolute 1 1000"
- echo >>$TMP_DIR/cpufreq.sh "echo \"SET $id = \"\$(< $file )"
+ echo >>"$TMP_DIR/cpufreq.sh" "echo \"SET $id = \"\$(< $file )"
done
- echo >>$TMP_DIR/cpufreq.sh "echo END"
+ echo >>"$TMP_DIR/cpufreq.sh" "echo END"
- [ $cpufreq_source_update -eq 1 ] && echo >>$TMP_DIR/cpufreq.sh "}"
+ [ $cpufreq_source_update -eq 1 ] && echo >>"$TMP_DIR/cpufreq.sh" "}"
# ok, load the function cpufreq_update() we created
- [ $cpufreq_source_update -eq 1 ] && . $TMP_DIR/cpufreq.sh
+ # shellcheck disable=SC1090
+ [ $cpufreq_source_update -eq 1 ] && . "$TMP_DIR/cpufreq.sh"
return 0
}
@@ -80,8 +82,8 @@ cpufreq_update() {
# do all the work to collect / calculate the values
# for each dimension
# remember: KEEP IT SIMPLE AND SHORT
-
- [ $cpufreq_source_update -eq 0 ] && . $TMP_DIR/cpufreq.sh $1
+ # shellcheck disable=SC1090
+ [ $cpufreq_source_update -eq 0 ] && . "$TMP_DIR/cpufreq.sh" "$1"
return 0
}
diff --git a/conf.d/charts.d/cpufreq.conf b/collectors/charts.d.plugin/cpufreq/cpufreq.conf
index 7130555af..7130555af 100644
--- a/conf.d/charts.d/cpufreq.conf
+++ b/collectors/charts.d.plugin/cpufreq/cpufreq.conf
diff --git a/collectors/charts.d.plugin/example/Makefile.inc b/collectors/charts.d.plugin/example/Makefile.inc
new file mode 100644
index 000000000..e6838fbbe
--- /dev/null
+++ b/collectors/charts.d.plugin/example/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += example/example.chart.sh
+dist_chartsconfig_DATA += example/example.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += example/README.md example/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/example/README.md b/collectors/charts.d.plugin/example/README.md
new file mode 100644
index 000000000..bfd5e210a
--- /dev/null
+++ b/collectors/charts.d.plugin/example/README.md
@@ -0,0 +1,2 @@
+This is just an example charts.d data collector.
+
diff --git a/charts.d/example.chart.sh b/collectors/charts.d.plugin/example/example.chart.sh
index ffc98712f..1562c597a 100644
--- a/charts.d/example.chart.sh
+++ b/collectors/charts.d.plugin/example/example.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# if this chart is called X.chart.sh, then all functions and global variables
@@ -46,7 +47,7 @@ example_get() {
example_value4=$((8192 + (RANDOM * 16383 / 32767) ))
if [ $example_count -gt 0 ]
- then
+ then
example_count=$((example_count - 1))
[ $example_last -gt 16383 ] && example_value4=$((example_last + (RANDOM * ( (32767 - example_last) / 2) / 32767)))
@@ -54,8 +55,14 @@ example_get() {
else
example_count=$((1 + (RANDOM * 5 / 32767) ))
- [ $example_last -gt 16383 -a $example_value4 -gt 16383 ] && example_value4=$((example_value4 - 16383))
- [ $example_last -le 16383 -a $example_value4 -lt 16383 ] && example_value4=$((example_value4 + 16383))
+ if [ $example_last -gt 16383 ] && [ $example_value4 -gt 16383 ]
+ then
+ example_value4=$((example_value4 - 16383))
+ fi
+ if [ $example_last -le 16383 ] && [ $example_value4 -lt 16383 ]
+ then
+ example_value4=$((example_value4 + 16383))
+ fi
fi
example_last=$example_value4
diff --git a/conf.d/charts.d/example.conf b/collectors/charts.d.plugin/example/example.conf
index 6232ca584..6232ca584 100644
--- a/conf.d/charts.d/example.conf
+++ b/collectors/charts.d.plugin/example/example.conf
diff --git a/collectors/charts.d.plugin/exim/Makefile.inc b/collectors/charts.d.plugin/exim/Makefile.inc
new file mode 100644
index 000000000..ca2112a80
--- /dev/null
+++ b/collectors/charts.d.plugin/exim/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += exim/exim.chart.sh
+dist_chartsconfig_DATA += exim/exim.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += exim/README.md exim/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/exim/README.md b/collectors/charts.d.plugin/exim/README.md
new file mode 100644
index 000000000..d82951aac
--- /dev/null
+++ b/collectors/charts.d.plugin/exim/README.md
@@ -0,0 +1,2 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
diff --git a/charts.d/exim.chart.sh b/collectors/charts.d.plugin/exim/exim.chart.sh
index 4c70f2c19..8099a7249 100644
--- a/charts.d/exim.chart.sh
+++ b/collectors/charts.d.plugin/exim/exim.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# Contributed by @jsveiga with PR #480
@@ -22,7 +23,7 @@ exim_check() {
exim_command="${EXIM_CMD}"
fi
- if [ $(${exim_command} -bpc 2>&1 | grep -c denied) -ne 0 ]
+ if [ "$(${exim_command} -bpc 2>&1 | grep -c denied)" -ne 0 ]
then
error "permission denied - please set 'queue_list_requires_admin = false' in your exim options file"
return 1
@@ -41,7 +42,7 @@ EOF
exim_update() {
echo "BEGIN exim_local.qemails $1"
- echo "SET emails = " $(run ${exim_command} -bpc)
+ echo "SET emails = $(run "${exim_command}" -bpc)"
echo "END"
return 0
}
diff --git a/conf.d/charts.d/exim.conf b/collectors/charts.d.plugin/exim/exim.conf
index f96ac4dbb..f96ac4dbb 100644
--- a/conf.d/charts.d/exim.conf
+++ b/collectors/charts.d.plugin/exim/exim.conf
diff --git a/collectors/charts.d.plugin/hddtemp/Makefile.inc b/collectors/charts.d.plugin/hddtemp/Makefile.inc
new file mode 100644
index 000000000..2bd29e5b1
--- /dev/null
+++ b/collectors/charts.d.plugin/hddtemp/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += hddtemp/hddtemp.chart.sh
+dist_chartsconfig_DATA += hddtemp/hddtemp.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += hddtemp/README.md hddtemp/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/hddtemp/README.md b/collectors/charts.d.plugin/hddtemp/README.md
new file mode 100644
index 000000000..98f18900c
--- /dev/null
+++ b/collectors/charts.d.plugin/hddtemp/README.md
@@ -0,0 +1,28 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
+
+# hddtemp
+
+The plugin will collect temperatures from disks
+
+It will create one chart with all active disks
+
+1. **temperature in Celsius**
+
+### configuration
+
+hddtemp needs to be running in daemonized mode
+
+```sh
+# host with daemonized hddtemp
+hddtemp_host="localhost"
+
+# port on which hddtemp is showing data
+hddtemp_port="7634"
+
+# array of included disks
+# the default is to include all
+hddtemp_disks=()
+```
+
+---
diff --git a/charts.d/hddtemp.chart.sh b/collectors/charts.d.plugin/hddtemp/hddtemp.chart.sh
index 3aada1751..e90310981 100644
--- a/charts.d/hddtemp.chart.sh
+++ b/collectors/charts.d.plugin/hddtemp/hddtemp.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# contributed by @paulfantom with PR #511
@@ -30,13 +31,14 @@ hddtemp_create() {
local all
all=$(nc $hddtemp_host $hddtemp_port )
unset hddtemp_disks
- hddtemp_disks=( `grep -Po '/dev/[^|]+' <<< "$all" | cut -c 6-` )
+ # shellcheck disable=SC2190,SC2207
+ hddtemp_disks=( $(grep -Po '/dev/[^|]+' <<< "$all" | cut -c 6-) )
fi
# local disk_names
# disk_names=(`sed -e 's/||/\n/g;s/^|//' <<< "$all" | cut -d '|' -f2 | tr ' ' '_'`)
echo "CHART hddtemp.temperature 'disks_temp' 'temperature' 'Celsius' 'Disks temperature' 'hddtemp.temp' line $((hddtemp_priority)) $hddtemp_update_every"
- for i in `seq 0 $((${#hddtemp_disks[@]}-1))`; do
+ for i in $(seq 0 $((${#hddtemp_disks[@]}-1))); do
# echo "DIMENSION ${hddtemp_disks[i]} ${disk_names[i]} absolute 1 1"
echo "DIMENSION ${hddtemp_disks[$i]} '' absolute 1 1"
done
@@ -44,13 +46,14 @@ hddtemp_create() {
}
# _update is called continuously, to collect the values
-hddtemp_last=0
-hddtemp_count=0
+#hddtemp_last=0
+#hddtemp_count=0
hddtemp_update() {
# local all=( `nc $hddtemp_host $hddtemp_port | sed -e 's/||/\n/g;s/^|//' | cut -d '|' -f3` )
# local all=( `nc $hddtemp_host $hddtemp_port | awk 'BEGIN { FS="|" };{i=4; while (i <= NF) {print $i+0;i+=5;};}'` )
OLD_IFS=$IFS
set -f
+ # shellcheck disable=SC2207
IFS="|" all=( $(nc $hddtemp_host $hddtemp_port 2>/dev/null) )
set +f
IFS=$OLD_IFS
diff --git a/conf.d/charts.d/hddtemp.conf b/collectors/charts.d.plugin/hddtemp/hddtemp.conf
index b6037b40e..b6037b40e 100644
--- a/conf.d/charts.d/hddtemp.conf
+++ b/collectors/charts.d.plugin/hddtemp/hddtemp.conf
diff --git a/collectors/charts.d.plugin/libreswan/Makefile.inc b/collectors/charts.d.plugin/libreswan/Makefile.inc
new file mode 100644
index 000000000..af767d0dd
--- /dev/null
+++ b/collectors/charts.d.plugin/libreswan/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += libreswan/libreswan.chart.sh
+dist_chartsconfig_DATA += libreswan/libreswan.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += libreswan/README.md libreswan/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/libreswan/README.md b/collectors/charts.d.plugin/libreswan/README.md
new file mode 100644
index 000000000..41026cf72
--- /dev/null
+++ b/collectors/charts.d.plugin/libreswan/README.md
@@ -0,0 +1,42 @@
+# libreswan
+
+The plugin will collects bytes-in, bytes-out and uptime for all established libreswan IPSEC tunnels.
+
+The following charts are created, **per tunnel**:
+
+1. **Uptime**
+
+ * the uptime of the tunnel
+
+2. **Traffic**
+
+ * bytes in
+ * bytes out
+
+### configuration
+
+Its config file is `/etc/netdata/charts.d/libreswan.conf`.
+
+The plugin executes 2 commands to collect all the information it needs:
+
+```sh
+ipsec whack --status
+ipsec whack --trafficstatus
+```
+
+The first command is used to extract the currently established tunnels, their IDs and their names.
+The second command is used to extract the current uptime and traffic.
+
+Most probably user `netdata` will not be able to query libreswan, so the `ipsec` commands will be denied.
+The plugin attempts to run `ipsec` as `sudo ipsec ...`, to get access to libreswan statistics.
+
+To allow user `netdata` execute `sudo ipsec ...`, create the file `/etc/sudoers.d/netdata` with this content:
+
+```
+netdata ALL = (root) NOPASSWD: /sbin/ipsec whack --status
+netdata ALL = (root) NOPASSWD: /sbin/ipsec whack --trafficstatus
+```
+
+Make sure the path `/sbin/ipsec` matches your setup (execute `which ipsec` to find the right path).
+
+---
diff --git a/charts.d/libreswan.chart.sh b/collectors/charts.d.plugin/libreswan/libreswan.chart.sh
index 30632e9ce..6e29f8473 100644
--- a/charts.d/libreswan.chart.sh
+++ b/collectors/charts.d.plugin/libreswan/libreswan.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash disable=SC1117
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2018 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# _update_every is a special variable - it holds the number of seconds
@@ -60,7 +61,8 @@ libreswan_get() {
libreswan_connected_tunnels=()
# convert the ipsec command output to a shell script
- # and source it to get the values
+ # and source it to get the values
+ # shellcheck disable=SC1090
source <(
{
libreswan_ipsec whack --status;
@@ -85,6 +87,7 @@ libreswan_check() {
require_cmd ipsec || return 1
# make sure it is libreswan
+ # shellcheck disable=SC2143
if [ -z "$(ipsec --version | grep -i libreswan)" ]
then
error "ipsec command is not Libreswan. Disabling Libreswan plugin."
@@ -140,7 +143,7 @@ libreswan_update_one() {
[ -z "${id}" ] && libreswan_create_one "${name}"
- uptime=$(( ${libreswan_now} - ${libreswan_established_add_time[${n}]} ))
+ uptime=$(( libreswan_now - libreswan_established_add_time[${n}] ))
[ ${uptime} -lt 0 ] && uptime=0
# write the result of the work.
diff --git a/conf.d/charts.d/libreswan.conf b/collectors/charts.d.plugin/libreswan/libreswan.conf
index 9b3ee77b7..9b3ee77b7 100644
--- a/conf.d/charts.d/libreswan.conf
+++ b/collectors/charts.d.plugin/libreswan/libreswan.conf
diff --git a/collectors/charts.d.plugin/load_average/Makefile.inc b/collectors/charts.d.plugin/load_average/Makefile.inc
new file mode 100644
index 000000000..e5a481bf4
--- /dev/null
+++ b/collectors/charts.d.plugin/load_average/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += load_average/load_average.chart.sh
+dist_chartsconfig_DATA += load_average/load_average.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += load_average/README.md load_average/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/load_average/README.md b/collectors/charts.d.plugin/load_average/README.md
new file mode 100644
index 000000000..39d3b8189
--- /dev/null
+++ b/collectors/charts.d.plugin/load_average/README.md
@@ -0,0 +1,2 @@
+> THIS MODULE IS OBSOLETE.
+> THE NETDATA DAEMON COLLECTS LOAD AVERAGE BY ITSELF
diff --git a/charts.d/load_average.chart.sh b/collectors/charts.d.plugin/load_average/load_average.chart.sh
index 70d3aec7a..b30cb850f 100644
--- a/charts.d/load_average.chart.sh
+++ b/collectors/charts.d.plugin/load_average/load_average.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash disable=SC2154,SC1072,SC1073,SC2009,SC2162,SC2006,SC2002,SC2086,SC1117
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
load_average_update_every=5
diff --git a/conf.d/charts.d/load_average.conf b/collectors/charts.d.plugin/load_average/load_average.conf
index 68979275f..68979275f 100644
--- a/conf.d/charts.d/load_average.conf
+++ b/collectors/charts.d.plugin/load_average/load_average.conf
diff --git a/plugins.d/loopsleepms.sh.inc b/collectors/charts.d.plugin/loopsleepms.sh.inc
index ef3db192d..bdc032b99 100644
--- a/plugins.d/loopsleepms.sh.inc
+++ b/collectors/charts.d.plugin/loopsleepms.sh.inc
@@ -1,4 +1,5 @@
# no need for shebang - this file is included from other scripts
+# SPDX-License-Identifier: GPL-3.0-or-later
LOOPSLEEP_DATE="$(which date 2>/dev/null || command -v date 2>/dev/null)"
if [ -z "$LOOPSLEEP_DATE" ]
@@ -85,11 +86,12 @@ fi
# -----------------------------------------------------------------------------
# use read with timeout for sleep
-mysleep="mysleep_read"
+mysleep=""
mysleep_fifo="${NETDATA_CACHE_DIR-/tmp}/.netdata_bash_sleep_timer_fifo"
-[ ! -e "${mysleep_fifo}" ] && mkfifo "${mysleep_fifo}"
-[ ! -e "${mysleep_fifo}" ] && mysleep="sleep"
+[ -f "${mysleep_fifo}" ] && rm "${mysleep_fifo}"
+[ ! -p "${mysleep_fifo}" ] && mkfifo "${mysleep_fifo}"
+[ -p "${mysleep_fifo}" ] && mysleep="mysleep_read"
mysleep_read() {
read -t "${1}" <>"${mysleep_fifo}"
@@ -102,6 +104,52 @@ mysleep_read() {
fi
}
+# -----------------------------------------------------------------------------
+# use bash loadable module for sleep
+
+mysleep_builtin() {
+ builtin sleep "${1}"
+ ret=$?
+ if [ $ret -ne 0 ]
+ then
+ echo >&2 "$0: Cannot use builtin sleep for sleeping (return code ${ret})."
+ mysleep="sleep"
+ ${mysleep} "${1}"
+ fi
+}
+
+if [ -z "${mysleep}" -a "$((BASH_VERSINFO[0] +0))" -ge 3 -a "${NETDATA_BASH_LOADABLES}" != "DISABLE" ]
+ then
+ # enable modules only for bash version 3+
+
+ for bash_modules_path in ${BASH_LOADABLES_PATH//:/ } "$(pkg-config bash --variable=loadablesdir 2>/dev/null)" "/usr/lib/bash" "/lib/bash" "/lib64/bash" "/usr/local/lib/bash" "/usr/local/lib64/bash"
+ do
+ [ -z "${bash_modules_path}" -o ! -d "${bash_modules_path}" ] && continue
+
+ # check for sleep
+ for bash_module_sleep in "sleep" "sleep.so"
+ do
+ if [ -f "${bash_modules_path}/${bash_module_sleep}" ]
+ then
+ if enable -f "${bash_modules_path}/${bash_module_sleep}" sleep 2>/dev/null
+ then
+ mysleep="mysleep_builtin"
+ # echo >&2 "$0: Using bash loadable ${bash_modules_path}/${bash_module_sleep} for sleep"
+ break
+ fi
+ fi
+
+ done
+
+ [ ! -z "${mysleep}" ] && break
+ done
+fi
+
+# -----------------------------------------------------------------------------
+# fallback to external sleep
+
+[ -z "${mysleep}" ] && mysleep="sleep"
+
# -----------------------------------------------------------------------------
# this function is used to sleep a fraction of a second
diff --git a/collectors/charts.d.plugin/mem_apps/Makefile.inc b/collectors/charts.d.plugin/mem_apps/Makefile.inc
new file mode 100644
index 000000000..ea546fb69
--- /dev/null
+++ b/collectors/charts.d.plugin/mem_apps/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += mem_apps/mem_apps.chart.sh
+dist_chartsconfig_DATA += mem_apps/mem_apps.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += mem_apps/README.md mem_apps/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/mem_apps/README.md b/collectors/charts.d.plugin/mem_apps/README.md
new file mode 100644
index 000000000..cd8adf0a2
--- /dev/null
+++ b/collectors/charts.d.plugin/mem_apps/README.md
@@ -0,0 +1,2 @@
+> THIS MODULE IS OBSOLETE.
+> USE APPS.PLUGIN.
diff --git a/charts.d/mem_apps.chart.sh b/collectors/charts.d.plugin/mem_apps/mem_apps.chart.sh
index 3bc65fe24..a13dc71f1 100644
--- a/charts.d/mem_apps.chart.sh
+++ b/collectors/charts.d.plugin/mem_apps/mem_apps.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash disable=SC2154,SC1072,SC1073,SC2009,SC2162,SC2006,SC2002,SC2086,SC1117
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
mem_apps_apps=
diff --git a/conf.d/charts.d/mem_apps.conf b/collectors/charts.d.plugin/mem_apps/mem_apps.conf
index 75d24dc3e..75d24dc3e 100644
--- a/conf.d/charts.d/mem_apps.conf
+++ b/collectors/charts.d.plugin/mem_apps/mem_apps.conf
diff --git a/collectors/charts.d.plugin/mysql/Makefile.inc b/collectors/charts.d.plugin/mysql/Makefile.inc
new file mode 100644
index 000000000..ca02fd078
--- /dev/null
+++ b/collectors/charts.d.plugin/mysql/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += mysql/mysql.chart.sh
+dist_chartsconfig_DATA += mysql/mysql.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += mysql/README.md mysql/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/mysql/README.md b/collectors/charts.d.plugin/mysql/README.md
new file mode 100644
index 000000000..6765b53ab
--- /dev/null
+++ b/collectors/charts.d.plugin/mysql/README.md
@@ -0,0 +1,81 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
+
+# mysql
+
+The plugin will monitor one or more mysql servers
+
+It will produce the following charts:
+
+1. **Bandwidth** in kbps
+ * in
+ * out
+
+2. **Queries** in queries/sec
+ * queries
+ * questions
+ * slow queries
+
+3. **Operations** in operations/sec
+ * opened tables
+ * flush
+ * commit
+ * delete
+ * prepare
+ * read first
+ * read key
+ * read next
+ * read prev
+ * read random
+ * read random next
+ * rollback
+ * save point
+ * update
+ * write
+
+4. **Table Locks** in locks/sec
+ * immediate
+ * waited
+
+5. **Select Issues** in issues/sec
+ * full join
+ * full range join
+ * range
+ * range check
+ * scan
+
+6. **Sort Issues** in issues/sec
+ * merge passes
+ * range
+ * scan
+
+### configuration
+
+You can configure many database servers, like this:
+
+You can provide, per server, the following:
+
+1. a name, anything you like, but keep it short
+2. the mysql command to connect to the server
+3. the mysql command line options to be used for connecting to the server
+
+Here is an example for 2 servers:
+
+```sh
+mysql_opts[server1]="-h server1.example.com"
+mysql_opts[server2]="-h server2.example.com --connect_timeout 2"
+```
+
+The above will use the `mysql` command found in the system path.
+You can also provide a custom mysql command per server, like this:
+
+```sh
+mysql_cmds[server2]="/opt/mysql/bin/mysql"
+```
+
+The above sets the mysql command only for server2. server1 will use the system default.
+
+If no configuration is given, the plugin will attempt to connect to mysql server at localhost.
+
+
+---
diff --git a/charts.d/mysql.chart.sh b/collectors/charts.d.plugin/mysql/mysql.chart.sh
index 1363d01f4..37e8e2a7c 100644
--- a/charts.d/mysql.chart.sh
+++ b/collectors/charts.d.plugin/mysql/mysql.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# http://dev.mysql.com/doc/refman/5.0/en/server-status-variables.html
@@ -25,7 +26,8 @@ mysql_get() {
IFS=$'\t'$'\n'
#arr=($(run "${@}" -e "SHOW GLOBAL STATUS WHERE value REGEXP '^[0-9]';" | egrep "^(Bytes|Slow_|Que|Handl|Table|Selec|Sort_|Creat|Conne|Abort|Binlo|Threa|Innod|Qcach|Key_|Open)" ))
#arr=($(run "${@}" -N -e "SHOW GLOBAL STATUS;" | egrep "^(Bytes|Slow_|Que|Handl|Table|Selec|Sort_|Creat|Conne|Abort|Binlo|Threa|Innod|Qcach|Key_|Open)[^ ]+\s[0-9]" ))
- arr=($(run "${@}" -N -e "SHOW GLOBAL STATUS;" | egrep "^(Bytes|Slow_|Que|Handl|Table|Selec|Sort_|Creat|Conne|Abort|Binlo|Threa|Innod|Qcach|Key_|Open)[^[:space:]]+[[:space:]]+[0-9]+" ))
+ # shellcheck disable=SC2207
+ arr=($(run "${@}" -N -e "SHOW GLOBAL STATUS;" | grep -E "^(Bytes|Slow_|Que|Handl|Table|Selec|Sort_|Creat|Conne|Abort|Binlo|Threa|Innod|Qcach|Key_|Open)[^[:space:]]+[[:space:]]+[0-9]+" ))
IFS="${oIFS}"
[ "${#arr[@]}" -lt 3 ] && return 1
@@ -55,6 +57,7 @@ mysql_check() {
shift
fi
+ # shellcheck disable=SC2230
[ -z "${mysql_cmd}" ] && mysql_cmd="$(which mysql 2>/dev/null || command -v mysql 2>/dev/null)"
if [ ${#mysql_opts[@]} -eq 0 ]
@@ -80,16 +83,18 @@ mysql_check() {
[ -z "${mysql_cmds[$m]}" ] && mysql_cmds[$m]="$mysql_cmd"
if [ -z "${mysql_cmds[$m]}" ]
then
- error "cannot get mysql command for '$m'. Please set mysql_cmds[$m]='/path/to/mysql', in $confd/mysql.conf"
+ # shellcheck disable=SC2154
+ error "cannot get mysql command for '${m}'. Please set mysql_cmds[$m]='/path/to/mysql', in $confd/mysql.conf"
fi
mysql_get "${mysql_cmds[$m]}" ${mysql_opts[$m]}
+ # shellcheck disable=SC2181
if [ ! $? -eq 0 ]
then
error "cannot get global status for '$m'. Please set mysql_opts[$m]='options' to whatever needed to get connected to the mysql server, in $confd/mysql.conf"
- unset mysql_cmds[$m]
- unset mysql_opts[$m]
- unset mysql_ids[$m]
+ unset "mysql_cmds[$m]"
+ unset "mysql_opts[$m]"
+ unset "mysql_ids[$m]"
continue
fi
@@ -98,7 +103,7 @@ mysql_check() {
if [ ${#mysql_opts[@]} -eq 0 ]
then
- if [ ${unconfigured} -eq 1 -a ${tryroot} -eq 0 ]
+ if [ ${unconfigured} -eq 1 ] && [ ${tryroot} -eq 0 ]
then
mysql_check tryroot "${@}"
return $?
@@ -319,12 +324,13 @@ mysql_update() {
x="${mysql_ids[$m]}"
mysql_get "${mysql_cmds[$m]}" ${mysql_opts[$m]}
+ # shellcheck disable=SC2181
if [ $? -ne 0 ]
then
- unset mysql_ids[$m]
- unset mysql_opts[$m]
- unset mysql_cmds[$m]
- error "failed to get values for '$m', disabling it."
+ unset "mysql_ids[$m]"
+ unset "mysql_opts[$m]"
+ unset "mysql_cmds[$m]"
+ error "failed to get values for '${m}', disabling it."
continue
fi
diff --git a/conf.d/charts.d/mysql.conf b/collectors/charts.d.plugin/mysql/mysql.conf
index 683e4af35..683e4af35 100644
--- a/conf.d/charts.d/mysql.conf
+++ b/collectors/charts.d.plugin/mysql/mysql.conf
diff --git a/collectors/charts.d.plugin/nginx/Makefile.inc b/collectors/charts.d.plugin/nginx/Makefile.inc
new file mode 100644
index 000000000..c9d31aada
--- /dev/null
+++ b/collectors/charts.d.plugin/nginx/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += nginx/nginx.chart.sh
+dist_chartsconfig_DATA += nginx/nginx.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += nginx/README.md nginx/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/nginx/README.md b/collectors/charts.d.plugin/nginx/README.md
new file mode 100644
index 000000000..d82951aac
--- /dev/null
+++ b/collectors/charts.d.plugin/nginx/README.md
@@ -0,0 +1,2 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
diff --git a/charts.d/nginx.chart.sh b/collectors/charts.d.plugin/nginx/nginx.chart.sh
index d0df460ac..14dda0832 100644
--- a/charts.d/nginx.chart.sh
+++ b/collectors/charts.d.plugin/nginx/nginx.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# if this chart is called X.chart.sh, then all functions and global variables
@@ -26,20 +27,21 @@ nginx_reading=0
nginx_writing=0
nginx_waiting=0
nginx_get() {
+ # shellcheck disable=SC2207
nginx_response=($(run curl -Ss ${nginx_curl_opts} "${nginx_url}"))
- [ $? -ne 0 -o "${#nginx_response[@]}" -eq 0 ] && return 1
-
- if [ "${nginx_response[0]}" != "Active" \
- -o "${nginx_response[1]}" != "connections:" \
- -o "${nginx_response[3]}" != "server" \
- -o "${nginx_response[4]}" != "accepts" \
- -o "${nginx_response[5]}" != "handled" \
- -o "${nginx_response[6]}" != "requests" \
- -o "${nginx_response[10]}" != "Reading:" \
- -o "${nginx_response[12]}" != "Writing:" \
- -o "${nginx_response[14]}" != "Waiting:" \
- ]
- then
+ # shellcheck disable=SC2181
+ if [ $? -ne 0 ] || [ "${#nginx_response[@]}" -eq 0 ]; then return 1; fi
+
+ if [ "${nginx_response[0]}" != "Active" ] ||\
+ [ "${nginx_response[1]}" != "connections:" ] ||\
+ [ "${nginx_response[3]}" != "server" ] ||\
+ [ "${nginx_response[4]}" != "accepts" ] ||\
+ [ "${nginx_response[5]}" != "handled" ] ||\
+ [ "${nginx_response[6]}" != "requests" ] ||\
+ [ "${nginx_response[10]}" != "Reading:" ] ||\
+ [ "${nginx_response[12]}" != "Writing:" ] ||\
+ [ "${nginx_response[14]}" != "Waiting:" ]
+ then
error "Invalid response from nginx server: ${nginx_response[*]}"
return 1
fi
@@ -52,15 +54,14 @@ nginx_get() {
nginx_writing="${nginx_response[13]}"
nginx_waiting="${nginx_response[15]}"
- if [ -z "${nginx_active_connections}" \
- -o -z "${nginx_accepts}" \
- -o -z "${nginx_handled}" \
- -o -z "${nginx_requests}" \
- -o -z "${nginx_reading}" \
- -o -z "${nginx_writing}" \
- -o -z "${nginx_waiting}" \
- ]
- then
+ if [ -z "${nginx_active_connections}" ] ||\
+ [ -z "${nginx_accepts}" ] ||\
+ [ -z "${nginx_handled}" ] ||\
+ [ -z "${nginx_requests}" ] ||\
+ [ -z "${nginx_reading}" ] ||\
+ [ -z "${nginx_writing}" ] ||\
+ [ -z "${nginx_waiting}" ]
+ then
error "empty values got from nginx server: ${nginx_response[*]}"
return 1
fi
@@ -72,8 +73,10 @@ nginx_get() {
nginx_check() {
nginx_get
+ # shellcheck disable=2181
if [ $? -ne 0 ]
- then
+ then
+ # shellcheck disable=SC2154
error "cannot find stub_status on URL '${nginx_url}'. Please set nginx_url='http://nginx.server/stub_status' in $confd/nginx.conf"
return 1
fi
diff --git a/conf.d/charts.d/nginx.conf b/collectors/charts.d.plugin/nginx/nginx.conf
index c46100a58..c46100a58 100644
--- a/conf.d/charts.d/nginx.conf
+++ b/collectors/charts.d.plugin/nginx/nginx.conf
diff --git a/collectors/charts.d.plugin/nut/Makefile.inc b/collectors/charts.d.plugin/nut/Makefile.inc
new file mode 100644
index 000000000..4fb47145d
--- /dev/null
+++ b/collectors/charts.d.plugin/nut/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += nut/nut.chart.sh
+dist_chartsconfig_DATA += nut/nut.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += nut/README.md nut/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/nut/README.md b/collectors/charts.d.plugin/nut/README.md
new file mode 100644
index 000000000..71906f55a
--- /dev/null
+++ b/collectors/charts.d.plugin/nut/README.md
@@ -0,0 +1,59 @@
+# nut
+
+The plugin will collect UPS data for all UPSes configured in the system.
+
+The following charts will be created:
+
+1. **UPS Charge**
+
+ * percentage changed
+
+2. **UPS Battery Voltage**
+
+ * current voltage
+ * high voltage
+ * low voltage
+ * nominal voltage
+
+3. **UPS Input Voltage**
+
+ * current voltage
+ * fault voltage
+ * nominal voltage
+
+4. **UPS Input Current**
+
+ * nominal current
+
+5. **UPS Input Frequency**
+
+ * current frequency
+ * nominal frequency
+
+6. **UPS Output Voltage**
+
+ * current voltage
+
+7. **UPS Load**
+
+ * current load
+
+8. **UPS Temperature**
+
+ * current temperature
+
+
+### configuration
+
+This is the internal default for `/etc/netdata/nut.conf`
+
+```sh
+# a space separated list of UPS names
+# if empty, the list returned by 'upsc -l' will be used
+nut_ups=
+
+# how frequently to collect UPS data
+nut_update_every=2
+```
+
+---
diff --git a/charts.d/nut.chart.sh b/collectors/charts.d.plugin/nut/nut.chart.sh
index 6137639f9..7e252f325 100644
--- a/charts.d/nut.chart.sh
+++ b/collectors/charts.d.plugin/nut/nut.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# a space separated list of UPS names
@@ -24,6 +25,7 @@ nut_clients_chart=0
nut_priority=90000
declare -A nut_ids=()
+declare -A nut_names=()
nut_get_all() {
run -t $nut_timeout upsc -l
@@ -54,16 +56,23 @@ nut_check() {
for x in $nut_ups
do
nut_get "$x" >/dev/null
+ # shellcheck disable=SC2181
if [ $? -eq 0 ]
+ then
+ if [ ! -z "${nut_names[${x}]}" ]
then
- nut_ids[$x]="$( fixid "$x" )"
+ nut_ids[$x]="$( fixid "${nut_names[${x}]}" )"
+ else
+ nut_ids[$x]="$( fixid "$x" )"
+ fi
continue
fi
error "cannot get information for NUT UPS '$x'."
done
if [ ${#nut_ids[@]} -eq 0 ]
- then
+ then
+ # shellcheck disable=SC2154
error "Cannot find UPSes - please set nut_ups='ups_name' in $confd/nut.conf"
return 1
fi
@@ -81,38 +90,41 @@ nut_create() {
CHART nut_$x.charge '' "UPS Charge" "percentage" ups nut.charge area $((nut_priority + 1)) $nut_update_every
DIMENSION battery_charge charge absolute 1 100
-CHART nut_$x.battery_voltage '' "UPS Battery Voltage" "Volts" ups nut.battery.voltage line $((nut_priority + 2)) $nut_update_every
+CHART nut_$x.runtime '' "UPS Runtime" "seconds" ups nut.runtime area $((nut_priority + 2)) $nut_update_every
+DIMENSION battery_runtime runtime absolute 1 100
+
+CHART nut_$x.battery_voltage '' "UPS Battery Voltage" "Volts" ups nut.battery.voltage line $((nut_priority + 3)) $nut_update_every
DIMENSION battery_voltage voltage absolute 1 100
DIMENSION battery_voltage_high high absolute 1 100
DIMENSION battery_voltage_low low absolute 1 100
DIMENSION battery_voltage_nominal nominal absolute 1 100
-CHART nut_$x.input_voltage '' "UPS Input Voltage" "Volts" input nut.input.voltage line $((nut_priority + 3)) $nut_update_every
+CHART nut_$x.input_voltage '' "UPS Input Voltage" "Volts" input nut.input.voltage line $((nut_priority + 4)) $nut_update_every
DIMENSION input_voltage voltage absolute 1 100
DIMENSION input_voltage_fault fault absolute 1 100
DIMENSION input_voltage_nominal nominal absolute 1 100
-CHART nut_$x.input_current '' "UPS Input Current" "Ampere" input nut.input.current line $((nut_priority + 4)) $nut_update_every
+CHART nut_$x.input_current '' "UPS Input Current" "Ampere" input nut.input.current line $((nut_priority + 5)) $nut_update_every
DIMENSION input_current_nominal nominal absolute 1 100
-CHART nut_$x.input_frequency '' "UPS Input Frequency" "Hz" input nut.input.frequency line $((nut_priority + 5)) $nut_update_every
+CHART nut_$x.input_frequency '' "UPS Input Frequency" "Hz" input nut.input.frequency line $((nut_priority + 6)) $nut_update_every
DIMENSION input_frequency frequency absolute 1 100
DIMENSION input_frequency_nominal nominal absolute 1 100
-CHART nut_$x.output_voltage '' "UPS Output Voltage" "Volts" output nut.output.voltage line $((nut_priority + 6)) $nut_update_every
+CHART nut_$x.output_voltage '' "UPS Output Voltage" "Volts" output nut.output.voltage line $((nut_priority + 7)) $nut_update_every
DIMENSION output_voltage voltage absolute 1 100
CHART nut_$x.load '' "UPS Load" "percentage" ups nut.load area $((nut_priority)) $nut_update_every
DIMENSION load load absolute 1 100
-CHART nut_$x.temp '' "UPS Temperature" "temperature" ups nut.temperature line $((nut_priority + 7)) $nut_update_every
+CHART nut_$x.temp '' "UPS Temperature" "temperature" ups nut.temperature line $((nut_priority + 8)) $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
+CHART nut_$x.clients '' "UPS Connected Clients" "clients" ups nut.clients area $((nut_priority + 9)) $nut_update_every
DIMENSION clients '' absolute 1 1
EOF2
fi
@@ -138,6 +150,7 @@ nut_update() {
nut_get "$i" | awk "
BEGIN {
battery_charge = 0;
+ battery_runtime = 0;
battery_voltage = 0;
battery_voltage_high = 0;
battery_voltage_low = 0;
@@ -155,6 +168,7 @@ BEGIN {
do_clients = ${nut_clients_chart};
}
/^battery.charge: .*/ { battery_charge = \$2 * 100 };
+/^battery.runtime: .*/ { battery_runtime = \$2 * 100 };
/^battery.voltage: .*/ { battery_voltage = \$2 * 100 };
/^battery.voltage.high: .*/ { battery_voltage_high = \$2 * 100 };
/^battery.voltage.low: .*/ { battery_voltage_low = \$2 * 100 };
@@ -174,6 +188,10 @@ END {
print \"SET battery_charge = \" battery_charge;
print \"END\"
+ print \"BEGIN nut_$x.runtime $1\";
+ print \"SET battery_runtime = \" battery_runtime;
+ print \"END\"
+
print \"BEGIN nut_$x.battery_voltage $1\";
print \"SET battery_voltage = \" battery_voltage;
print \"SET battery_voltage_high = \" battery_voltage_high;
@@ -214,7 +232,8 @@ END {
print \"END\"
}
}"
- [ $? -ne 0 ] && unset nut_ids[$i] && error "failed to get values for '$i', disabling it."
+ # shellcheck disable=2181
+ [ $? -ne 0 ] && unset "nut_ids[$i]" && error "failed to get values for '$i', disabling it."
done
[ ${#nut_ids[@]} -eq 0 ] && error "no UPSes left active." && return 1
diff --git a/conf.d/charts.d/nut.conf b/collectors/charts.d.plugin/nut/nut.conf
index d477ddd34..b95ad9048 100644
--- a/conf.d/charts.d/nut.conf
+++ b/collectors/charts.d.plugin/nut/nut.conf
@@ -9,6 +9,11 @@
# if empty, the list returned by 'upsc -l' will be used
#nut_ups=
+# each line represents an alias for one UPS
+# if empty, the FQDN will be used
+#nut_names["FQDN1"]="alias"
+#nut_names["FQDN2"]="alias"
+
# how much time in seconds, to wait for nut to respond
#nut_timeout=2
diff --git a/collectors/charts.d.plugin/opensips/Makefile.inc b/collectors/charts.d.plugin/opensips/Makefile.inc
new file mode 100644
index 000000000..a7b5d3a92
--- /dev/null
+++ b/collectors/charts.d.plugin/opensips/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += opensips/opensips.chart.sh
+dist_chartsconfig_DATA += opensips/opensips.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += opensips/README.md opensips/Makefile.inc
+
diff --git a/python.d/python_modules/bases/__init__.py b/collectors/charts.d.plugin/opensips/README.md
index e69de29bb..e69de29bb 100644
--- a/python.d/python_modules/bases/__init__.py
+++ b/collectors/charts.d.plugin/opensips/README.md
diff --git a/charts.d/opensips.chart.sh b/collectors/charts.d.plugin/opensips/opensips.chart.sh
index 2a0249dae..c227bd4f2 100644
--- a/charts.d/opensips.chart.sh
+++ b/collectors/charts.d.plugin/opensips/opensips.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash disable=SC1117,SC2154,SC2086
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
opensips_opts="fifo get_statistics all"
@@ -34,8 +35,10 @@ opensips_check() {
fi
# check once if the command works
- local x="$(opensips_get_stats | grep "^opensips_core_")"
- if [ ! $? -eq 0 -o -z "$x" ]
+ local x
+ x="$(opensips_get_stats | grep "^opensips_core_")"
+ # shellcheck disable=SC2181
+ if [ ! $? -eq 0 ] || [ -z "$x" ]
then
error "cannot get global status. Please set opensips_opts='options' whatever needed to get connected to opensips server, in $confd/opensips.conf"
return 1
@@ -218,6 +221,7 @@ opensips_update() {
opensips_command_failed=0
eval "local $(opensips_get_stats)"
+ # shellcheck disable=SC2181
[ $? -ne 0 ] && return 1
[ $opensips_command_failed -eq 1 ] && error "failed to get values, disabling." && return 1
diff --git a/conf.d/charts.d/opensips.conf b/collectors/charts.d.plugin/opensips/opensips.conf
index e25111dce..e25111dce 100644
--- a/conf.d/charts.d/opensips.conf
+++ b/collectors/charts.d.plugin/opensips/opensips.conf
diff --git a/collectors/charts.d.plugin/phpfpm/Makefile.inc b/collectors/charts.d.plugin/phpfpm/Makefile.inc
new file mode 100644
index 000000000..56bff6102
--- /dev/null
+++ b/collectors/charts.d.plugin/phpfpm/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += phpfpm/phpfpm.chart.sh
+dist_chartsconfig_DATA += phpfpm/phpfpm.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += phpfpm/README.md phpfpm/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/phpfpm/README.md b/collectors/charts.d.plugin/phpfpm/README.md
new file mode 100644
index 000000000..d82951aac
--- /dev/null
+++ b/collectors/charts.d.plugin/phpfpm/README.md
@@ -0,0 +1,2 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
diff --git a/charts.d/phpfpm.chart.sh b/collectors/charts.d.plugin/phpfpm/phpfpm.chart.sh
index a3c69b6f0..1af7910bc 100644
--- a/charts.d/phpfpm.chart.sh
+++ b/collectors/charts.d.plugin/phpfpm/phpfpm.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# Contributed by @safeie with PR #276
@@ -36,8 +37,12 @@ phpfpm_slow_requests=0
phpfpm_get() {
local opts="${1}" url="${2}"
+ # shellcheck disable=SC2207,2086
phpfpm_response=($(run curl -Ss ${opts} "${url}"))
- [ $? -ne 0 -o "${#phpfpm_response[@]}" -eq 0 ] && return 1
+ # shellcheck disable=SC2181
+ if [ $? -ne 0 ] || [ "${#phpfpm_response[@]}" -eq 0 ]; then
+ return 1
+ fi
if [[ "${phpfpm_response[0]}" != "pool:" \
|| "${phpfpm_response[2]}" != "process" \
@@ -104,9 +109,11 @@ phpfpm_check() {
for m in "${!phpfpm_urls[@]}"
do
phpfpm_get "${phpfpm_curl_opts[$m]}" "${phpfpm_urls[$m]}"
+ # shellcheck disable=SC2181
if [ $? -ne 0 ]; then
- error "cannot find status on URL '${phpfpm_url[$m]}'. Please set phpfpm_urls[$m]='http://localhost/status' in $confd/phpfpm.conf"
- unset phpfpm_urls[$m]
+ # shellcheck disable=SC2154
+ error "cannot find status on URL '${phpfpm_urls[$m]}'. Please set phpfpm_urls[$m]='http://localhost/status' in $confd/phpfpm.conf"
+ unset "phpfpm_urls[$m]"
continue
fi
done
@@ -162,6 +169,7 @@ phpfpm_update() {
for m in "${!phpfpm_urls[@]}"
do
phpfpm_get "${phpfpm_curl_opts[$m]}" "${phpfpm_urls[$m]}"
+ # shellcheck disable=SC2181
if [ $? -ne 0 ]; then
continue
fi
@@ -188,7 +196,3 @@ EOF
return 0
}
-
-phpfpm_check
-phpfpm_create
-phpfpm_update
diff --git a/conf.d/charts.d/phpfpm.conf b/collectors/charts.d.plugin/phpfpm/phpfpm.conf
index e4dd0231b..e4dd0231b 100644
--- a/conf.d/charts.d/phpfpm.conf
+++ b/collectors/charts.d.plugin/phpfpm/phpfpm.conf
diff --git a/collectors/charts.d.plugin/postfix/Makefile.inc b/collectors/charts.d.plugin/postfix/Makefile.inc
new file mode 100644
index 000000000..6e148352d
--- /dev/null
+++ b/collectors/charts.d.plugin/postfix/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += postfix/postfix.chart.sh
+dist_chartsconfig_DATA += postfix/postfix.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += postfix/README.md postfix/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/postfix/README.md b/collectors/charts.d.plugin/postfix/README.md
new file mode 100644
index 000000000..5fc265d56
--- /dev/null
+++ b/collectors/charts.d.plugin/postfix/README.md
@@ -0,0 +1,26 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
+
+# postfix
+
+The plugin will collect the postfix queue size.
+
+It will create two charts:
+
+1. **queue size in emails**
+2. **queue size in KB**
+
+### configuration
+
+This is the internal default for `/etc/netdata/postfix.conf`
+
+```sh
+# the postqueue command
+# if empty, it will use the one found in the system path
+postfix_postqueue=
+
+# how frequently to collect queue size
+postfix_update_every=15
+```
+
+---
diff --git a/charts.d/postfix.chart.sh b/collectors/charts.d.plugin/postfix/postfix.chart.sh
index 85604fcbe..8cb938ce1 100644
--- a/charts.d/postfix.chart.sh
+++ b/collectors/charts.d.plugin/postfix/postfix.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash disable=SC1117
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# the postqueue command
@@ -21,13 +22,15 @@ postfix_check() {
# - 1 to disable the chart
# try to find the postqueue executable
- if [ -z "$postfix_postqueue" -o ! -x "$postfix_postqueue" ]
+ if [ -z "$postfix_postqueue" ] || [ ! -x "$postfix_postqueue" ]
then
+ # shellcheck disable=SC2230
postfix_postqueue="$(which postqueue 2>/dev/null || command -v postqueue 2>/dev/null)"
fi
- if [ -z "$postfix_postqueue" -o ! -x "$postfix_postqueue" ]
+ if [ -z "$postfix_postqueue" ] || [ ! -x "$postfix_postqueue" ]
then
+ # shellcheck disable=SC2154
error "cannot find postqueue. Please set 'postfix_postqueue=/path/to/postqueue' in $confd/postfix.conf"
return 1
fi
@@ -67,10 +70,10 @@ postfix_update() {
postfix_q_emails=0
postfix_q_size=0
- eval "$(run $postfix_postqueue -p |\
+ eval "$(run "$postfix_postqueue" -p |\
grep "^--" |\
sed -e "s/-- \([0-9]\+\) Kbytes in \([0-9]\+\) Requests.$/local postfix_q_size=\1\nlocal postfix_q_emails=\2/g" |\
- egrep "^local postfix_q_(emails|size)=[0-9]+$")"
+ grep -E "^local postfix_q_(emails|size)=[0-9]+$")"
# write the result of the work.
cat <<VALUESEOF
diff --git a/conf.d/charts.d/postfix.conf b/collectors/charts.d.plugin/postfix/postfix.conf
index b77817bd6..b77817bd6 100644
--- a/conf.d/charts.d/postfix.conf
+++ b/collectors/charts.d.plugin/postfix/postfix.conf
diff --git a/collectors/charts.d.plugin/sensors/Makefile.inc b/collectors/charts.d.plugin/sensors/Makefile.inc
new file mode 100644
index 000000000..f466a1b62
--- /dev/null
+++ b/collectors/charts.d.plugin/sensors/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += sensors/sensors.chart.sh
+dist_chartsconfig_DATA += sensors/sensors.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += sensors/README.md sensors/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/sensors/README.md b/collectors/charts.d.plugin/sensors/README.md
new file mode 100644
index 000000000..ddc3650d6
--- /dev/null
+++ b/collectors/charts.d.plugin/sensors/README.md
@@ -0,0 +1,52 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
+
+> Unlike the python one, this module can collect temperature on RPi.
+
+# sensors
+
+The plugin will provide charts for all configured system sensors
+
+> This plugin is reading sensors directly from the kernel.
+> The `lm-sensors` package is able to perform calculations on the
+> kernel provided values, this plugin will not perform.
+> So, the values graphed, are the raw hardware values of the sensors.
+
+The plugin will create netdata charts for:
+
+1. **Temperature**
+2. **Voltage**
+3. **Current**
+4. **Power**
+5. **Fans Speed**
+6. **Energy**
+7. **Humidity**
+
+One chart for every sensor chip found and each of the above will be created.
+
+### configuration
+
+This is the internal default for `/etc/netdata/sensors.conf`
+
+```sh
+# the directory the kernel keeps sensor data
+sensors_sys_dir="${NETDATA_HOST_PREFIX}/sys/devices"
+
+# how deep in the tree to check for sensor data
+sensors_sys_depth=10
+
+# if set to 1, the script will overwrite internal
+# script functions with code generated ones
+# leave to 1, is faster
+sensors_source_update=1
+
+# how frequently to collect sensor data
+# the default is to collect it at every iteration of charts.d
+sensors_update_every=
+
+# array of sensors which are excluded
+# the default is to include all
+sensors_excluded=()
+```
+
+---
diff --git a/charts.d/sensors.chart.sh b/collectors/charts.d.plugin/sensors/sensors.chart.sh
index f21248da1..54368f1e0 100644
--- a/charts.d/sensors.chart.sh
+++ b/collectors/charts.d.plugin/sensors/sensors.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# sensors docs
@@ -32,13 +33,14 @@ sensors_priority=90000
declare -A sensors_excluded=()
sensors_find_all_files() {
- find $1 -maxdepth $sensors_sys_depth -name \*_input -o -name temp 2>/dev/null
+ find "$1" -maxdepth $sensors_sys_depth -name \*_input -o -name temp 2>/dev/null
}
sensors_find_all_dirs() {
- sensors_find_all_files $1 | while read
+ # shellcheck disable=SC2162
+ sensors_find_all_files "$1" | while read
do
- dirname $REPLY
+ dirname "$REPLY"
done | sort -u
}
@@ -49,7 +51,7 @@ sensors_check() {
# - 0 to enable the chart
# - 1 to disable the chart
- [ -z "$( sensors_find_all_files $sensors_sys_dir )" ] && error "no sensors found in '$sensors_sys_dir'." && return 1
+ [ -z "$( sensors_find_all_files "$sensors_sys_dir" )" ] && error "no sensors found in '$sensors_sys_dir'." && return 1
return 0
}
@@ -57,15 +59,15 @@ sensors_check_files() {
# we only need sensors that report a non-zero value
# also remove not needed sensors
- local f= v= excluded=
- for f in $*
+ local f v excluded
+ for f in "$@"
do
[ ! -f "$f" ] && continue
- for ex in ${sensors_excluded[@]}; do
+ for ex in "${sensors_excluded[@]}"; do
[[ $f =~ .*$ex$ ]] && excluded='1' && break
done
- [ "$excluded" != "1" ] && v="$( cat $f )" || v=0
+ [ "$excluded" != "1" ] && v="$( cat "$f" )" || v=0
v=$(( v + 1 - 1 ))
[ $v -ne 0 ] && echo "$f" && continue
excluded=
@@ -78,14 +80,15 @@ sensors_check_temp_type() {
# valid temp types are 1 to 6
# disabled sensors have the value 0
- local f= t= v=
- for f in $*
+ local f t v
+ for f in "$@"
do
- t=$( echo $f | sed "s|_input$|_type|g" )
+ # shellcheck disable=SC2001
+ t=$( echo "$f" | sed "s|_input$|_type|g" )
[ "$f" = "$t" ] && echo "$f" && continue
[ ! -f "$t" ] && echo "$f" && continue
- v="$( cat $t )"
+ v="$( cat "$t" )"
v=$(( v + 1 - 1 ))
[ $v -ne 0 ] && echo "$f" && continue
@@ -95,34 +98,34 @@ sensors_check_temp_type() {
# _create is called once, to create the charts
sensors_create() {
- local path= dir= name= x= file= lfile= labelname= labelid= device= subsystem= id= type= mode= files= multiplier= divisor=
+ local path dir name x file lfile labelname device subsystem id type mode files multiplier divisor
# we create a script with the source of the
# sensors_update() function
# - the highest speed we can achieve -
- [ $sensors_source_update -eq 1 ] && echo >$TMP_DIR/sensors.sh "sensors_update() {"
+ [ $sensors_source_update -eq 1 ] && echo >"$TMP_DIR/sensors.sh" "sensors_update() {"
- for path in $( sensors_find_all_dirs $sensors_sys_dir | sort -u )
+ for path in $( sensors_find_all_dirs "$sensors_sys_dir" | sort -u )
do
- dir=$( basename $path )
+ dir=$( basename "$path" )
device=
subsystem=
id=
type=
name=
- [ -h $path/device ] && device=$( readlink -f $path/device )
- [ ! -z "$device" ] && device=$( basename $device )
+ [ -h "$path/device" ] && device=$( readlink -f "$path/device" )
+ [ ! -z "$device" ] && device=$( basename "$device" )
[ -z "$device" ] && device="$dir"
- [ -h $path/subsystem ] && subsystem=$( readlink -f $path/subsystem )
- [ ! -z "$subsystem" ] && subsystem=$( basename $subsystem )
+ [ -h "$path/subsystem" ] && subsystem=$( readlink -f "$path/subsystem" )
+ [ ! -z "$subsystem" ] && subsystem=$( basename "$subsystem" )
[ -z "$subsystem" ] && subsystem="$dir"
- [ -f $path/name ] && name=$( cat $path/name )
+ [ -f "$path/name" ] && name=$( cat "$path/name" )
[ -z "$name" ] && name="$dir"
- [ -f $path/type ] && type=$( cat $path/type )
+ [ -f "$path/type" ] && type=$( cat "$path/type" )
[ -z "$type" ] && type="$dir"
id="$( fixid "$device.$subsystem.$dir" )"
@@ -138,66 +141,66 @@ sensors_create() {
case $mode in
temperature)
- files="$( ls $path/temp*_input 2>/dev/null; ls $path/temp 2>/dev/null )"
- files="$( sensors_check_files $files )"
- files="$( sensors_check_temp_type $files )"
+ files="$( ls "$path"/temp*_input 2>/dev/null; ls "$path/temp" 2>/dev/null )"
+ files="$( sensors_check_files "$files" )"
+ files="$( sensors_check_temp_type "$files" )"
[ -z "$files" ] && continue
echo "CHART sensors.temp_$id '' '$name Temperature' 'Celsius' 'temperature' 'sensors.temp' line $((sensors_priority + 1)) $sensors_update_every"
- echo >>$TMP_DIR/sensors.sh "echo \"BEGIN sensors.temp_$id \$1\""
+ echo >>"$TMP_DIR/sensors.sh" "echo \"BEGIN sensors.temp_$id \$1\""
divisor=1000
;;
voltage)
- files="$( ls $path/in*_input 2>/dev/null )"
- files="$( sensors_check_files $files )"
+ files="$( ls "$path"/in*_input 2>/dev/null )"
+ files="$( sensors_check_files "$files" )"
[ -z "$files" ] && continue
echo "CHART sensors.volt_$id '' '$name Voltage' 'Volts' 'voltage' 'sensors.volt' line $((sensors_priority + 2)) $sensors_update_every"
- echo >>$TMP_DIR/sensors.sh "echo \"BEGIN sensors.volt_$id \$1\""
+ echo >>"$TMP_DIR/sensors.sh" "echo \"BEGIN sensors.volt_$id \$1\""
divisor=1000
;;
current)
- files="$( ls $path/curr*_input 2>/dev/null )"
- files="$( sensors_check_files $files )"
+ files="$( ls "$path"/curr*_input 2>/dev/null )"
+ files="$( sensors_check_files "$files" )"
[ -z "$files" ] && continue
echo "CHART sensors.curr_$id '' '$name Current' 'Ampere' 'current' 'sensors.curr' line $((sensors_priority + 3)) $sensors_update_every"
- echo >>$TMP_DIR/sensors.sh "echo \"BEGIN sensors.curr_$id \$1\""
+ echo >>"$TMP_DIR/sensors.sh" "echo \"BEGIN sensors.curr_$id \$1\""
divisor=1000
;;
power)
- files="$( ls $path/power*_input 2>/dev/null )"
- files="$( sensors_check_files $files )"
+ files="$( ls "$path"/power*_input 2>/dev/null )"
+ files="$( sensors_check_files "$files" )"
[ -z "$files" ] && continue
echo "CHART sensors.power_$id '' '$name Power' 'Watt' 'power' 'sensors.power' line $((sensors_priority + 4)) $sensors_update_every"
- echo >>$TMP_DIR/sensors.sh "echo \"BEGIN sensors.power_$id \$1\""
+ echo >>"$TMP_DIR/sensors.sh" "echo \"BEGIN sensors.power_$id \$1\""
divisor=1000000
;;
fans)
- files="$( ls $path/fan*_input 2>/dev/null )"
- files="$( sensors_check_files $files )"
+ files="$( ls "$path"/fan*_input 2>/dev/null )"
+ files="$( sensors_check_files "$files" )"
[ -z "$files" ] && continue
echo "CHART sensors.fan_$id '' '$name Fans Speed' 'Rotations / Minute' 'fans' 'sensors.fans' line $((sensors_priority + 5)) $sensors_update_every"
- echo >>$TMP_DIR/sensors.sh "echo \"BEGIN sensors.fan_$id \$1\""
+ echo >>"$TMP_DIR/sensors.sh" "echo \"BEGIN sensors.fan_$id \$1\""
;;
energy)
- files="$( ls $path/energy*_input 2>/dev/null )"
- files="$( sensors_check_files $files )"
+ files="$( ls "$path"/energy*_input 2>/dev/null )"
+ files="$( sensors_check_files "$files" )"
[ -z "$files" ] && continue
echo "CHART sensors.energy_$id '' '$name Energy' 'Joule' 'energy' 'sensors.energy' areastack $((sensors_priority + 6)) $sensors_update_every"
- echo >>$TMP_DIR/sensors.sh "echo \"BEGIN sensors.energy_$id \$1\""
+ echo >>"$TMP_DIR/sensors.sh" "echo \"BEGIN sensors.energy_$id \$1\""
algorithm="incremental"
divisor=1000000
;;
humidity)
- files="$( ls $path/humidity*_input 2>/dev/null )"
- files="$( sensors_check_files $files )"
+ files="$( ls "$path"/humidity*_input 2>/dev/null )"
+ files="$( sensors_check_files "$files" )"
[ -z "$files" ] && continue
echo "CHART sensors.humidity_$id '' '$name Humidity' 'Percent' 'humidity' 'sensors.humidity' line $((sensors_priority + 7)) $sensors_update_every"
- echo >>$TMP_DIR/sensors.sh "echo \"BEGIN sensors.humidity_$id \$1\""
+ echo >>"$TMP_DIR/sensors.sh" "echo \"BEGIN sensors.humidity_$id \$1\""
divisor=1000
;;
@@ -210,26 +213,27 @@ sensors_create() {
do
file="$x"
fid="$( fixid "$file" )"
- lfile="$( basename $file | sed "s|_input$|_label|g" )"
- labelname="$( basename $file | sed "s|_input$||g" )"
+ lfile="$( basename "$file" | sed "s|_input$|_label|g" )"
+ labelname="$( basename "$file" | sed "s|_input$||g" )"
- if [ ! "$path/$lfile" = "$file" -a -f "$path/$lfile" ]
- then
+ if [ ! "$path/$lfile" = "$file" ] && [ -f "$path/$lfile" ]
+ then
labelname="$( cat "$path/$lfile" )"
fi
echo "DIMENSION $fid '$labelname' $algorithm $multiplier $divisor"
- echo >>$TMP_DIR/sensors.sh "echo \"SET $fid = \"\$(< $file )"
+ echo >>"$TMP_DIR/sensors.sh" "echo \"SET $fid = \"\$(< $file )"
done
- echo >>$TMP_DIR/sensors.sh "echo END"
+ echo >>"$TMP_DIR/sensors.sh" "echo END"
done
done
- [ $sensors_source_update -eq 1 ] && echo >>$TMP_DIR/sensors.sh "}"
+ [ $sensors_source_update -eq 1 ] && echo >>"$TMP_DIR/sensors.sh" "}"
# ok, load the function sensors_update() we created
- [ $sensors_source_update -eq 1 ] && . $TMP_DIR/sensors.sh
+ # shellcheck source=/dev/null
+ [ $sensors_source_update -eq 1 ] && . "$TMP_DIR/sensors.sh"
return 0
}
@@ -243,7 +247,8 @@ sensors_update() {
# for each dimension
# remember: KEEP IT SIMPLE AND SHORT
- [ $sensors_source_update -eq 0 ] && . $TMP_DIR/sensors.sh $1
+ # shellcheck source=/dev/null
+ [ $sensors_source_update -eq 0 ] && . "$TMP_DIR/sensors.sh" "$1"
return 0
}
diff --git a/conf.d/charts.d/sensors.conf b/collectors/charts.d.plugin/sensors/sensors.conf
index bcb28807d..bcb28807d 100644
--- a/conf.d/charts.d/sensors.conf
+++ b/collectors/charts.d.plugin/sensors/sensors.conf
diff --git a/collectors/charts.d.plugin/squid/Makefile.inc b/collectors/charts.d.plugin/squid/Makefile.inc
new file mode 100644
index 000000000..ad470d88c
--- /dev/null
+++ b/collectors/charts.d.plugin/squid/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += squid/squid.chart.sh
+dist_chartsconfig_DATA += squid/squid.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += squid/README.md squid/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/squid/README.md b/collectors/charts.d.plugin/squid/README.md
new file mode 100644
index 000000000..0934ccfcf
--- /dev/null
+++ b/collectors/charts.d.plugin/squid/README.md
@@ -0,0 +1,66 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
+
+
+# squid
+
+The plugin will monitor a squid server.
+
+It will produce 4 charts:
+
+1. **Squid Client Bandwidth** in kbps
+
+ * in
+ * out
+ * hits
+
+2. **Squid Client Requests** in requests/sec
+
+ * requests
+ * hits
+ * errors
+
+3. **Squid Server Bandwidth** in kbps
+
+ * in
+ * out
+
+4. **Squid Server Requests** in requests/sec
+
+ * requests
+ * errors
+
+### autoconfig
+
+The plugin will by itself detect squid servers running on
+localhost, on ports 3128 or 8080.
+
+It will attempt to download URLs in the form:
+
+- `cache_object://HOST:PORT/counters`
+- `/squid-internal-mgr/counters`
+
+If any succeeds, it will use this.
+
+### configuration
+
+If you need to configure it by hand, create the file
+`/etc/netdata/squid.conf` with the following variables:
+
+- `squid_host=IP` the IP of the squid host
+- `squid_port=PORT` the port the squid is listening
+- `squid_url="URL"` the URL with the statistics to be fetched from squid
+- `squid_timeout=SECONDS` how much time we should wait for squid to respond
+- `squid_update_every=SECONDS` the frequency of the data collection
+
+Example `/etc/netdata/squid.conf`:
+
+```sh
+squid_host=127.0.0.1
+squid_port=3128
+squid_url="cache_object://127.0.0.1:3128/counters"
+squid_timeout=2
+squid_update_every=5
+```
+
+---
diff --git a/charts.d/squid.chart.sh b/collectors/charts.d.plugin/squid/squid.chart.sh
index 2c19c35d5..cf5d1d78a 100644
--- a/charts.d/squid.chart.sh
+++ b/collectors/charts.d.plugin/squid/squid.chart.sh
@@ -1,21 +1,21 @@
+# shellcheck shell=bash disable=SC2154
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
squid_host=
squid_port=
squid_url=
-squid_timeout=2
squid_update_every=2
squid_priority=60000
squid_get_stats_internal() {
local host="$1" port="$2" url="$3"
- run squidclient -h $host -p $port $url
+ run squidclient -h "$host" -p "$port" "$url"
}
squid_get_stats() {
@@ -31,7 +31,7 @@ squid_autodetect() {
do
x=$(squid_get_stats_internal "$host" "$port" "$url" | grep client_http.requests)
if [ ! -z "$x" ]
- then
+ then
squid_host="$host"
squid_port="$port"
squid_url="$url"
@@ -50,14 +50,16 @@ squid_check() {
require_cmd sed || return 1
require_cmd egrep || return 1
- if [ -z "$squid_host" -o -z "$squid_port" -o -z "$squid_url" ]
- then
+ if [ -z "$squid_host" ] || [ -z "$squid_port" ] || [ -z "$squid_url" ]
+ then
squid_autodetect || return 1
fi
# check once if the url works
- local x="$(squid_get_stats | grep client_http.requests)"
- if [ ! $? -eq 0 -o -z "$x" ]
+ local x
+ x="$(squid_get_stats | grep client_http.requests)"
+ # shellcheck disable=SC2181
+ if [ ! $? -eq 0 ] || [ -z "$x" ]
then
error "cannot fetch URL '$squid_url' by connecting to $squid_host:$squid_port. Please set squid_url='url' and squid_host='host' and squid_port='port' in $confd/squid.conf"
return 1
@@ -111,9 +113,10 @@ squid_update() {
# prepare the script and always grep at the end the lines that are usefull, so that
# even if something goes wrong, no other code can be executed
+ # shellcheck disable=SC1117
eval "$(squid_get_stats |\
sed -e "s/ \+/ /g" -e "s/\./_/g" -e "s/^\([a-z0-9_]\+\) *= *\([0-9]\+\)$/local squid_\1=\2/g" |\
- egrep "^local squid_(client_http|server_all)_[a-z0-9_]+=[0-9]+$")"
+ grep -E "^local squid_(client_http|server_all)_[a-z0-9_]+=[0-9]+$")"
# write the result of the work.
cat <<VALUESEOF
diff --git a/conf.d/charts.d/squid.conf b/collectors/charts.d.plugin/squid/squid.conf
index 19e928f25..19e928f25 100644
--- a/conf.d/charts.d/squid.conf
+++ b/collectors/charts.d.plugin/squid/squid.conf
diff --git a/collectors/charts.d.plugin/tomcat/Makefile.inc b/collectors/charts.d.plugin/tomcat/Makefile.inc
new file mode 100644
index 000000000..ef05b1953
--- /dev/null
+++ b/collectors/charts.d.plugin/tomcat/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_charts_DATA += tomcat/tomcat.chart.sh
+dist_chartsconfig_DATA += tomcat/tomcat.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += tomcat/README.md tomcat/Makefile.inc
+
diff --git a/collectors/charts.d.plugin/tomcat/README.md b/collectors/charts.d.plugin/tomcat/README.md
new file mode 100644
index 000000000..d82951aac
--- /dev/null
+++ b/collectors/charts.d.plugin/tomcat/README.md
@@ -0,0 +1,2 @@
+> THIS MODULE IS OBSOLETE.
+> USE THE PYTHON ONE - IT SUPPORTS MULTIPLE JOBS AND IT IS MORE EFFICIENT
diff --git a/charts.d/tomcat.chart.sh b/collectors/charts.d.plugin/tomcat/tomcat.chart.sh
index 4ea6ae683..294487b8b 100644
--- a/charts.d/tomcat.chart.sh
+++ b/collectors/charts.d.plugin/tomcat/tomcat.chart.sh
@@ -1,9 +1,10 @@
+# shellcheck shell=bash
# no need for shebang - this file is loaded from charts.d.plugin
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
#
# Contributed by @jgeromero with PR #277
@@ -46,6 +47,7 @@ tomcat_check() {
fi
if [ -z "${tomcat_user}" ]; then
# check backwards compatibility
+ # shellcheck disable=SC2154
if [ -z "${tomcatUser}" ]; then
error "tomcat user is unset or set to the empty string"
return 1
@@ -55,6 +57,7 @@ tomcat_check() {
fi
if [ -z "${tomcat_password}" ]; then
# check backwards compatibility
+ # shellcheck disable=SC2154
if [ -z "${tomcatPassword}" ]; then
error "tomcat password is unset or set to the empty string"
return 1
@@ -65,6 +68,7 @@ tomcat_check() {
# check if we can get to tomcat's status page
tomcat_get
+ # shellcheck disable=2181
if [ $? -ne 0 ]
then
error "cannot get to status page on URL '${tomcat_url}'. Please make sure tomcat url, username and password are correct."
@@ -116,7 +120,6 @@ EOF
# _update is called continuously, to collect the values
tomcat_update() {
- local reqs net
# the first argument to this function is the microseconds since last update
# pass this parameter to the BEGIN statement (see bellow).
diff --git a/conf.d/charts.d/tomcat.conf b/collectors/charts.d.plugin/tomcat/tomcat.conf
index e9f3eefa9..e9f3eefa9 100644
--- a/conf.d/charts.d/tomcat.conf
+++ b/collectors/charts.d.plugin/tomcat/tomcat.conf
diff --git a/collectors/checks.plugin/Makefile.am b/collectors/checks.plugin/Makefile.am
new file mode 100644
index 000000000..babdcf0df
--- /dev/null
+++ b/collectors/checks.plugin/Makefile.am
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
diff --git a/collectors/checks.plugin/Makefile.in b/collectors/checks.plugin/Makefile.in
new file mode 100644
index 000000000..632125466
--- /dev/null
+++ b/collectors/checks.plugin/Makefile.in
@@ -0,0 +1,457 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors/checks.plugin
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/checks.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/checks.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+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
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/plugin_checks.c b/collectors/checks.plugin/plugin_checks.c
index b99b97d40..f8a2008a8 100644
--- a/src/plugin_checks.c
+++ b/collectors/checks.plugin/plugin_checks.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_checks.h"
#ifdef NETDATA_INTERNAL_CHECKS
@@ -27,9 +29,9 @@ void *checks_main(void *ptr) {
, NULL
, "Caller gives microseconds"
, "a million !"
- , "netdata"
- , "checks"
- , 99999
+ , "checks.plugin"
+ , ""
+ , NETDATA_CHART_PRIO_CHECKS
, localhost->rrd_update_every
, RRDSET_TYPE_LINE
);
@@ -45,9 +47,9 @@ void *checks_main(void *ptr) {
, NULL
, "Netdata calcs microseconds"
, "a million !"
- , "netdata"
- , "checks"
- , 99999
+ , "checks.plugin"
+ , ""
+ , NETDATA_CHART_PRIO_CHECKS
, localhost->rrd_update_every
, RRDSET_TYPE_LINE
);
@@ -62,9 +64,9 @@ void *checks_main(void *ptr) {
, NULL
, "Clock difference"
, "microseconds diff"
- , "netdata"
- , "checks"
- , 99999
+ , "checks.plugin"
+ , ""
+ , NETDATA_CHART_PRIO_CHECKS
, localhost->rrd_update_every
, RRDSET_TYPE_LINE
);
diff --git a/collectors/checks.plugin/plugin_checks.h b/collectors/checks.plugin/plugin_checks.h
new file mode 100644
index 000000000..93494765d
--- /dev/null
+++ b/collectors/checks.plugin/plugin_checks.h
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_PLUGIN_CHECKS_H
+#define NETDATA_PLUGIN_CHECKS_H 1
+
+#include "../../daemon/common.h"
+
+#ifdef NETDATA_INTERNAL_CHECKS
+
+#define NETDATA_PLUGIN_HOOK_CHECKS \
+ { \
+ .name = "PLUGIN[check]", \
+ .config_section = CONFIG_SECTION_PLUGINS, \
+ .config_name = "checks", \
+ .enabled = 0, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = checks_main \
+ },
+
+extern void *checks_main(void *ptr);
+
+#else // !NETDATA_INTERNAL_CHECKS
+
+#define NETDATA_PLUGIN_HOOK_CHECKS
+
+#endif // NETDATA_INTERNAL_CHECKS
+
+#endif // NETDATA_PLUGIN_CHECKS_H
diff --git a/collectors/diskspace.plugin/Makefile.am b/collectors/diskspace.plugin/Makefile.am
new file mode 100644
index 000000000..19554bed8
--- /dev/null
+++ b/collectors/diskspace.plugin/Makefile.am
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
diff --git a/collectors/diskspace.plugin/Makefile.in b/collectors/diskspace.plugin/Makefile.in
new file mode 100644
index 000000000..ceebc5455
--- /dev/null
+++ b/collectors/diskspace.plugin/Makefile.in
@@ -0,0 +1,464 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors/diskspace.plugin
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(dist_noinst_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/diskspace.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/diskspace.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+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
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/collectors/diskspace.plugin/README.md b/collectors/diskspace.plugin/README.md
new file mode 100644
index 000000000..74d6cde3c
--- /dev/null
+++ b/collectors/diskspace.plugin/README.md
@@ -0,0 +1,5 @@
+> for disks performance monitoring, see the `proc` plugin, [here](../proc.plugin/#monitoring-disks-performance-with-netdata)
+
+# diskspace.plugin
+
+This plugin monitors the disk space usage of mounted disks, under Linux.
diff --git a/src/plugin_proc_diskspace.c b/collectors/diskspace.plugin/plugin_diskspace.c
index 0a229f38e..dca7c9076 100644
--- a/src/plugin_proc_diskspace.c
+++ b/collectors/diskspace.plugin/plugin_diskspace.c
@@ -1,7 +1,11 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_diskspace.h"
+
+#define PLUGIN_DISKSPACE_NAME "diskspace.plugin"
#define DELAULT_EXCLUDED_PATHS "/proc/* /sys/* /var/run/user/* /run/user/* /snap/* /var/lib/docker/*"
-#define DEFAULT_EXCLUDED_FILESYSTEMS ""
+#define DEFAULT_EXCLUDED_FILESYSTEMS "*gvfs *gluster* *s3fs *ipfs *davfs2 *httpfs *sshfs *gdfs *moosefs fusectl"
#define CONFIG_SECTION_DISKSPACE "plugin:proc:diskspace"
static struct mountinfo *disk_mountinfo_root = NULL;
@@ -129,7 +133,8 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
}
// check if the mount point is a directory #2407
- {
+ // but only when it is enabled by default #4491
+ if(def_space != CONFIG_BOOLEAN_NO || def_inodes != CONFIG_BOOLEAN_NO) {
struct stat bs;
if(stat(mi->mount_point, &bs) == -1) {
error("DISKSPACE: Cannot stat() mount point '%s' (disk '%s', filesystem '%s', root '%s')."
@@ -259,9 +264,9 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
, "disk.space"
, title
, "GB"
- , "diskspace"
+ , PLUGIN_DISKSPACE_NAME
, NULL
- , 2023
+ , NETDATA_CHART_PRIO_DISKSPACE_SPACE
, update_every
, RRDSET_TYPE_STACKED
);
@@ -299,9 +304,9 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
, "disk.inodes"
, title
, "Inodes"
- , "diskspace"
+ , PLUGIN_DISKSPACE_NAME
, NULL
- , 2024
+ , NETDATA_CHART_PRIO_DISKSPACE_INODES
, update_every
, RRDSET_TYPE_STACKED
);
@@ -337,7 +342,7 @@ static void diskspace_main_cleanup(void *ptr) {
static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
}
-void *proc_diskspace_main(void *ptr) {
+void *diskspace_main(void *ptr) {
netdata_thread_cleanup_push(diskspace_main_cleanup, ptr);
int vdo_cpu_netdata = config_get_boolean("plugin:proc", "netdata server resources", 1);
@@ -359,7 +364,7 @@ void *proc_diskspace_main(void *ptr) {
heartbeat_t hb;
heartbeat_init(&hb);
while(!netdata_exit) {
- duration = heartbeat_dt_usec(&hb);
+ duration = heartbeat_monotonic_dt_to_now_usec(&hb);
/* usec_t hb_dt = */ heartbeat_next(&hb, step);
if(unlikely(netdata_exit)) break;
@@ -406,9 +411,9 @@ void *proc_diskspace_main(void *ptr) {
, NULL
, "NetData Disk Space Plugin CPU usage"
, "milliseconds/s"
- , "diskspace"
+ , PLUGIN_DISKSPACE_NAME
, NULL
- , 132020
+ , NETDATA_CHART_PRIO_NETDATA_DISKSPACE
, update_every
, RRDSET_TYPE_STACKED
);
@@ -434,7 +439,7 @@ void *proc_diskspace_main(void *ptr) {
, NULL
, "NetData Disk Space Plugin Duration"
, "milliseconds/run"
- , "diskspace"
+ , PLUGIN_DISKSPACE_NAME
, NULL
, 132021
, update_every
diff --git a/collectors/diskspace.plugin/plugin_diskspace.h b/collectors/diskspace.plugin/plugin_diskspace.h
new file mode 100644
index 000000000..7c9df9d13
--- /dev/null
+++ b/collectors/diskspace.plugin/plugin_diskspace.h
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_PLUGIN_PROC_DISKSPACE_H
+#define NETDATA_PLUGIN_PROC_DISKSPACE_H
+
+#include "../../daemon/common.h"
+
+
+#if (TARGET_OS == OS_LINUX)
+
+#define NETDATA_PLUGIN_HOOK_LINUX_DISKSPACE \
+ { \
+ .name = "PLUGIN[diskspace]", \
+ .config_section = CONFIG_SECTION_PLUGINS, \
+ .config_name = "diskspace", \
+ .enabled = 1, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = diskspace_main \
+ },
+
+extern void *diskspace_main(void *ptr);
+
+#include "../proc.plugin/plugin_proc.h"
+
+#else // (TARGET_OS == OS_LINUX)
+
+#define NETDATA_PLUGIN_HOOK_LINUX_DISKSPACE
+
+#endif // (TARGET_OS == OS_LINUX)
+
+
+
+#endif //NETDATA_PLUGIN_PROC_DISKSPACE_H
diff --git a/collectors/fping.plugin/Makefile.am b/collectors/fping.plugin/Makefile.am
new file mode 100644
index 000000000..4395394db
--- /dev/null
+++ b/collectors/fping.plugin/Makefile.am
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+CLEANFILES = \
+ fping.plugin \
+ $(NULL)
+
+include $(top_srcdir)/build/subst.inc
+SUFFIXES = .in
+
+dist_plugins_SCRIPTS = \
+ fping.plugin \
+ $(NULL)
+
+dist_noinst_DATA = \
+ fping.plugin.in \
+ README.md \
+ $(NULL)
+
+dist_libconfig_DATA = \
+ fping.conf \
+ $(NULL)
diff --git a/plugins.d/Makefile.in b/collectors/fping.plugin/Makefile.in
index 059d68f6a..67b9699b7 100644
--- a/plugins.d/Makefile.in
+++ b/collectors/fping.plugin/Makefile.in
@@ -14,6 +14,8 @@
@SET_MAKE@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
@@ -79,18 +81,21 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-subdir = plugins.d
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
- $(dist_plugins_SCRIPTS) $(dist_plugins_DATA)
+DIST_COMMON = $(top_srcdir)/build/subst.inc $(srcdir)/Makefile.in \
+ $(srcdir)/Makefile.am $(dist_plugins_SCRIPTS) \
+ $(dist_libconfig_DATA) $(dist_noinst_DATA)
+subdir = collectors/fping.plugin
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
- $(top_srcdir)/m4/ax_c_mallinfo.m4 \
- $(top_srcdir)/m4/ax_c_mallopt.m4 \
- $(top_srcdir)/m4/ax_check_compile_flag.m4 \
- $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
- $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/jemalloc.m4 \
- $(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
@@ -124,7 +129,8 @@ am__uninstall_files_from_dir = { \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
-am__installdirs = "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(pluginsdir)"
+am__installdirs = "$(DESTDIR)$(pluginsdir)" \
+ "$(DESTDIR)$(libconfigdir)"
SCRIPTS = $(dist_plugins_SCRIPTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -145,7 +151,7 @@ am__can_run_installinfo = \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
-DATA = $(dist_plugins_DATA)
+DATA = $(dist_libconfig_DATA) $(dist_noinst_DATA)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
@@ -245,6 +251,7 @@ build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
+build_target = @build_target@
build_vendor = @build_vendor@
builddir = @builddir@
cachedir = @cachedir@
@@ -266,6 +273,7 @@ htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
+libconfigdir = @libconfigdir@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
@@ -292,34 +300,31 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
varlibdir = @varlibdir@
webdir = @webdir@
-
-#
-# Copyright (C) 2015 Alon Bar-Lev <alon.barlev@gmail.com>
-#
+AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
-dist_plugins_DATA = \
- README.md \
+CLEANFILES = \
+ fping.plugin \
$(NULL)
+SUFFIXES = .in
dist_plugins_SCRIPTS = \
- alarm-email.sh \
- alarm-notify.sh \
- alarm-test.sh \
- cgroup-name.sh \
- cgroup-network-helper.sh \
- charts.d.dryrun-helper.sh \
- charts.d.plugin \
fping.plugin \
- node.d.plugin \
- python.d.plugin \
- tc-qos-helper.sh \
- loopsleepms.sh.inc \
$(NULL)
+dist_noinst_DATA = \
+ fping.plugin.in \
+ README.md \
+ $(NULL)
+
+dist_libconfig_DATA = \
+ fping.conf \
+ $(NULL)
+
all: all-am
.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+.SUFFIXES: .in
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/build/subst.inc $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -328,9 +333,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
exit 1;; \
esac; \
done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plugins.d/Makefile'; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/fping.plugin/Makefile'; \
$(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --gnu plugins.d/Makefile
+ $(AUTOMAKE) --gnu collectors/fping.plugin/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
@@ -340,6 +345,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:
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
@@ -384,27 +390,27 @@ uninstall-dist_pluginsSCRIPTS:
files=`for p in $$list; do echo "$$p"; done | \
sed -e 's,.*/,,;$(transform)'`; \
dir='$(DESTDIR)$(pluginsdir)'; $(am__uninstall_files_from_dir)
-install-dist_pluginsDATA: $(dist_plugins_DATA)
+install-dist_libconfigDATA: $(dist_libconfig_DATA)
@$(NORMAL_INSTALL)
- @list='$(dist_plugins_DATA)'; test -n "$(pluginsdir)" || list=; \
+ @list='$(dist_libconfig_DATA)'; test -n "$(libconfigdir)" || list=; \
if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(pluginsdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(pluginsdir)" || exit 1; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libconfigdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pluginsdir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(pluginsdir)" || exit $$?; \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(libconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(libconfigdir)" || exit $$?; \
done
-uninstall-dist_pluginsDATA:
+uninstall-dist_libconfigDATA:
@$(NORMAL_UNINSTALL)
- @list='$(dist_plugins_DATA)'; test -n "$(pluginsdir)" || list=; \
+ @list='$(dist_libconfig_DATA)'; test -n "$(libconfigdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- dir='$(DESTDIR)$(pluginsdir)'; $(am__uninstall_files_from_dir)
+ dir='$(DESTDIR)$(libconfigdir)'; $(am__uninstall_files_from_dir)
tags TAGS:
ctags CTAGS:
@@ -446,7 +452,7 @@ check-am: all-am
check: check-am
all-am: Makefile $(SCRIPTS) $(DATA)
installdirs:
- for dir in "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(pluginsdir)"; do \
+ for dir in "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(libconfigdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -471,6 +477,7 @@ install-strip:
mostlyclean-generic:
clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -500,7 +507,8 @@ info: info-am
info-am:
-install-data-am: install-dist_pluginsDATA install-dist_pluginsSCRIPTS
+install-data-am: install-dist_libconfigDATA \
+ install-dist_pluginsSCRIPTS
install-dvi: install-dvi-am
@@ -544,14 +552,15 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-dist_pluginsDATA uninstall-dist_pluginsSCRIPTS
+uninstall-am: uninstall-dist_libconfigDATA \
+ 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-data-am install-dist_libconfigDATA \
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 \
@@ -559,8 +568,23 @@ uninstall-am: uninstall-dist_pluginsDATA uninstall-dist_pluginsSCRIPTS
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
-
+ uninstall-dist_libconfigDATA uninstall-dist_pluginsSCRIPTS
+
+.in:
+ if sed \
+ -e 's#[@]localstatedir_POST@#$(localstatedir)#g' \
+ -e 's#[@]sbindir_POST@#$(sbindir)#g' \
+ -e 's#[@]sysconfdir_POST@#$(sysconfdir)#g' \
+ -e 's#[@]pythondir_POST@#$(pythondir)#g' \
+ -e 's#[@]configdir_POST@#$(configdir)#g' \
+ -e 's#[@]libconfigdir_POST@#$(libconfigdir)#g' \
+ -e 's#[@]cachedir_POST@#$(cachedir)#g' \
+ $< > $@.tmp; then \
+ mv "$@.tmp" "$@"; \
+ else \
+ rm -f "$@.tmp"; \
+ false; \
+ 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/collectors/fping.plugin/README.md b/collectors/fping.plugin/README.md
new file mode 100644
index 000000000..0554a7edc
--- /dev/null
+++ b/collectors/fping.plugin/README.md
@@ -0,0 +1,96 @@
+# fping.plugin
+
+The fping plugin supports monitoring latency, packet loss and uptime of any number of network end points,
+by pinging them with `fping`.
+
+A recent version of `fping` is required (one that supports option ` -N `).
+The supplied plugin can install it, by running:
+
+```sh
+/usr/libexec/netdata/plugins.d/fping.plugin install
+```
+
+The above will download, build and install the right version as `/usr/local/bin/fping`.
+
+Then you need to edit `/etc/netdata/fping.conf` (to edit it on your system run
+`/etc/netdata/edit-config fping.conf`) like this:
+
+```sh
+# uncomment the following line - it should already be there
+fping="/usr/local/bin/fping"
+
+# set here all the hosts you need to ping
+# I suggest to use hostnames and put their IPs in /etc/hosts
+hosts="host1 host2 host3"
+
+# override the chart update frequency - the default is inherited from netdata
+update_every=1
+
+# time in milliseconds (1 sec = 1000 ms) to ping the hosts
+# 200 = 5 pings per second
+ping_every=200
+
+# other fping options - these are the defaults
+fping_opts="-R -b 56 -i 1 -r 0 -t 5000"
+```
+
+## alarms
+
+netdata will automatically attach a few alarms for each host.
+Check the [latest versions of the fping alarms](https://github.com/netdata/netdata/blob/master/health/health.d/fping.conf)
+
+## Additional Tips
+
+### Customizing Amount of Pings Per Second
+
+For example, to update the chart every 10 seconds and use 2 pings every 10 seconds, use this:
+
+```sh
+# Chart Update Frequency (Time in Seconds)
+update_every=10
+
+# Time in Milliseconds (1 sec = 1000 ms) to Ping the Hosts
+# The Following Example Sends 1 Ping Every 5000 ms
+# Calculation Formula: ping_every = (update_every * 1000 ) / 2
+ping_every=5000
+```
+
+### Multiple fping Plugins With Different Settings
+
+You may need to run multiple fping plugins with different settings for different end points.
+For example, you may need to ping a few hosts 10 times per second, and others once per second.
+
+netdata allows you to add as many `fping` plugins as you like.
+
+Follow this procedure:
+
+**1. Create New fping Configuration File**
+
+
+```sh
+# Step Into Configuration Directory
+cd /etc/netdata
+
+# Copy Original fping Configuration File To New Configuration File
+cp fping.conf fping2.conf
+```
+
+Edit `fping2.conf` and set the settings and the hosts you need for the seconds instance.
+
+**2. Soft Link Original fping Plugin to New Plugin File**
+
+```sh
+# Become root (If The Step Step Is Performed As Non-Root User)
+sudo su
+
+# Step Into The Plugins Directory
+cd /usr/libexec/netdata/plugins.d
+
+# Link fping.plugin to fping2.plugin
+ln -s fping.plugin fping2.plugin
+```
+
+That's it. netdata will detect the new plugin and start it.
+
+You can name the new plugin any name you like.
+Just make sure the plugin and the configuration file have the same name.
diff --git a/conf.d/fping.conf b/collectors/fping.plugin/fping.conf
index 63a7f7acd..63a7f7acd 100644
--- a/conf.d/fping.conf
+++ b/collectors/fping.plugin/fping.conf
diff --git a/plugins.d/fping.plugin b/collectors/fping.plugin/fping.plugin
index f38a8dde0..cf8f17e9a 100755..100644
--- a/plugins.d/fping.plugin
+++ b/collectors/fping.plugin/fping.plugin
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-3.0-or-later
# netdata
# real-time performance and health monitoring, done right!
@@ -129,7 +130,8 @@ update_every="${1-1}"
# the netdata configuration directory
# passed by netdata as an environment variable
-[ -z "${NETDATA_CONFIG_DIR}" ] && NETDATA_CONFIG_DIR="$(dirname "${0}")/../../../../etc/netdata"
+[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="/usr/local/etc/netdata"
+[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="/usr/local/lib/netdata/conf.d"
# -----------------------------------------------------------------------------
# configuration options
@@ -152,23 +154,33 @@ ping_every="$((update_every * 1000 / 5))"
fping_opts="-R -b 56 -i 1 -r 0 -t 5000"
# -----------------------------------------------------------------------------
-# load the configuration file
+# load the configuration files
-if [ ! -f "${NETDATA_CONFIG_DIR}/${plugin}.conf" ]
+for CONFIG in "${NETDATA_STOCK_CONFIG_DIR}/${plugin}.conf" "${NETDATA_USER_CONFIG_DIR}/${plugin}.conf"
+do
+ if [ -f "${CONFIG}" ]
+ then
+ info "Loading config file '${CONFIG}'..."
+ source "${CONFIG}"
+ [ $? -ne 0 ] && error "Failed to load config file '${CONFIG}'."
+ else
+ warning "Cannot find file '${CONFIG}'."
+ fi
+done
+
+if [ -z "${hosts}" ]
then
- fatal "configuration file '${NETDATA_CONFIG_DIR}/${plugin}.conf' not found - nothing to do."
+ fatal "no hosts configured - nothing to do."
fi
-source "${NETDATA_CONFIG_DIR}/${plugin}.conf"
-
-if [ -z "${hosts}" ]
+if [ -z "${fping}" ]
then
- fatal "no hosts configured in '${NETDATA_CONFIG_DIR}/${plugin}.conf' - nothing to do."
+ fatal "fping command is not found. Please set its full path in '${NETDATA_USER_CONFIG_DIR}/${plugin}.conf'"
fi
-if [ -z "${fping}" -o ! -x "${fping}" ]
+if [ ! -x "${fping}" ]
then
- fatal "command '${fping}' is not found or is not executable - cannot proceed."
+ fatal "fping command '${fping}' is not executable - cannot proceed."
fi
if [ ${ping_every} -lt 20 ]
@@ -185,4 +197,4 @@ info "starting fping: ${fping} ${options[*]}"
exec "${fping}" "${options[@]}"
# if we cannot execute fping, stop
-fatal "command '${fping} ${options[@]}' failed to be executed."
+fatal "command '${fping} ${options[*]}' failed to be executed (returned code $?)."
diff --git a/collectors/fping.plugin/fping.plugin.in b/collectors/fping.plugin/fping.plugin.in
new file mode 100755
index 000000000..2c03e418e
--- /dev/null
+++ b/collectors/fping.plugin/fping.plugin.in
@@ -0,0 +1,200 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# netdata
+# real-time performance and health monitoring, done right!
+# (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
+# GPL v3+
+#
+# This plugin requires a latest version of fping.
+# You can compile it from source, by running me with option: install
+
+export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin"
+export LC_ALL=C
+
+if [ "${1}" = "install" ]
+ then
+ [ "${UID}" != 0 ] && echo >&2 "Please run me as root. This will install a single binary file: /usr/local/bin/fping." && exit 1
+
+ run() {
+ printf >&2 " > "
+ printf >&2 "%q " "${@}"
+ printf >&2 "\n"
+ "${@}" || 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-4.0 ]
+ then
+ run rm -rf fping-4.0 || exit 1
+ fi
+
+ download 'https://github.com/schweikert/fping/releases/download/v4.0/fping-4.0.tar.gz' | run tar -zxvpf -
+ [ $? -ne 0 ] && exit 1
+ run cd fping-4.0 || exit 1
+
+ run ./configure --prefix=/usr/local
+ run make clean
+ run make
+ if [ -f /usr/local/bin/fping ]
+ then
+ run mv -f /usr/local/bin/fping /usr/local/bin/fping.old
+ fi
+ run mv src/fping /usr/local/bin/fping
+ run chown root:root /usr/local/bin/fping
+ run chmod 4755 /usr/local/bin/fping
+ echo >&2
+ echo >&2 "All done, you have a compatible fping now at /usr/local/bin/fping."
+ echo >&2
+
+ fping="$(which fping 2>/dev/null || command -v fping 2>/dev/null)"
+ if [ "${fping}" != "/usr/local/bin/fping" ]
+ then
+ echo >&2 "You have another fping installed at: ${fping}."
+ echo >&2 "Please set:"
+ echo >&2
+ echo >&2 " fping=\"/usr/local/bin/fping\""
+ echo >&2
+ echo >&2 "at /etc/netdata/fping.conf"
+ echo >&2
+ fi
+ exit 0
+fi
+
+# -----------------------------------------------------------------------------
+
+PROGRAM_NAME="$(basename "${0}")"
+
+logdate() {
+ date "+%Y-%m-%d %H:%M:%S"
+}
+
+log() {
+ local status="${1}"
+ shift
+
+ echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}"
+
+}
+
+warning() {
+ log WARNING "${@}"
+}
+
+error() {
+ log ERROR "${@}"
+}
+
+info() {
+ log INFO "${@}"
+}
+
+fatal() {
+ log FATAL "${@}"
+ echo "DISABLE"
+ exit 1
+}
+
+debug=0
+debug() {
+ [ $debug -eq 1 ] && log DEBUG "${@}"
+}
+
+# -----------------------------------------------------------------------------
+
+# store in ${plugin} the name we run under
+# this allows us to copy/link fping.plugin under a different name
+# to have multiple fping plugins running with different settings
+plugin="${PROGRAM_NAME/.plugin/}"
+
+
+# -----------------------------------------------------------------------------
+
+# the frequency to send info to netdata
+# passed by netdata as the first parameter
+update_every="${1-1}"
+
+# the netdata configuration directory
+# passed by netdata as an environment variable
+[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@"
+[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="@libconfigdir_POST@"
+
+# -----------------------------------------------------------------------------
+# configuration options
+# can be overwritten at /etc/netdata/fping.conf
+
+# the fping binary to use
+# we need one that can output netdata friendly info (supporting: -N)
+# if you have multiple versions, put here the full filename of the right one
+fping="$( which fping 2>/dev/null || command -v fping 2>/dev/null )"
+
+# a space separated list of hosts to fping
+# we suggest to put names here and the IPs of these names in /etc/hosts
+hosts=""
+
+# the time in milliseconds (1 sec = 1000 ms)
+# to ping the hosts - by default 5 pings per host per iteration
+ping_every="$((update_every * 1000 / 5))"
+
+# fping options
+fping_opts="-R -b 56 -i 1 -r 0 -t 5000"
+
+# -----------------------------------------------------------------------------
+# load the configuration files
+
+for CONFIG in "${NETDATA_STOCK_CONFIG_DIR}/${plugin}.conf" "${NETDATA_USER_CONFIG_DIR}/${plugin}.conf"
+do
+ if [ -f "${CONFIG}" ]
+ then
+ info "Loading config file '${CONFIG}'..."
+ source "${CONFIG}"
+ [ $? -ne 0 ] && error "Failed to load config file '${CONFIG}'."
+ else
+ warning "Cannot find file '${CONFIG}'."
+ fi
+done
+
+if [ -z "${hosts}" ]
+then
+ fatal "no hosts configured - nothing to do."
+fi
+
+if [ -z "${fping}" ]
+then
+ fatal "fping command is not found. Please set its full path in '${NETDATA_USER_CONFIG_DIR}/${plugin}.conf'"
+fi
+
+if [ ! -x "${fping}" ]
+then
+ fatal "fping command '${fping}' is not executable - cannot proceed."
+fi
+
+if [ ${ping_every} -lt 20 ]
+ then
+ warning "ping every was set to ${ping_every} but 20 is the minimum for non-root users. Setting it to 20 ms."
+ ping_every=20
+fi
+
+# the fping options we will use
+options=( -N -l -Q ${update_every} -p ${ping_every} ${fping_opts} ${hosts} )
+
+# execute fping
+info "starting fping: ${fping} ${options[*]}"
+exec "${fping}" "${options[@]}"
+
+# if we cannot execute fping, stop
+fatal "command '${fping} ${options[*]}' failed to be executed (returned code $?)."
diff --git a/collectors/freebsd.plugin/Makefile.am b/collectors/freebsd.plugin/Makefile.am
new file mode 100644
index 000000000..e80ec702d
--- /dev/null
+++ b/collectors/freebsd.plugin/Makefile.am
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
diff --git a/collectors/freebsd.plugin/Makefile.in b/collectors/freebsd.plugin/Makefile.in
new file mode 100644
index 000000000..c88b3d755
--- /dev/null
+++ b/collectors/freebsd.plugin/Makefile.in
@@ -0,0 +1,457 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors/freebsd.plugin
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/freebsd.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/freebsd.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+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
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/freebsd_devstat.c b/collectors/freebsd.plugin/freebsd_devstat.c
index ed7466ead..10279aabc 100644
--- a/src/freebsd_devstat.c
+++ b/collectors/freebsd.plugin/freebsd_devstat.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_freebsd.h"
#include <sys/devicestat.h>
@@ -359,9 +361,9 @@ int do_kern_devstat(int update_every, usec_t dt) {
"disk.io",
"Disk I/O Bandwidth",
"kilobytes/s",
- "freebsd",
+ "freebsd.plugin",
"devstat",
- 2000,
+ NETDATA_CHART_PRIO_DISK_IO,
update_every,
RRDSET_TYPE_AREA
);
@@ -396,9 +398,9 @@ int do_kern_devstat(int update_every, usec_t dt) {
"disk.ops",
"Disk Completed I/O Operations",
"operations/s",
- "freebsd",
+ "freebsd.plugin",
"devstat",
- 2001,
+ NETDATA_CHART_PRIO_DISK_OPS,
update_every,
RRDSET_TYPE_LINE
);
@@ -435,9 +437,9 @@ int do_kern_devstat(int update_every, usec_t dt) {
"disk.qops",
"Disk Current I/O Operations",
"operations",
- "freebsd",
+ "freebsd.plugin",
"devstat",
- 2002,
+ NETDATA_CHART_PRIO_DISK_QOPS,
update_every,
RRDSET_TYPE_LINE
);
@@ -464,9 +466,9 @@ int do_kern_devstat(int update_every, usec_t dt) {
"disk.util",
"Disk Utilization Time",
"% of time working",
- "freebsd",
+ "freebsd.plugin",
"devstat",
- 2004,
+ NETDATA_CHART_PRIO_DISK_UTIL,
update_every,
RRDSET_TYPE_AREA
);
@@ -497,9 +499,9 @@ int do_kern_devstat(int update_every, usec_t dt) {
"disk.iotime",
"Disk Total I/O Time",
"milliseconds/s",
- "freebsd",
+ "freebsd.plugin",
"devstat",
- 2022,
+ NETDATA_CHART_PRIO_DISK_IOTIME,
update_every,
RRDSET_TYPE_LINE
);
@@ -545,9 +547,9 @@ int do_kern_devstat(int update_every, usec_t dt) {
"disk.await",
"Average Completed I/O Operation Time",
"ms per operation",
- "freebsd",
+ "freebsd.plugin",
"devstat",
- 2005,
+ NETDATA_CHART_PRIO_DISK_AWAIT,
update_every,
RRDSET_TYPE_LINE
);
@@ -610,9 +612,9 @@ int do_kern_devstat(int update_every, usec_t dt) {
"disk.avgsz",
"Average Completed I/O Operation Bandwidth",
"kilobytes per operation",
- "freebsd",
+ "freebsd.plugin",
"devstat",
- 2006,
+ NETDATA_CHART_PRIO_DISK_AVGSZ,
update_every,
RRDSET_TYPE_AREA
);
@@ -667,9 +669,9 @@ int do_kern_devstat(int update_every, usec_t dt) {
"disk.svctm",
"Average Service Time",
"ms per operation",
- "freebsd",
+ "freebsd.plugin",
"devstat",
- 2007,
+ NETDATA_CHART_PRIO_DISK_SVCTM,
update_every,
RRDSET_TYPE_LINE
);
@@ -727,9 +729,9 @@ int do_kern_devstat(int update_every, usec_t dt) {
NULL,
"Disk I/O",
"kilobytes/s",
- "freebsd",
+ "freebsd.plugin",
"devstat",
- 150,
+ NETDATA_CHART_PRIO_SYSTEM_IO,
update_every,
RRDSET_TYPE_AREA
);
diff --git a/src/freebsd_getifaddrs.c b/collectors/freebsd.plugin/freebsd_getifaddrs.c
index 73f8f1824..e15845857 100644
--- a/src/freebsd_getifaddrs.c
+++ b/collectors/freebsd.plugin/freebsd_getifaddrs.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_freebsd.h"
#include <ifaddrs.h>
@@ -141,19 +143,24 @@ static struct cgroup_network_interface *get_network_interface(const char *name)
int do_getifaddrs(int update_every, usec_t dt) {
(void)dt;
-#define DELAULT_EXLUDED_INTERFACES "lo*"
+#define DEFAULT_EXLUDED_INTERFACES "lo*"
+#define DEFAULT_PHYSICAL_INTERFACES "igb* ix* cxl* em* ixl* ixlv* bge* ixgbe*"
#define CONFIG_SECTION_GETIFADDRS "plugin:freebsd:getifaddrs"
static int enable_new_interfaces = -1;
- static int do_bandwidth_ipv4 = -1, do_bandwidth_ipv6 = -1, do_bandwidth = -1, do_packets = -1,
+ static int do_bandwidth_ipv4 = -1, do_bandwidth_ipv6 = -1, do_bandwidth = -1, do_packets = -1, do_bandwidth_net = -1, do_packets_net = -1,
do_errors = -1, do_drops = -1, do_events = -1;
- static SIMPLE_PATTERN *excluded_interfaces = NULL;
+ static SIMPLE_PATTERN *excluded_interfaces = NULL, *physical_interfaces = NULL;
if (unlikely(enable_new_interfaces == -1)) {
enable_new_interfaces = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS,
"enable new interfaces detected at runtime",
CONFIG_BOOLEAN_AUTO);
-
+
+ do_bandwidth_net = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for physical interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_packets_net = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total packets for physical interfaces",
+ CONFIG_BOOLEAN_AUTO);
do_bandwidth_ipv4 = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for ipv4 interfaces",
CONFIG_BOOLEAN_AUTO);
do_bandwidth_ipv6 = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for ipv6 interfaces",
@@ -170,18 +177,27 @@ int do_getifaddrs(int update_every, usec_t dt) {
CONFIG_BOOLEAN_AUTO);
excluded_interfaces = simple_pattern_create(
- config_get(CONFIG_SECTION_GETIFADDRS, "disable by default interfaces matching", DELAULT_EXLUDED_INTERFACES)
+ config_get(CONFIG_SECTION_GETIFADDRS, "disable by default interfaces matching", DEFAULT_EXLUDED_INTERFACES)
+ , NULL
+ , SIMPLE_PATTERN_EXACT
+ );
+ physical_interfaces = simple_pattern_create(
+ config_get(CONFIG_SECTION_GETIFADDRS, "set physical interfaces for system.net", DEFAULT_PHYSICAL_INTERFACES)
, NULL
, SIMPLE_PATTERN_EXACT
);
}
- if (likely(do_bandwidth_ipv4 || do_bandwidth_ipv6 || do_bandwidth || do_packets || do_errors ||
+ if (likely(do_bandwidth_ipv4 || do_bandwidth_ipv6 || do_bandwidth || do_packets || do_errors || do_bandwidth_net || do_packets_net ||
do_drops || do_events)) {
struct ifaddrs *ifap;
if (unlikely(getifaddrs(&ifap))) {
error("FREEBSD: getifaddrs() failed");
+ do_bandwidth_net = 0;
+ error("DISABLED: system.net chart");
+ do_packets_net = 0;
+ error("DISABLED: system.packets chart");
do_bandwidth_ipv4 = 0;
error("DISABLED: system.ipv4 chart");
do_bandwidth_ipv6 = 0;
@@ -204,7 +220,103 @@ int do_getifaddrs(int update_every, usec_t dt) {
struct iftot {
u_long ift_ibytes;
u_long ift_obytes;
- } iftot = {0, 0};
+ u_long ift_ipackets;
+ u_long ift_opackets;
+ u_long ift_imcasts;
+ u_long ift_omcasts;
+ } iftot = {0, 0, 0, 0, 0, 0};
+
+ // --------------------------------------------------------------------
+
+ if (likely(do_bandwidth_net)) {
+
+ iftot.ift_ibytes = iftot.ift_obytes = 0;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ if (!simple_pattern_matches(physical_interfaces, ifa->ifa_name))
+ 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",
+ "net",
+ NULL,
+ "network",
+ NULL,
+ "Network Traffic",
+ "kilobits/s",
+ "freebsd.plugin",
+ "getifaddrs",
+ NETDATA_CHART_PRIO_SYSTEM_NET,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_in = rrddim_add(st, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_in, iftot.ift_ibytes);
+ rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes);
+ rrdset_done(st);
+ }
+
+ // --------------------------------------------------------------------
+
+ if (likely(do_packets_net)) {
+
+ iftot.ift_ipackets = iftot.ift_opackets = iftot.ift_imcasts = iftot.ift_omcasts = 0;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ if (!simple_pattern_matches(physical_interfaces, ifa->ifa_name))
+ continue;
+ iftot.ift_ipackets += IFA_DATA(ipackets);
+ iftot.ift_opackets += IFA_DATA(opackets);
+ iftot.ift_imcasts += IFA_DATA(imcasts);
+ iftot.ift_omcasts += IFA_DATA(omcasts);
+ }
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_packets_in = NULL, *rd_packets_out = NULL, *rd_packets_m_in = NULL, *rd_packets_m_out = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "packets",
+ NULL,
+ "network",
+ NULL,
+ "Network Packets",
+ "packets/s",
+ "freebsd.plugin",
+ "getifaddrs",
+ NETDATA_CHART_PRIO_SYSTEM_PACKETS,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_packets_in = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_packets_out = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_packets_m_in = rrddim_add(st, "multicast_received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_packets_m_out = rrddim_add(st, "multicast_sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_packets_in, iftot.ift_ipackets);
+ rrddim_set_by_pointer(st, rd_packets_out, iftot.ift_opackets);
+ rrddim_set_by_pointer(st, rd_packets_m_in, iftot.ift_imcasts);
+ rrddim_set_by_pointer(st, rd_packets_m_out, iftot.ift_omcasts);
+ rrdset_done(st);
+ }
// --------------------------------------------------------------------
@@ -228,9 +340,9 @@ int do_getifaddrs(int update_every, usec_t dt) {
NULL,
"IPv4 Bandwidth",
"kilobits/s",
- "freebsd",
+ "freebsd.plugin",
"getifaddrs",
- 500,
+ NETDATA_CHART_PRIO_SYSTEM_IPV4,
update_every,
RRDSET_TYPE_AREA
);
@@ -267,9 +379,9 @@ int do_getifaddrs(int update_every, usec_t dt) {
NULL,
"IPv6 Bandwidth",
"kilobits/s",
- "freebsd",
+ "freebsd.plugin",
"getifaddrs",
- 500,
+ NETDATA_CHART_PRIO_SYSTEM_IPV6,
update_every,
RRDSET_TYPE_AREA
);
@@ -337,9 +449,9 @@ int do_getifaddrs(int update_every, usec_t dt) {
"net.net",
"Bandwidth",
"kilobits/s",
- "freebsd",
+ "freebsd.plugin",
"getifaddrs",
- 7000,
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE,
update_every,
RRDSET_TYPE_AREA
);
@@ -366,9 +478,9 @@ int do_getifaddrs(int update_every, usec_t dt) {
"net.packets",
"Packets",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"getifaddrs",
- 7001,
+ NETDATA_CHART_PRIO_FIRST_NET_PACKETS,
update_every,
RRDSET_TYPE_LINE
);
@@ -405,9 +517,9 @@ int do_getifaddrs(int update_every, usec_t dt) {
"net.errors",
"Interface Errors",
"errors/s",
- "freebsd",
+ "freebsd.plugin",
"getifaddrs",
- 7002,
+ NETDATA_CHART_PRIO_FIRST_NET_ERRORS,
update_every,
RRDSET_TYPE_LINE
);
@@ -439,9 +551,9 @@ int do_getifaddrs(int update_every, usec_t dt) {
"net.drops",
"Interface Drops",
"drops/s",
- "freebsd",
+ "freebsd.plugin",
"getifaddrs",
- 7003,
+ NETDATA_CHART_PRIO_FIRST_NET_DROPS,
update_every,
RRDSET_TYPE_LINE
);
@@ -474,9 +586,9 @@ int do_getifaddrs(int update_every, usec_t dt) {
"net.events",
"Network Interface Events",
"events/s",
- "freebsd",
+ "freebsd.plugin",
"getifaddrs",
- 7006,
+ NETDATA_CHART_PRIO_FIRST_NET_EVENTS,
update_every,
RRDSET_TYPE_LINE
);
diff --git a/src/freebsd_getmntinfo.c b/collectors/freebsd.plugin/freebsd_getmntinfo.c
index ea82b9fd1..c86f23166 100644
--- a/src/freebsd_getmntinfo.c
+++ b/collectors/freebsd.plugin/freebsd_getmntinfo.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_freebsd.h"
#include <sys/mount.h>
@@ -225,9 +227,9 @@ int do_getmntinfo(int update_every, usec_t dt) {
"disk.space",
title,
"GB",
- "freebsd",
+ "freebsd.plugin",
"getmntinfo",
- 2023,
+ NETDATA_CHART_PRIO_DISKSPACE_SPACE,
update_every,
RRDSET_TYPE_STACKED
);
@@ -264,9 +266,9 @@ int do_getmntinfo(int update_every, usec_t dt) {
"disk.inodes",
title,
"Inodes",
- "freebsd",
+ "freebsd.plugin",
"getmntinfo",
- 2024,
+ NETDATA_CHART_PRIO_DISKSPACE_INODES,
update_every,
RRDSET_TYPE_STACKED
);
diff --git a/src/freebsd_ipfw.c b/collectors/freebsd.plugin/freebsd_ipfw.c
index 81264b3f3..c256da8b3 100644
--- a/src/freebsd_ipfw.c
+++ b/collectors/freebsd.plugin/freebsd_ipfw.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_freebsd.h"
#include <netinet/ip_fw.h>
@@ -162,9 +164,9 @@ int do_ipfw(int update_every, usec_t dt) {
NULL,
"Memory allocated by rules",
"bytes",
- "freebsd",
+ "freebsd.plugin",
"ipfw",
- 3005,
+ NETDATA_CHART_PRIO_IPFW_MEM,
update_every,
RRDSET_TYPE_STACKED
);
@@ -195,9 +197,9 @@ int do_ipfw(int update_every, usec_t dt) {
NULL,
"Packets",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"ipfw",
- 3001,
+ NETDATA_CHART_PRIO_IPFW_PACKETS,
update_every,
RRDSET_TYPE_STACKED
);
@@ -212,9 +214,9 @@ int do_ipfw(int update_every, usec_t dt) {
NULL,
"Bytes",
"bytes/s",
- "freebsd",
+ "freebsd.plugin",
"ipfw",
- 3002,
+ NETDATA_CHART_PRIO_IPFW_BYTES,
update_every,
RRDSET_TYPE_STACKED
);
@@ -316,9 +318,9 @@ int do_ipfw(int update_every, usec_t dt) {
NULL,
"Active rules",
"rules",
- "freebsd",
+ "freebsd.plugin",
"ipfw",
- 3003,
+ NETDATA_CHART_PRIO_IPFW_ACTIVE,
update_every,
RRDSET_TYPE_STACKED
);
@@ -333,9 +335,9 @@ int do_ipfw(int update_every, usec_t dt) {
NULL,
"Expired rules",
"rules",
- "freebsd",
+ "freebsd.plugin",
"ipfw",
- 3004,
+ NETDATA_CHART_PRIO_IPFW_EXPIRED,
update_every,
RRDSET_TYPE_STACKED
);
diff --git a/src/freebsd_kstat_zfs.c b/collectors/freebsd.plugin/freebsd_kstat_zfs.c
index 1bd48d4bf..93dfc320b 100644
--- a/src/freebsd_kstat_zfs.c
+++ b/collectors/freebsd.plugin/freebsd_kstat_zfs.c
@@ -1,5 +1,7 @@
-#include "common.h"
-#include "zfs_common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_freebsd.h"
+#include "collectors/proc.plugin/zfs_common.h"
extern struct arcstats arcstats;
@@ -207,8 +209,8 @@ int do_kstat_zfs_misc_arcstats(int update_every, usec_t dt) {
// missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_need_free", mibs.arc_need_free, arcstats.arc_need_free);
// missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_sys_free", mibs.arc_sys_free, arcstats.arc_sys_free);
- generate_charts_arcstats("freebsd", update_every);
- generate_charts_arc_summary("freebsd", update_every);
+ generate_charts_arcstats("freebsd", "zfs", update_every);
+ generate_charts_arc_summary("freebsd", "zfs", update_every);
return 0;
}
diff --git a/src/freebsd_sysctl.c b/collectors/freebsd.plugin/freebsd_sysctl.c
index 1e11255aa..da5a351de 100644
--- a/src/freebsd_sysctl.c
+++ b/collectors/freebsd.plugin/freebsd_sysctl.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_freebsd.h"
#include <sys/vmmeter.h>
#include <vm/vm_param.h>
@@ -84,6 +86,10 @@ typedef struct __vmmeter vmmeter_t;
typedef struct vmmeter vmmeter_t;
#endif
+#if (__FreeBSD_version >= 1101516 && __FreeBSD_version < 1200000) || __FreeBSD_version >= 1200015
+#define NETDATA_COLLECT_LAUNDRY 1
+#endif
+
// --------------------------------------------------------------------------------------------------------------------
// FreeBSD plugin initialization
@@ -141,9 +147,9 @@ int do_vm_loadavg(int update_every, usec_t dt){
NULL,
"System Load Average",
"load",
- "freebsd",
+ "freebsd.plugin",
"vm.loadavg",
- 100,
+ NETDATA_CHART_PRIO_SYSTEM_LOAD,
(update_every < MIN_LOADAVG_UPDATE_EVERY) ?
MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE
);
@@ -210,9 +216,9 @@ int do_vm_vmtotal(int update_every, usec_t dt) {
NULL,
"System Active Processes",
"processes",
- "freebsd",
+ "freebsd.plugin",
"vm.vmtotal",
- 750,
+ NETDATA_CHART_PRIO_SYSTEM_ACTIVE_PROCESSES,
update_every,
RRDSET_TYPE_LINE
);
@@ -239,9 +245,9 @@ int do_vm_vmtotal(int update_every, usec_t dt) {
NULL,
"System Processes",
"processes",
- "freebsd",
+ "freebsd.plugin",
"vm.vmtotal",
- 600,
+ NETDATA_CHART_PRIO_SYSTEM_PROCESSES,
update_every,
RRDSET_TYPE_LINE
);
@@ -271,7 +277,7 @@ int do_vm_vmtotal(int update_every, usec_t dt) {
NULL,
"Committed (Allocated) Memory",
"MB",
- "freebsd",
+ "freebsd.plugin",
"vm.vmtotal",
NETDATA_CHART_PRIO_MEM_SYSTEM_COMMITTED,
update_every,
@@ -330,9 +336,10 @@ int do_kern_cp_time(int update_every, usec_t dt) {
"system.cpu",
"Total CPU utilization",
"percentage",
- "freebsd",
+ "freebsd.plugin",
"kern.cp_time",
- 100, update_every,
+ NETDATA_CHART_PRIO_SYSTEM_CPU,
+ update_every,
RRDSET_TYPE_STACKED
);
@@ -411,9 +418,9 @@ int do_kern_cp_times(int update_every, usec_t dt) {
"cpu.cpu",
"Core utilization",
"percentage",
- "freebsd",
+ "freebsd.plugin",
"kern.cp_times",
- 1000,
+ NETDATA_CHART_PRIO_CPU_PER_CORE,
update_every,
RRDSET_TYPE_STACKED
);
@@ -495,9 +502,9 @@ int do_dev_cpu_temperature(int update_every, usec_t dt) {
"cpu.temperatute",
"Core temperature",
"Celsius",
- "freebsd",
+ "freebsd.plugin",
"dev.cpu.temperature",
- 1050,
+ NETDATA_CHART_PRIO_CPU_TEMPERATURE,
update_every,
RRDSET_TYPE_LINE
);
@@ -548,9 +555,9 @@ int do_dev_cpu_0_freq(int update_every, usec_t dt) {
NULL,
"Current CPU Scaling Frequency",
"MHz",
- "freebsd",
+ "freebsd.plugin",
"dev.cpu.0.freq",
- 5003,
+ NETDATA_CHART_PRIO_CPUFREQ_SCALING_CUR_FREQ,
update_every,
RRDSET_TYPE_LINE
);
@@ -612,9 +619,9 @@ int do_hw_intcnt(int update_every, usec_t dt) {
NULL,
"Total Hardware Interrupts",
"interrupts/s",
- "freebsd",
+ "freebsd.plugin",
"hw.intrcnt",
- 900,
+ NETDATA_CHART_PRIO_SYSTEM_INTR,
update_every,
RRDSET_TYPE_LINE
);
@@ -657,9 +664,9 @@ int do_hw_intcnt(int update_every, usec_t dt) {
NULL,
"System interrupts",
"interrupts/s",
- "freebsd",
+ "freebsd.plugin",
"hw.intrcnt",
- 1000,
+ NETDATA_CHART_PRIO_SYSTEM_INTERRUPTS,
update_every,
RRDSET_TYPE_STACKED
);
@@ -715,9 +722,9 @@ int do_vm_stats_sys_v_intr(int update_every, usec_t dt) {
NULL,
"Device Interrupts",
"interrupts/s",
- "freebsd",
+ "freebsd.plugin",
"vm.stats.sys.v_intr",
- 1000,
+ NETDATA_CHART_PRIO_SYSTEM_DEV_INTR,
update_every,
RRDSET_TYPE_LINE
);
@@ -761,9 +768,9 @@ int do_vm_stats_sys_v_soft(int update_every, usec_t dt) {
NULL,
"Software Interrupts",
"interrupts/s",
- "freebsd",
+ "freebsd.plugin",
"vm.stats.sys.v_soft",
- 1100,
+ NETDATA_CHART_PRIO_SYSTEM_SOFT_INTR,
update_every,
RRDSET_TYPE_LINE
);
@@ -807,9 +814,9 @@ int do_vm_stats_sys_v_swtch(int update_every, usec_t dt) {
NULL,
"CPU Context Switches",
"context switches/s",
- "freebsd",
+ "freebsd.plugin",
"vm.stats.sys.v_swtch",
- 800,
+ NETDATA_CHART_PRIO_SYSTEM_CTXT,
update_every,
RRDSET_TYPE_LINE
);
@@ -853,9 +860,9 @@ int do_vm_stats_sys_v_forks(int update_every, usec_t dt) {
NULL,
"Started Processes",
"processes/s",
- "freebsd",
+ "freebsd.plugin",
"vm.stats.sys.v_swtch",
- 700,
+ NETDATA_CHART_PRIO_SYSTEM_FORKS,
update_every,
RRDSET_TYPE_LINE
);
@@ -930,9 +937,9 @@ int do_vm_swap_info(int update_every, usec_t dt) {
NULL,
"System Swap",
"MB",
- "freebsd",
+ "freebsd.plugin",
"vm.swap_info",
- 201,
+ NETDATA_CHART_PRIO_SYSTEM_SWAP,
update_every,
RRDSET_TYPE_STACKED
);
@@ -958,7 +965,8 @@ int do_vm_swap_info(int update_every, usec_t dt) {
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};
+ mib_cache_count[4] = {0, 0, 0, 0}, mib_laundry_count[4] = {0, 0, 0, 0}, mib_vfs_bufspace[2] = {0, 0},
+ mib_free_count[4] = {0, 0, 0, 0};
vmmeter_t vmmeter_data;
int vfs_bufspace_count;
@@ -968,6 +976,9 @@ int do_system_ram(int update_every, usec_t dt) {
#if __FreeBSD_version < 1200016
GETSYSCTL_SIMPLE("vm.stats.vm.v_cache_count", mib_cache_count, vmmeter_data.v_cache_count) ||
#endif
+#if defined(NETDATA_COLLECT_LAUNDRY)
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_laundry_count", mib_laundry_count, vmmeter_data.v_laundry_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");
@@ -978,8 +989,8 @@ int do_system_ram(int update_every, usec_t dt) {
// --------------------------------------------------------------------
static RRDSET *st = NULL;
- static RRDDIM *rd_free = NULL, *rd_active = NULL, *rd_inactive = NULL,
- *rd_wired = NULL, *rd_cache = NULL, *rd_buffers = NULL;
+ static RRDDIM *rd_free = NULL, *rd_active = NULL, *rd_inactive = NULL, *rd_wired = NULL,
+ *rd_cache = NULL, *rd_laundry = NULL, *rd_buffers = NULL;
if (unlikely(!st)) {
st = rrdset_create_localhost(
@@ -990,9 +1001,9 @@ int do_system_ram(int update_every, usec_t dt) {
NULL,
"System RAM",
"MB",
- "freebsd",
+ "freebsd.plugin",
"system.ram",
- 200,
+ NETDATA_CHART_PRIO_SYSTEM_RAM,
update_every,
RRDSET_TYPE_STACKED
);
@@ -1004,6 +1015,9 @@ int do_system_ram(int update_every, usec_t dt) {
#if __FreeBSD_version < 1200016
rd_cache = rrddim_add(st, "cache", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
#endif
+#if defined(NETDATA_COLLECT_LAUNDRY)
+ rd_laundry = rrddim_add(st, "laundry", 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);
@@ -1015,6 +1029,9 @@ int do_system_ram(int update_every, usec_t dt) {
#if __FreeBSD_version < 1200016
rrddim_set_by_pointer(st, rd_cache, vmmeter_data.v_cache_count);
#endif
+#if defined(NETDATA_COLLECT_LAUNDRY)
+ rrddim_set_by_pointer(st, rd_laundry, vmmeter_data.v_laundry_count);
+#endif
rrddim_set_by_pointer(st, rd_buffers, vfs_bufspace_count);
rrdset_done(st);
}
@@ -1051,9 +1068,9 @@ int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt) {
NULL,
"Swap I/O",
"kilobytes/s",
- "freebsd",
+ "freebsd.plugin",
"vm.stats.vm.v_swappgs",
- 250,
+ NETDATA_CHART_PRIO_SYSTEM_SWAPIO,
update_every,
RRDSET_TYPE_AREA
);
@@ -1105,7 +1122,7 @@ int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt) {
NULL,
"Memory Page Faults",
"page faults/s",
- "freebsd",
+ "freebsd.plugin",
"vm.stats.vm.v_pgfaults",
NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS,
update_every,
@@ -1187,9 +1204,9 @@ int do_kern_ipc_sem(int update_every, usec_t dt) {
NULL,
"IPC Semaphores",
"semaphores",
- "freebsd",
+ "freebsd.plugin",
"kern.ipc.sem",
- 1000,
+ NETDATA_CHART_PRIO_SYSTEM_IPC_SEMAPHORES,
update_every,
RRDSET_TYPE_AREA
);
@@ -1212,9 +1229,9 @@ int do_kern_ipc_sem(int update_every, usec_t dt) {
NULL,
"IPC Semaphore Arrays",
"arrays",
- "freebsd",
+ "freebsd.plugin",
"kern.ipc.sem",
- 1000,
+ NETDATA_CHART_PRIO_SYSTEM_IPC_SEM_ARRAYS,
update_every,
RRDSET_TYPE_AREA
);
@@ -1286,9 +1303,9 @@ int do_kern_ipc_shm(int update_every, usec_t dt) {
NULL,
"IPC Shared Memory Segments",
"segments",
- "freebsd",
+ "freebsd.plugin",
"kern.ipc.shm",
- 1000,
+ NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_SEGS,
update_every,
RRDSET_TYPE_AREA
);
@@ -1311,9 +1328,9 @@ int do_kern_ipc_shm(int update_every, usec_t dt) {
NULL,
"IPC Shared Memory Segments Size",
"kilobytes",
- "freebsd",
+ "freebsd.plugin",
"kern.ipc.shm",
- 1000,
+ NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_SIZE,
update_every,
RRDSET_TYPE_AREA
);
@@ -1391,9 +1408,9 @@ int do_kern_ipc_msq(int update_every, usec_t dt) {
NULL,
"Number of IPC Message Queues",
"queues",
- "freebsd",
+ "freebsd.plugin",
"kern.ipc.msq",
- 990,
+ NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_QUEUES,
update_every,
RRDSET_TYPE_AREA
);
@@ -1416,9 +1433,9 @@ int do_kern_ipc_msq(int update_every, usec_t dt) {
NULL,
"Number of Messages in IPC Message Queues",
"messages",
- "freebsd",
+ "freebsd.plugin",
"kern.ipc.msq",
- 1000,
+ NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_MESSAGES,
update_every,
RRDSET_TYPE_AREA
);
@@ -1441,9 +1458,9 @@ int do_kern_ipc_msq(int update_every, usec_t dt) {
NULL,
"Size of IPC Message Queues",
"bytes",
- "freebsd",
+ "freebsd.plugin",
"kern.ipc.msq",
- 1100,
+ NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_SIZE,
update_every,
RRDSET_TYPE_LINE
);
@@ -1485,9 +1502,9 @@ int do_uptime(int update_every, usec_t dt) {
NULL,
"System Uptime",
"seconds",
- "freebsd",
+ "freebsd.plugin",
"uptime",
- 1000,
+ NETDATA_CHART_PRIO_SYSTEM_UPTIME,
update_every,
RRDSET_TYPE_LINE
);
@@ -1613,9 +1630,9 @@ int do_net_isr(int update_every, usec_t dt) {
NULL,
"System softnet_stat",
"events/s",
- "freebsd",
+ "freebsd.plugin",
"net.isr",
- 955,
+ NETDATA_CHART_PRIO_SYSTEM_SOFTNET_STAT,
update_every,
RRDSET_TYPE_LINE
);
@@ -1666,9 +1683,9 @@ int do_net_isr(int update_every, usec_t dt) {
NULL,
"Per CPU netisr statistics",
"events/s",
- "freebsd",
+ "freebsd.plugin",
"net.isr",
- 1101 + i,
+ NETDATA_CHART_PRIO_SOFTNET_PER_CORE + i,
update_every,
RRDSET_TYPE_LINE
);
@@ -1728,7 +1745,7 @@ int do_net_inet_tcp_states(int update_every, usec_t dt) {
NULL,
"IPv4 TCP Connections",
"active connections",
- "freebsd",
+ "freebsd.plugin",
"net.inet.tcp.states",
2500,
update_every,
@@ -1812,7 +1829,7 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) {
NULL,
"IPv4 TCP Packets",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.tcp.stats",
2600,
update_every,
@@ -1844,7 +1861,7 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) {
NULL,
"IPv4 TCP Errors",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.tcp.stats",
2700,
update_every,
@@ -1886,7 +1903,7 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) {
NULL,
"IPv4 TCP Handshake Issues",
"events/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.tcp.stats",
2900,
update_every,
@@ -1927,7 +1944,7 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) {
NULL,
"TCP Connection Aborts",
"connections/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.tcp.stats",
3010,
update_every,
@@ -1967,7 +1984,7 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) {
NULL,
"TCP Out-Of-Order Queue",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.tcp.stats",
3050,
update_every,
@@ -1999,7 +2016,7 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) {
NULL,
"TCP SYN Cookies",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.tcp.stats",
3100,
update_every,
@@ -2036,7 +2053,7 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) {
NULL,
"TCP Listen Socket Issues",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.tcp.stats",
3015,
update_every,
@@ -2070,7 +2087,7 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) {
NULL,
"IPv4 ECN Statistics",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.tcp.stats",
8700,
update_every,
@@ -2144,7 +2161,7 @@ int do_net_inet_udp_stats(int update_every, usec_t dt) {
NULL,
"IPv4 UDP Packets",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.udp.stats",
2601,
update_every,
@@ -2177,7 +2194,7 @@ int do_net_inet_udp_stats(int update_every, usec_t dt) {
NULL,
"IPv4 UDP Errors",
"events/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.udp.stats",
2701,
update_every,
@@ -2263,7 +2280,7 @@ int do_net_inet_icmp_stats(int update_every, usec_t dt) {
, NULL
, "IPv4 ICMP Packets"
, "packets/s"
- , "freebsd"
+ , "freebsd.plugin"
, "net.inet.icmp.stats"
, 2602
, update_every
@@ -2296,7 +2313,7 @@ int do_net_inet_icmp_stats(int update_every, usec_t dt) {
, NULL
, "IPv4 ICMP Errors"
, "packets/s"
- , "freebsd"
+ , "freebsd.plugin"
, "net.inet.icmp.stats"
, 2603
, update_every
@@ -2332,7 +2349,7 @@ int do_net_inet_icmp_stats(int update_every, usec_t dt) {
, NULL
, "IPv4 ICMP Messages"
, "packets/s"
- , "freebsd"
+ , "freebsd.plugin"
, "net.inet.icmp.stats"
, 2604
, update_every
@@ -2410,7 +2427,7 @@ int do_net_inet_ip_stats(int update_every, usec_t dt) {
NULL,
"IPv4 Packets",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.ip.stats",
3000,
update_every,
@@ -2446,7 +2463,7 @@ int do_net_inet_ip_stats(int update_every, usec_t dt) {
NULL,
"IPv4 Fragments Sent",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.ip.stats",
3010,
update_every,
@@ -2482,7 +2499,7 @@ int do_net_inet_ip_stats(int update_every, usec_t dt) {
NULL,
"IPv4 Fragments Reassembly",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.ip.stats",
3011,
update_every,
@@ -2520,7 +2537,7 @@ int do_net_inet_ip_stats(int update_every, usec_t dt) {
NULL,
"IPv4 Errors",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet.ip.stats",
3002,
update_every,
@@ -2611,7 +2628,7 @@ int do_net_inet6_ip6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 Packets",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.ip6.stats",
3000,
update_every,
@@ -2651,7 +2668,7 @@ int do_net_inet6_ip6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 Fragments Sent",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.ip6.stats",
3010,
update_every,
@@ -2691,7 +2708,7 @@ int do_net_inet6_ip6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 Fragments Reassembly",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.ip6.stats",
3011,
update_every,
@@ -2742,7 +2759,7 @@ int do_net_inet6_ip6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 Errors",
"packets/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.ip6.stats",
3002,
update_every,
@@ -2856,7 +2873,7 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 ICMP Messages",
"messages/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.icmp6.stats",
10000,
update_every,
@@ -2891,7 +2908,7 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 ICMP Redirects",
"redirects/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.icmp6.stats",
10050,
update_every,
@@ -2938,7 +2955,7 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 ICMP Errors",
"errors/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.icmp6.stats",
10100,
update_every,
@@ -2993,7 +3010,7 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 ICMP Echo",
"messages/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.icmp6.stats",
10200,
update_every,
@@ -3036,7 +3053,7 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 Router Messages",
"messages/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.icmp6.stats",
10400,
update_every,
@@ -3079,7 +3096,7 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 Neighbor Messages",
"messages/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.icmp6.stats",
10500,
update_every,
@@ -3129,7 +3146,7 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
NULL,
"IPv6 ICMP Types",
"messages/s",
- "freebsd",
+ "freebsd.plugin",
"net.inet6.icmp6.stats",
10700,
update_every,
diff --git a/src/plugin_freebsd.c b/collectors/freebsd.plugin/plugin_freebsd.c
index a0d3dc2ea..5cde37113 100644
--- a/src/plugin_freebsd.c
+++ b/collectors/freebsd.plugin/plugin_freebsd.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_freebsd.h"
static struct freebsd_module {
const char *name;
@@ -113,7 +115,7 @@ void *freebsd_main(void *ptr) {
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;
+ pm->duration = heartbeat_monotonic_dt_to_now_usec(&hb) - duration;
duration += pm->duration;
if(unlikely(netdata_exit)) break;
diff --git a/collectors/freebsd.plugin/plugin_freebsd.h b/collectors/freebsd.plugin/plugin_freebsd.h
new file mode 100644
index 000000000..ab46080be
--- /dev/null
+++ b/collectors/freebsd.plugin/plugin_freebsd.h
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_PLUGIN_FREEBSD_H
+#define NETDATA_PLUGIN_FREEBSD_H 1
+
+#include "daemon/common.h"
+
+#if (TARGET_OS == OS_FREEBSD)
+
+#define NETDATA_PLUGIN_HOOK_FREEBSD \
+ { \
+ .name = "PLUGIN[freebsd]", \
+ .config_section = CONFIG_SECTION_PLUGINS, \
+ .config_name = "freebsd", \
+ .enabled = 1, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = freebsd_main \
+ },
+
+
+#include <sys/sysctl.h>
+
+#define KILO_FACTOR 1024
+#define MEGA_FACTOR 1048576 // 1024 * 1024
+#define GIGA_FACTOR 1073741824 // 1024 * 1024 * 1024
+
+#define MAX_INT_DIGITS 10 // maximum number of digits for int
+
+void *freebsd_main(void *ptr);
+
+extern int freebsd_plugin_init();
+
+extern int do_vm_loadavg(int update_every, usec_t dt);
+extern int do_vm_vmtotal(int update_every, usec_t dt);
+extern int do_kern_cp_time(int update_every, usec_t dt);
+extern int do_kern_cp_times(int update_every, usec_t dt);
+extern int do_dev_cpu_temperature(int update_every, usec_t dt);
+extern int do_dev_cpu_0_freq(int update_every, usec_t dt);
+extern int do_hw_intcnt(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_intr(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_soft(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_swtch(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_forks(int update_every, usec_t dt);
+extern int do_vm_swap_info(int update_every, usec_t dt);
+extern int do_system_ram(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt);
+extern int do_kern_ipc_sem(int update_every, usec_t dt);
+extern int do_kern_ipc_shm(int update_every, usec_t dt);
+extern int do_kern_ipc_msq(int update_every, usec_t dt);
+extern int do_uptime(int update_every, usec_t dt);
+extern int do_net_isr(int update_every, usec_t dt);
+extern int do_net_inet_tcp_states(int update_every, usec_t dt);
+extern int do_net_inet_tcp_stats(int update_every, usec_t dt);
+extern int do_net_inet_udp_stats(int update_every, usec_t dt);
+extern int do_net_inet_icmp_stats(int update_every, usec_t dt);
+extern int do_net_inet_ip_stats(int update_every, usec_t dt);
+extern int do_net_inet6_ip6_stats(int update_every, usec_t dt);
+extern int do_net_inet6_icmp6_stats(int update_every, usec_t dt);
+extern int do_getifaddrs(int update_every, usec_t dt);
+extern int do_getmntinfo(int update_every, usec_t dt);
+extern int do_kern_devstat(int update_every, usec_t dt);
+extern int do_kstat_zfs_misc_arcstats(int update_every, usec_t dt);
+extern int do_kstat_zfs_misc_zio_trim(int update_every, usec_t dt);
+extern int do_ipfw(int update_every, usec_t dt);
+
+#else // (TARGET_OS == OS_FREEBSD)
+
+#define NETDATA_PLUGIN_HOOK_FREEBSD
+
+#endif // (TARGET_OS == OS_FREEBSD)
+
+#endif /* NETDATA_PLUGIN_FREEBSD_H */
diff --git a/collectors/freeipmi.plugin/Makefile.am b/collectors/freeipmi.plugin/Makefile.am
new file mode 100644
index 000000000..19554bed8
--- /dev/null
+++ b/collectors/freeipmi.plugin/Makefile.am
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
diff --git a/collectors/freeipmi.plugin/Makefile.in b/collectors/freeipmi.plugin/Makefile.in
new file mode 100644
index 000000000..54a0035c6
--- /dev/null
+++ b/collectors/freeipmi.plugin/Makefile.in
@@ -0,0 +1,464 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors/freeipmi.plugin
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(dist_noinst_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/freeipmi.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/freeipmi.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+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
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/collectors/freeipmi.plugin/README.md b/collectors/freeipmi.plugin/README.md
new file mode 100644
index 000000000..f7c5cc148
--- /dev/null
+++ b/collectors/freeipmi.plugin/README.md
@@ -0,0 +1,180 @@
+netdata has a [freeipmi](https://www.gnu.org/software/freeipmi/) plugin.
+
+> FreeIPMI provides in-band and out-of-band IPMI software based on the IPMI v1.5/2.0 specification. The IPMI specification defines a set of interfaces for platform management and is implemented by a number vendors for system management. The features of IPMI that most users will be interested in are sensor monitoring, system event monitoring, power control, and serial-over-LAN (SOL).
+
+## compile `freeipmi.plugin`
+
+1. install `libipmimonitoring-dev` or `libipmimonitoring-devel` (`freeipmi-devel` on RHEL based OS) using the package manager of your system.
+
+2. re-install netdata from source. The installer will detect that the required libraries are now available and will also build `freeipmi.plugin`.
+
+Keep in mind IPMI requires root access, so the plugin is setuid to root.
+
+If you just installed the required IPMI tools, please run at least once the command `ipmimonitoring` and verify it returns sensors information. This command initialises IPMI configuration, so that the netdata plugin will be able to work.
+
+## netdata use
+
+The plugin creates (up to) 8 charts, based on the information collected from IPMI:
+
+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 adds 2 alarms:
+
+1. Sensors in non-nominal state (i.e. warning and critical)
+2. SEL is non empty
+
+![image](https://cloud.githubusercontent.com/assets/2662304/23674138/88926a20-037d-11e7-89c0-20e74ee10cd1.png)
+
+The plugin does a speed test when it starts, to find out the duration needed by the IPMI processor to respond. Depending on the speed of your IPMI processor, charts may need several seconds to show up on the dashboard.
+
+## `freeipmi.plugin` configuration
+
+The plugin supports a few options. To see them, run:
+
+```sh
+# /usr/libexec/netdata/plugins.d/freeipmi.plugin -h
+
+ netdata freeipmi.plugin 1.8.0-546-g72ce5d6b_rolling
+ Copyright (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>
+ Released under GNU General Public License v3 or later.
+ All rights reserved.
+
+ This program is a data collector plugin for netdata.
+
+ Available command line options:
+
+ SECONDS data collection frequency
+ minimum: 5
+
+ debug enable verbose output
+ default: disabled
+
+ sel
+ no-sel enable/disable SEL collection
+ default: enabled
+
+ hostname HOST
+ username USER
+ password PASS connect to remote IPMI host
+ default: local IPMI processor
+
+ sdr-cache-dir PATH directory for SDR cache files
+ default: /tmp
+
+ sensor-config-file FILE filename to read sensor configuration
+ default: system default
+
+ ignore N1,N2,N3,... sensor IDs to ignore
+ default: none
+
+ -v
+ -V
+ version print version and exit
+
+ Linux kernel module for IPMI is CPU hungry.
+ On Linux run this to lower kipmiN CPU utilization:
+ # echo 10 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us
+
+ or create: /etc/modprobe.d/ipmi.conf with these contents:
+ options ipmi_si kipmid_max_busy_us=10
+
+ For more information:
+ https://github.com/ktsaou/netdata/tree/master/plugins/freeipmi.plugin
+
+```
+
+You can set these options in `/etc/netdata/netdata.conf` at this section:
+
+```
+[plugin:freeipmi]
+ update every = 5
+ command options =
+```
+
+Append to `command options = ` the settings you need. The minimum `update every` is 5 (enforced internally by the plugin). IPMI is slow and CPU hungry. So, once every 5 seconds is pretty acceptable.
+
+## ignoring specific sensors
+
+Specific sensor IDs can be excluded from freeipmi tools by editing `/etc/freeipmi/freeipmi.conf` and setting the IDs to be ignored at `ipmi-sensors-exclude-record-ids`. **However this file is not used by `libipmimonitoring`** (the library used by netdata's `freeipmi.plugin`).
+
+So, `freeipmi.plugin` supports the option `ignore` that accepts a comma separated list of sensor IDs to ignore. To configure it, edit `/etc/netdata/netdata.conf` and set:
+
+```
+[plugin:freeipmi]
+ command options = ignore 1,2,3,4,...
+```
+
+To find the IDs to ignore, run the command `ipmimonitoring`. The first column is the wanted ID:
+
+```
+ID | Name | Type | State | Reading | Units | Event
+1 | Ambient Temp | Temperature | Nominal | 26.00 | C | 'OK'
+2 | Altitude | Other Units Based Sensor | Nominal | 480.00 | ft | 'OK'
+3 | Avg Power | Current | Nominal | 100.00 | W | 'OK'
+4 | Planar 3.3V | Voltage | Nominal | 3.29 | V | 'OK'
+5 | Planar 5V | Voltage | Nominal | 4.90 | V | 'OK'
+6 | Planar 12V | Voltage | Nominal | 11.99 | V | 'OK'
+7 | Planar VBAT | Voltage | Nominal | 2.95 | V | 'OK'
+8 | Fan 1A Tach | Fan | Nominal | 3132.00 | RPM | 'OK'
+9 | Fan 1B Tach | Fan | Nominal | 2150.00 | RPM | 'OK'
+10 | Fan 2A Tach | Fan | Nominal | 2494.00 | RPM | 'OK'
+11 | Fan 2B Tach | Fan | Nominal | 1825.00 | RPM | 'OK'
+12 | Fan 3A Tach | Fan | Nominal | 3538.00 | RPM | 'OK'
+13 | Fan 3B Tach | Fan | Nominal | 2625.00 | RPM | 'OK'
+14 | Fan 1 | Entity Presence | Nominal | N/A | N/A | 'Entity Present'
+15 | Fan 2 | Entity Presence | Nominal | N/A | N/A | 'Entity Present'
+...
+```
+
+
+## debugging
+
+You can run the plugin by hand:
+
+```sh
+# become user netdata
+sudo su -s /bin/sh netdata
+
+# run the plugin in debug mode
+/usr/libexec/netdata/plugins.d/freeipmi.plugin 5 debug
+```
+
+You will get verbose output on what the plugin does.
+
+## kipmi0 CPU usage
+
+There have been reports that kipmi is showing increased CPU when the IPMI is queried.
+
+[IBM has given a few explanations](http://www-01.ibm.com/support/docview.wss?uid=nas7d580df3d15874988862575fa0050f604).
+
+Check also [this stackexchange post](http://unix.stackexchange.com/questions/74900/kipmi0-eating-up-to-99-8-cpu-on-centos-6-4).
+
+To lower the CPU consumption of the system you can issue this command:
+
+```sh
+echo 10 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us
+```
+
+You can also permanently set the above setting by creating the file `/etc/modprobe.d/ipmi.conf` with this content:
+
+```sh
+# prevent kipmi from consuming 100% CPU
+options ipmi_si kipmid_max_busy_us=10
+```
+
+This instructs the kernel IPMI module to pause for a tick between checking IPMI. Querying IPMI will be a lot slower now (e.g. several seconds for IPMI to respond), but `kipmi` will not use any noticeable CPU. You can also use a higher number (this is the number of microseconds to poll IPMI for a response, before waiting for a tick).
+
+If you need to disable IPMI for netdata, edit `/etc/netdata/netdata.conf` and set:
+
+```
+[plugins]
+ freeipmi = no
+```
diff --git a/src/freeipmi_plugin.c b/collectors/freeipmi.plugin/freeipmi_plugin.c
index df4c019a4..a1cff3af0 100644
--- a/src/freeipmi_plugin.c
+++ b/collectors/freeipmi.plugin/freeipmi_plugin.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
/*
* netdata freeipmi.plugin
* Copyright (C) 2017 Costa Tsaousis
@@ -14,7 +15,7 @@
* UCRL-CODE-222073
*/
-#include "common.h"
+#include "../../libnetdata/libnetdata.h"
#include <stdio.h>
#include <stdlib.h>
@@ -27,6 +28,32 @@
#ifdef HAVE_FREEIPMI
+// ----------------------------------------------------------------------------
+
+// callback required by fatal()
+void netdata_cleanup_and_exit(int ret) {
+ exit(ret);
+}
+
+// callbacks required by popen()
+void signals_block(void) {};
+void signals_unblock(void) {};
+void signals_reset(void) {};
+
+// callback required by eval()
+int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, calculated_number *result) {
+ (void)variable;
+ (void)hash;
+ (void)rc;
+ (void)result;
+ return 0;
+};
+
+// required by get_system_cpus()
+char *netdata_configured_host_prefix = "";
+
+// ----------------------------------------------------------------------------
+
#include <ipmi_monitoring.h>
#include <ipmi_monitoring_bitmasks.h>
@@ -46,8 +73,8 @@ char *driver_device = NULL; /* not used if probing */
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;
+unsigned char *ipmi_k_g = NULL;
+unsigned int ipmi_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 */
@@ -123,8 +150,8 @@ _init_ipmi_config (struct ipmi_monitoring_ipmi_config *ipmi_config)
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->k_g = ipmi_k_g;
+ ipmi_config->k_g_len = ipmi_k_g_len;
ipmi_config->privilege_level = privilege_level;
ipmi_config->authentication_type = authentication_type;
ipmi_config->cipher_suite_id = cipher_suite_id;
@@ -557,6 +584,41 @@ static void excluded_record_ids_parse(const char *s) {
}
}
+static int *excluded_status_record_ids = NULL;
+size_t excluded_status_record_ids_length = 0;
+
+static void excluded_status_record_ids_parse(const char *s) {
+ if(!s) return;
+
+ while(*s) {
+ while(*s && !isdigit(*s)) s++;
+
+ if(isdigit(*s)) {
+ char *e;
+ unsigned long n = strtoul(s, &e, 10);
+ s = e;
+
+ if(n != 0) {
+ excluded_status_record_ids = realloc(excluded_status_record_ids, (excluded_status_record_ids_length + 1) * sizeof(int));
+ if(!excluded_status_record_ids) {
+ fprintf(stderr, "freeipmi.plugin: failed to allocate memory. Exiting.");
+ exit(1);
+ }
+ excluded_status_record_ids[excluded_status_record_ids_length++] = (int)n;
+ }
+ }
+ }
+
+ if(debug) {
+ fprintf(stderr, "freeipmi.plugin: excluded status record ids:");
+ size_t i;
+ for(i = 0; i < excluded_status_record_ids_length; i++) {
+ fprintf(stderr, " %d", excluded_status_record_ids[i]);
+ }
+ fprintf(stderr, "\n");
+ }
+}
+
static int excluded_record_ids_check(int record_id) {
size_t i;
@@ -569,6 +631,17 @@ static int excluded_record_ids_check(int record_id) {
return 0;
}
+static int excluded_status_record_ids_check(int record_id) {
+ size_t i;
+
+ for(i = 0; i < excluded_status_record_ids_length; i++) {
+ if(excluded_status_record_ids[i] == record_id)
+ return 1;
+ }
+
+ return 0;
+}
+
static void netdata_get_sensor(
int record_id
, int sensor_number
@@ -641,6 +714,10 @@ static void netdata_get_sensor(
break;
}
+ // check if it is excluded
+ if(excluded_status_record_ids_check(record_id))
+ return;
+
switch(sensor_state) {
case IPMI_MONITORING_STATE_NOMINAL:
netdata_sensors_states_nominal++;
@@ -672,10 +749,6 @@ static void netdata_get_sel(
}
-void netdata_cleanup_and_exit(int ret) {
- exit(ret);
-}
-
// END NETDATA CODE
// ----------------------------------------------------------------------------
@@ -1478,8 +1551,8 @@ int main (int argc, char **argv) {
int i, freq = 0;
for(i = 1; i < argc ; i++) {
if(isdigit(*argv[i]) && !freq) {
- int n = atoi(argv[i]);
- if(n > 0 && freq < 86400) {
+ int n = str2i(argv[i]);
+ if(n > 0 && n < 86400) {
freq = n;
continue;
}
@@ -1536,6 +1609,9 @@ int main (int argc, char **argv) {
" ignore N1,N2,N3,... sensor IDs to ignore\n"
" default: none\n"
"\n"
+ " ignore-status N1,N2,N3,... sensor IDs to ignore status (nominal/warning/critical)\n"
+ " default: none\n"
+ "\n"
" -v\n"
" -V\n"
" version print version and exit\n"
@@ -1548,7 +1624,7 @@ int main (int argc, char **argv) {
" options ipmi_si kipmid_max_busy_us=10\n"
"\n"
" For more information:\n"
- " https://github.com/firehol/netdata/wiki/monitoring-IPMI\n"
+ " https://github.com/ktsaou/netdata/tree/master/plugins/freeipmi.plugin\n"
"\n"
, VERSION
, netdata_update_every
@@ -1596,6 +1672,10 @@ int main (int argc, char **argv) {
excluded_record_ids_parse(argv[++i]);
continue;
}
+ else if(i < argc && strcmp("ignore-status", argv[i]) == 0) {
+ excluded_status_record_ids_parse(argv[++i]);
+ continue;
+ }
error("freeipmi.plugin: ignoring parameter '%s'", argv[i]);
}
diff --git a/collectors/idlejitter.plugin/Makefile.am b/collectors/idlejitter.plugin/Makefile.am
new file mode 100644
index 000000000..19554bed8
--- /dev/null
+++ b/collectors/idlejitter.plugin/Makefile.am
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
diff --git a/collectors/idlejitter.plugin/Makefile.in b/collectors/idlejitter.plugin/Makefile.in
new file mode 100644
index 000000000..973a3bef7
--- /dev/null
+++ b/collectors/idlejitter.plugin/Makefile.in
@@ -0,0 +1,464 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors/idlejitter.plugin
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(dist_noinst_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/idlejitter.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/idlejitter.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+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
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/collectors/idlejitter.plugin/README.md b/collectors/idlejitter.plugin/README.md
new file mode 100644
index 000000000..3c2080536
--- /dev/null
+++ b/collectors/idlejitter.plugin/README.md
@@ -0,0 +1,13 @@
+## idlejitter.plugin
+
+It works like this:
+
+A thread is spawn that requests to sleep for 20000 microseconds (20ms).
+When the system wakes it up, it measures how many microseconds have passed.
+The difference between the requested and the actual duration of the sleep, is the idle jitter.
+This is done at most 50 times per second, to ensure we have a good average.
+
+This number is useful:
+
+ 1. in real-time environments, when the CPU jitter can affect the quality of the service (like VoIP media gateways).
+ 2. in cloud infrastructure, at can pause the VM or container for a small duration to perform operations at the host.
diff --git a/src/plugin_idlejitter.c b/collectors/idlejitter.plugin/plugin_idlejitter.c
index 77bd95d55..3fe3b0306 100644
--- a/src/plugin_idlejitter.c
+++ b/collectors/idlejitter.plugin/plugin_idlejitter.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_idlejitter.h"
#define CPU_IDLEJITTER_SLEEP_TIME_MS 20
@@ -28,9 +30,9 @@ void *cpuidlejitter_main(void *ptr) {
, NULL
, "CPU Idle Jitter"
, "microseconds lost/s"
- , "idlejitter"
+ , "idlejitter.plugin"
, NULL
- , 800
+ , NETDATA_CHART_PRIO_SYSTEM_IDLEJITTER
, localhost->rrd_update_every
, RRDSET_TYPE_AREA
);
diff --git a/collectors/idlejitter.plugin/plugin_idlejitter.h b/collectors/idlejitter.plugin/plugin_idlejitter.h
new file mode 100644
index 000000000..62fabea16
--- /dev/null
+++ b/collectors/idlejitter.plugin/plugin_idlejitter.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_PLUGIN_IDLEJITTER_H
+#define NETDATA_PLUGIN_IDLEJITTER_H 1
+
+#include "../../daemon/common.h"
+
+#define NETDATA_PLUGIN_HOOK_IDLEJITTER \
+ { \
+ .name = "PLUGIN[idlejitter]", \
+ .config_section = CONFIG_SECTION_PLUGINS, \
+ .config_name = "idlejitter", \
+ .enabled = 1, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = cpuidlejitter_main \
+ },
+
+extern void *cpuidlejitter_main(void *ptr);
+
+#endif /* NETDATA_PLUGIN_IDLEJITTER_H */
diff --git a/collectors/macos.plugin/Makefile.am b/collectors/macos.plugin/Makefile.am
new file mode 100644
index 000000000..babdcf0df
--- /dev/null
+++ b/collectors/macos.plugin/Makefile.am
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
diff --git a/collectors/macos.plugin/Makefile.in b/collectors/macos.plugin/Makefile.in
new file mode 100644
index 000000000..6247dda70
--- /dev/null
+++ b/collectors/macos.plugin/Makefile.in
@@ -0,0 +1,457 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors/macos.plugin
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/macos.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/macos.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+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
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/macos_fw.c b/collectors/macos.plugin/macos_fw.c
index 5e8ce0ee4..5d0ba929e 100644
--- a/src/macos_fw.c
+++ b/collectors/macos.plugin/macos_fw.c
@@ -1,4 +1,7 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_macos.h"
+
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
diff --git a/src/macos_mach_smi.c b/collectors/macos.plugin/macos_mach_smi.c
index 47d32a9f7..1c43d624c 100644
--- a/src/macos_mach_smi.c
+++ b/collectors/macos.plugin/macos_mach_smi.c
@@ -1,4 +1,7 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_macos.h"
+
#include <mach/mach.h>
int do_macos_mach_smi(int update_every, usec_t dt) {
diff --git a/src/macos_sysctl.c b/collectors/macos.plugin/macos_sysctl.c
index cb6fa8af9..6b443c04a 100644
--- a/src/macos_sysctl.c
+++ b/collectors/macos.plugin/macos_sysctl.c
@@ -1,6 +1,8 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_macos.h"
+
#include <Availability.h>
-#include <sys/sysctl.h>
// NEEDED BY: do_bandwidth
#include <net/route.h>
// NEEDED BY do_tcp...
@@ -1488,17 +1490,3 @@ int do_macos_sysctl(int update_every, usec_t dt) {
return 0;
}
-int getsysctl_by_name(const char *name, void *ptr, size_t len)
-{
- size_t nlen = len;
-
- if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
- error("MACOS: sysctl(%s...) failed: %s", name, strerror(errno));
- return 1;
- }
- if (unlikely(nlen != len)) {
- error("MACOS: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
- return 1;
- }
- return 0;
-}
diff --git a/src/plugin_macos.c b/collectors/macos.plugin/plugin_macos.c
index 6ac3d25d1..628a5b10d 100644
--- a/src/plugin_macos.c
+++ b/collectors/macos.plugin/plugin_macos.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_macos.h"
static void macos_main_cleanup(void *ptr) {
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
diff --git a/collectors/macos.plugin/plugin_macos.h b/collectors/macos.plugin/plugin_macos.h
new file mode 100644
index 000000000..0815c59c3
--- /dev/null
+++ b/collectors/macos.plugin/plugin_macos.h
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+
+#ifndef NETDATA_PLUGIN_MACOS_H
+#define NETDATA_PLUGIN_MACOS_H 1
+
+#include "../../daemon/common.h"
+
+#if (TARGET_OS == OS_MACOS)
+
+#define NETDATA_PLUGIN_HOOK_MACOS \
+ { \
+ .name = "PLUGIN[macos]", \
+ .config_section = CONFIG_SECTION_PLUGINS, \
+ .config_name = "macos", \
+ .enabled = 1, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = macos_main \
+ },
+
+void *macos_main(void *ptr);
+
+#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
+
+extern int getsysctl_by_name(const char *name, void *ptr, size_t len);
+
+extern int do_macos_sysctl(int update_every, usec_t dt);
+extern int do_macos_mach_smi(int update_every, usec_t dt);
+extern int do_macos_iokit(int update_every, usec_t dt);
+
+
+#else // (TARGET_OS == OS_MACOS)
+
+#define NETDATA_PLUGIN_HOOK_MACOS
+
+#endif // (TARGET_OS == OS_MACOS)
+
+
+
+
+
+#endif /* NETDATA_PLUGIN_MACOS_H */
diff --git a/collectors/nfacct.plugin/Makefile.am b/collectors/nfacct.plugin/Makefile.am
new file mode 100644
index 000000000..19554bed8
--- /dev/null
+++ b/collectors/nfacct.plugin/Makefile.am
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
diff --git a/collectors/nfacct.plugin/Makefile.in b/collectors/nfacct.plugin/Makefile.in
new file mode 100644
index 000000000..2a1d001de
--- /dev/null
+++ b/collectors/nfacct.plugin/Makefile.in
@@ -0,0 +1,464 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors/nfacct.plugin
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(dist_noinst_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/nfacct.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/nfacct.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+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
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/collectors/nfacct.plugin/README.md b/collectors/nfacct.plugin/README.md
new file mode 100644
index 000000000..814b47915
--- /dev/null
+++ b/collectors/nfacct.plugin/README.md
@@ -0,0 +1,10 @@
+# nfacct.plugin
+
+This plugin that collects NFACCT statistics.
+
+It is currently disabled by default, because it requires root access.
+We have to move the code to an external plugin to setuid just the plugin not the whole netdata server.
+
+You can build netdata with it to test it though.
+Just run `./configure` (or `netdata-installer.sh`) with the option `--enable-plugin-nfacct` (and any other options you may need).
+Remember, you have to tell netdata you want it to run as `root` for this plugin to work.
diff --git a/src/plugin_nfacct.c b/collectors/nfacct.plugin/plugin_nfacct.c
index 02815ef04..7d42dd189 100644
--- a/src/plugin_nfacct.c
+++ b/collectors/nfacct.plugin/plugin_nfacct.c
@@ -1,6 +1,10 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
-#ifdef INTERNAL_PLUGIN_NFACCT
+#include "plugin_nfacct.h"
+
+#if defined(INTERNAL_PLUGIN_NFACCT)
+
+#define PLUGIN_NFACCT_NAME "nfacct.plugin"
#ifdef HAVE_LIBMNL
#include <libmnl/libmnl.h>
@@ -19,7 +23,7 @@ static inline size_t mnl_buffer_size() {
#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
+#define RRD_TYPE_NET_STAT_CONNTRACK "netlink"
#include <linux/netfilter/nfnetlink_conntrack.h>
@@ -302,9 +306,9 @@ static void nfstat_send_metrics() {
, NULL
, "Connection Tracker New Connections"
, "connections/s"
- , "nfacct"
+ , PLUGIN_NFACCT_NAME
, NULL
- , 3001
+ , NETDATA_CHART_PRIO_NETFILTER_NEW
, nfstat_root.update_every
, RRDSET_TYPE_LINE
);
@@ -338,9 +342,9 @@ static void nfstat_send_metrics() {
, NULL
, "Connection Tracker Changes"
, "changes/s"
- , "nfacct"
+ , PLUGIN_NFACCT_NAME
, NULL
- , 3002
+ , NETDATA_CHART_PRIO_NETFILTER_CHANGES
, nfstat_root.update_every
, RRDSET_TYPE_LINE
);
@@ -375,9 +379,9 @@ static void nfstat_send_metrics() {
, NULL
, "Connection Tracker Searches"
, "searches/s"
- , "nfacct"
+ , PLUGIN_NFACCT_NAME
, NULL
- , 3010
+ , NETDATA_CHART_PRIO_NETFILTER_SEARCH
, nfstat_root.update_every
, RRDSET_TYPE_LINE
);
@@ -412,9 +416,9 @@ static void nfstat_send_metrics() {
, NULL
, "Connection Tracker Errors"
, "events/s"
- , "nfacct"
+ , PLUGIN_NFACCT_NAME
, NULL
- , 3005
+ , NETDATA_CHART_PRIO_NETFILTER_ERRORS
, nfstat_root.update_every
, RRDSET_TYPE_LINE
);
@@ -451,9 +455,9 @@ static void nfstat_send_metrics() {
, NULL
, "Connection Tracker Expectations"
, "expectations/s"
- , "nfacct"
+ , PLUGIN_NFACCT_NAME
, NULL
- , 3003
+ , NETDATA_CHART_PRIO_NETFILTER_EXPECT
, nfstat_root.update_every
, RRDSET_TYPE_LINE
);
@@ -590,7 +594,7 @@ static void nfacct_cleanup() {
nfacct_root.buf = NULL;
nfacct_root.buf_size = 0;
- // FIXME: cleanup the metrics linked list
+ // TODO: cleanup the metrics linked list
}
static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
@@ -671,9 +675,9 @@ static void nfacct_send_metrics() {
, NULL
, "Netfilter Accounting Packets"
, "packets/s"
- , "nfacct"
+ , PLUGIN_NFACCT_NAME
, NULL
- , 3206
+ , NETDATA_CHART_PRIO_NETFILTER_PACKETS
, nfacct_root.update_every
, RRDSET_TYPE_STACKED
);
@@ -714,9 +718,9 @@ static void nfacct_send_metrics() {
, NULL
, "Netfilter Accounting Bandwidth"
, "kilobytes/s"
- , "nfacct"
+ , PLUGIN_NFACCT_NAME
, NULL
- , 3207
+ , NETDATA_CHART_PRIO_NETFILTER_BYTES
, nfacct_root.update_every
, RRDSET_TYPE_STACKED
);
@@ -788,7 +792,6 @@ void *nfacct_main(void *ptr) {
heartbeat_t hb;
heartbeat_init(&hb);
for(;;) {
- heartbeat_dt_usec(&hb);
heartbeat_next(&hb, step);
if(unlikely(netdata_exit)) break;
diff --git a/collectors/nfacct.plugin/plugin_nfacct.h b/collectors/nfacct.plugin/plugin_nfacct.h
new file mode 100644
index 000000000..4311ccecf
--- /dev/null
+++ b/collectors/nfacct.plugin/plugin_nfacct.h
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_NFACCT_H
+#define NETDATA_NFACCT_H 1
+
+#include "../../daemon/common.h"
+
+#if defined(INTERNAL_PLUGIN_NFACCT)
+
+#define NETDATA_PLUGIN_HOOK_LINUX_NFACCT \
+ { \
+ .name = "PLUGIN[nfacct]", \
+ .config_section = CONFIG_SECTION_PLUGINS, \
+ .config_name = "nfacct", \
+ .enabled = 1, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = nfacct_main \
+ },
+
+extern void *nfacct_main(void *ptr);
+
+#else // !defined(INTERNAL_PLUGIN_NFACCT)
+
+#define NETDATA_PLUGIN_HOOK_LINUX_NFACCT
+
+#endif // defined(INTERNAL_PLUGIN_NFACCT)
+
+#endif /* NETDATA_NFACCT_H */
+
diff --git a/collectors/node.d.plugin/Makefile.am b/collectors/node.d.plugin/Makefile.am
new file mode 100644
index 000000000..4de13cf76
--- /dev/null
+++ b/collectors/node.d.plugin/Makefile.am
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+CLEANFILES = \
+ node.d.plugin \
+ $(NULL)
+
+include $(top_srcdir)/build/subst.inc
+SUFFIXES = .in
+
+dist_libconfig_DATA = \
+ node.d.conf \
+ $(NULL)
+
+dist_plugins_SCRIPTS = \
+ node.d.plugin \
+ $(NULL)
+
+dist_noinst_DATA = \
+ node.d.plugin.in \
+ README.md \
+ $(NULL)
+
+usernodeconfigdir=$(configdir)/node.d
+dist_usernodeconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
+nodeconfigdir=$(libconfigdir)/node.d
+dist_nodeconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
+dist_node_DATA = \
+ $(NULL)
+
+include fronius/Makefile.inc
+include named/Makefile.inc
+include sma_webbox/Makefile.inc
+include snmp/Makefile.inc
+include stiebeleltron/Makefile.inc
+
+nodemodulesdir=$(nodedir)/node_modules
+dist_nodemodules_DATA = \
+ node_modules/netdata.js \
+ node_modules/extend.js \
+ node_modules/pixl-xml.js \
+ node_modules/net-snmp.js \
+ node_modules/asn1-ber.js \
+ $(NULL)
+
+nodemoduleslibberdir=$(nodedir)/node_modules/lib/ber
+dist_nodemoduleslibber_DATA = \
+ node_modules/lib/ber/index.js \
+ node_modules/lib/ber/errors.js \
+ node_modules/lib/ber/reader.js \
+ node_modules/lib/ber/types.js \
+ node_modules/lib/ber/writer.js \
+ $(NULL)
diff --git a/collectors/node.d.plugin/Makefile.in b/collectors/node.d.plugin/Makefile.in
new file mode 100644
index 000000000..4aec01dea
--- /dev/null
+++ b/collectors/node.d.plugin/Makefile.in
@@ -0,0 +1,805 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(top_srcdir)/build/subst.inc \
+ $(srcdir)/fronius/Makefile.inc $(srcdir)/named/Makefile.inc \
+ $(srcdir)/sma_webbox/Makefile.inc $(srcdir)/snmp/Makefile.inc \
+ $(srcdir)/stiebeleltron/Makefile.inc $(srcdir)/Makefile.in \
+ $(srcdir)/Makefile.am $(dist_plugins_SCRIPTS) \
+ $(dist_libconfig_DATA) $(dist_node_DATA) \
+ $(dist_nodeconfig_DATA) $(dist_nodemodules_DATA) \
+ $(dist_nodemoduleslibber_DATA) $(dist_noinst_DATA) \
+ $(dist_usernodeconfig_DATA)
+subdir = collectors/node.d.plugin
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pluginsdir)" \
+ "$(DESTDIR)$(libconfigdir)" "$(DESTDIR)$(nodedir)" \
+ "$(DESTDIR)$(nodeconfigdir)" "$(DESTDIR)$(nodemodulesdir)" \
+ "$(DESTDIR)$(nodemoduleslibberdir)" \
+ "$(DESTDIR)$(usernodeconfigdir)"
+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_libconfig_DATA) $(dist_node_DATA) \
+ $(dist_nodeconfig_DATA) $(dist_nodemodules_DATA) \
+ $(dist_nodemoduleslibber_DATA) $(dist_noinst_DATA) \
+ $(dist_usernodeconfig_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+CLEANFILES = \
+ node.d.plugin \
+ $(NULL)
+
+SUFFIXES = .in
+dist_libconfig_DATA = \
+ node.d.conf \
+ $(NULL)
+
+dist_plugins_SCRIPTS = \
+ node.d.plugin \
+ $(NULL)
+
+# dist_nodeconfig_DATA += fronius/fronius.conf
+
+# do not install these files, but include them in the distribution
+# dist_nodeconfig_DATA += named/named.conf
+
+# do not install these files, but include them in the distribution
+# dist_nodeconfig_DATA += sma_webbox/sma_webbox.conf
+
+# do not install these files, but include them in the distribution
+# dist_nodeconfig_DATA += snmp/snmp.conf
+
+# do not install these files, but include them in the distribution
+# dist_nodeconfig_DATA += stiebeleltron/stiebeleltron.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA = node.d.plugin.in README.md $(NULL) \
+ fronius/README.md fronius/Makefile.inc named/README.md \
+ named/Makefile.inc sma_webbox/README.md \
+ sma_webbox/Makefile.inc snmp/README.md snmp/Makefile.inc \
+ stiebeleltron/README.md stiebeleltron/Makefile.inc
+usernodeconfigdir = $(configdir)/node.d
+dist_usernodeconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
+nodeconfigdir = $(libconfigdir)/node.d
+dist_nodeconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+dist_node_DATA = $(NULL) fronius/fronius.node.js named/named.node.js \
+ sma_webbox/sma_webbox.node.js snmp/snmp.node.js \
+ stiebeleltron/stiebeleltron.node.js
+nodemodulesdir = $(nodedir)/node_modules
+dist_nodemodules_DATA = \
+ node_modules/netdata.js \
+ node_modules/extend.js \
+ node_modules/pixl-xml.js \
+ node_modules/net-snmp.js \
+ node_modules/asn1-ber.js \
+ $(NULL)
+
+nodemoduleslibberdir = $(nodedir)/node_modules/lib/ber
+dist_nodemoduleslibber_DATA = \
+ node_modules/lib/ber/index.js \
+ node_modules/lib/ber/errors.js \
+ node_modules/lib/ber/reader.js \
+ node_modules/lib/ber/types.js \
+ node_modules/lib/ber/writer.js \
+ $(NULL)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .in
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/build/subst.inc $(srcdir)/fronius/Makefile.inc $(srcdir)/named/Makefile.inc $(srcdir)/sma_webbox/Makefile.inc $(srcdir)/snmp/Makefile.inc $(srcdir)/stiebeleltron/Makefile.inc $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/node.d.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/node.d.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(top_srcdir)/build/subst.inc $(srcdir)/fronius/Makefile.inc $(srcdir)/named/Makefile.inc $(srcdir)/sma_webbox/Makefile.inc $(srcdir)/snmp/Makefile.inc $(srcdir)/stiebeleltron/Makefile.inc:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-dist_pluginsSCRIPTS: $(dist_plugins_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @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; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pluginsdir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pluginsdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dist_pluginsSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_plugins_SCRIPTS)'; test -n "$(pluginsdir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(pluginsdir)'; $(am__uninstall_files_from_dir)
+install-dist_libconfigDATA: $(dist_libconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_libconfig_DATA)'; test -n "$(libconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(libconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(libconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_libconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_libconfig_DATA)'; test -n "$(libconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(libconfigdir)'; $(am__uninstall_files_from_dir)
+install-dist_nodeDATA: $(dist_node_DATA)
+ @$(NORMAL_INSTALL)
+ @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"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(nodedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(nodedir)" || exit $$?; \
+ done
+
+uninstall-dist_nodeDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_node_DATA)'; test -n "$(nodedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(nodedir)'; $(am__uninstall_files_from_dir)
+install-dist_nodeconfigDATA: $(dist_nodeconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @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"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(nodeconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(nodeconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_nodeconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_nodeconfig_DATA)'; test -n "$(nodeconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(nodeconfigdir)'; $(am__uninstall_files_from_dir)
+install-dist_nodemodulesDATA: $(dist_nodemodules_DATA)
+ @$(NORMAL_INSTALL)
+ @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"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(nodemodulesdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(nodemodulesdir)" || exit $$?; \
+ done
+
+uninstall-dist_nodemodulesDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_nodemodules_DATA)'; test -n "$(nodemodulesdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(nodemodulesdir)'; $(am__uninstall_files_from_dir)
+install-dist_nodemoduleslibberDATA: $(dist_nodemoduleslibber_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_nodemoduleslibber_DATA)'; test -n "$(nodemoduleslibberdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(nodemoduleslibberdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(nodemoduleslibberdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(nodemoduleslibberdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(nodemoduleslibberdir)" || exit $$?; \
+ done
+
+uninstall-dist_nodemoduleslibberDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_nodemoduleslibber_DATA)'; test -n "$(nodemoduleslibberdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(nodemoduleslibberdir)'; $(am__uninstall_files_from_dir)
+install-dist_usernodeconfigDATA: $(dist_usernodeconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_usernodeconfig_DATA)'; test -n "$(usernodeconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(usernodeconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(usernodeconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(usernodeconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(usernodeconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_usernodeconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_usernodeconfig_DATA)'; test -n "$(usernodeconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(usernodeconfigdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(libconfigdir)" "$(DESTDIR)$(nodedir)" "$(DESTDIR)$(nodeconfigdir)" "$(DESTDIR)$(nodemodulesdir)" "$(DESTDIR)$(nodemoduleslibberdir)" "$(DESTDIR)$(usernodeconfigdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_libconfigDATA install-dist_nodeDATA \
+ install-dist_nodeconfigDATA install-dist_nodemodulesDATA \
+ install-dist_nodemoduleslibberDATA install-dist_pluginsSCRIPTS \
+ install-dist_usernodeconfigDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_libconfigDATA uninstall-dist_nodeDATA \
+ uninstall-dist_nodeconfigDATA uninstall-dist_nodemodulesDATA \
+ uninstall-dist_nodemoduleslibberDATA \
+ uninstall-dist_pluginsSCRIPTS \
+ uninstall-dist_usernodeconfigDATA
+
+.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_libconfigDATA \
+ install-dist_nodeDATA install-dist_nodeconfigDATA \
+ install-dist_nodemodulesDATA \
+ install-dist_nodemoduleslibberDATA install-dist_pluginsSCRIPTS \
+ install-dist_usernodeconfigDATA 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_libconfigDATA uninstall-dist_nodeDATA \
+ uninstall-dist_nodeconfigDATA uninstall-dist_nodemodulesDATA \
+ uninstall-dist_nodemoduleslibberDATA \
+ uninstall-dist_pluginsSCRIPTS \
+ uninstall-dist_usernodeconfigDATA
+
+.in:
+ if sed \
+ -e 's#[@]localstatedir_POST@#$(localstatedir)#g' \
+ -e 's#[@]sbindir_POST@#$(sbindir)#g' \
+ -e 's#[@]sysconfdir_POST@#$(sysconfdir)#g' \
+ -e 's#[@]pythondir_POST@#$(pythondir)#g' \
+ -e 's#[@]configdir_POST@#$(configdir)#g' \
+ -e 's#[@]libconfigdir_POST@#$(libconfigdir)#g' \
+ -e 's#[@]cachedir_POST@#$(cachedir)#g' \
+ $< > $@.tmp; then \
+ mv "$@.tmp" "$@"; \
+ else \
+ rm -f "$@.tmp"; \
+ false; \
+ 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.
+.NOEXPORT:
diff --git a/collectors/node.d.plugin/README.md b/collectors/node.d.plugin/README.md
new file mode 100644
index 000000000..dd977017d
--- /dev/null
+++ b/collectors/node.d.plugin/README.md
@@ -0,0 +1,218 @@
+# node.d.plugin
+
+`node.d.plugin` is a netdata external plugin. It is an **orchestrator** for data collection modules written in `node.js`.
+
+1. It runs as an independent process `ps fax` shows it
+2. It is started and stopped automatically by netdata
+3. It communicates with netdata via a unidirectional pipe (sending data to the netdata daemon)
+4. Supports any number of data collection **modules**
+5. Allows each **module** to have one or more data collection **jobs**
+6. Each **job** is collecting one or more metrics from a single data source
+
+# Motivation
+
+Node.js is perfect for asynchronous operations. It is very fast and quite common (actually the whole web is based on it).
+Since data collection is not a CPU intensive task, node.js is an ideal solution for it.
+
+`node.d.plugin` is a netdata plugin that provides an abstraction layer to allow easy and quick development of data
+collectors in node.js. It also manages all its data collectors (placed in `/usr/libexec/netdata/node.d`) using a single
+instance of node, thus lowering the memory footprint of data collection.
+
+Of course, there can be independent plugins written in node.js (placed in `/usr/libexec/netdata/plugins`).
+These will have to be developed using the guidelines of **[External Plugins](../plugins.d/)**.
+
+To run `node.js` plugins you need to have `node` installed in your system.
+
+In some older systems, the package named `node` is not node.js. It is a terminal emulation program called `ax25-node`.
+In this case the node.js package may be referred as `nodejs`. Once you install `nodejs`, we suggest to link
+`/usr/bin/nodejs` to `/usr/bin/node`, so that typing `node` in your terminal, opens node.js.
+For more information check the **[[Installation]]** guide.
+
+## configuring `node.d.plugin`
+
+`node.d.plugin` can work even without any configuration. Its default configuration file is
+[/etc/netdata/node.d.conf](node.d.conf) (to edit it on your system run `/etc/netdata/edit-config node.d.conf`).
+
+## configuring `node.d.plugin` modules
+
+`node.d.plugin` modules accept configuration in `JSON` format.
+
+Unfortunately, `JSON` files do not accept comments. So, the best way to describe them is to have markdown text files
+with instructions.
+
+`JSON` has a very strict formatting. If you get errors from netdata at `/var/log/netdata/error.log` that a certain
+configuration file cannot be loaded, we suggest to verify it at [http://jsonlint.com/](http://jsonlint.com/).
+
+The files in this directory, provide usable examples for configuring each `node.d.plugin` module.
+
+
+## debugging modules written for node.d.plugin
+
+To test `node.d.plugin` modules, which are placed in `/usr/libexec/netdata/node.d`, you can run `node.d.plugin` by hand,
+like this:
+
+```sh
+# become user netdata
+sudo su -s /bin/sh netdata
+
+# run the plugin in debug mode
+/usr/libexec/netdata/plugins.d/node.d.plugin debug 1 X Y Z
+```
+
+`node.d.plugin` will run in `debug` mode (lots of debug info), with an update frequency of `1` second, evaluating only
+the collector scripts `X` (i.e. `/usr/libexec/netdata/node.d/X.node.js`), `Y` and `Z`.
+You can define zero or more modules. If none is defined, `node.d.plugin` will evaluate all modules available.
+
+Keep in mind that if your configs are not in `/etc/netdata`, you should do the following before running `node.d.plugin`:
+
+```sh
+export NETDATA_USER_CONFIG_DIR="/path/to/etc/netdata"
+```
+
+---
+
+## developing `node.d.plugin` modules
+
+Your data collection module should be split in 3 parts:
+
+ - a function to fetch the data from its source. `node.d.plugin` already can fetch data from web sources,
+ so you don't need to do anything about it for http.
+
+ - a function to process the fetched/manipulate the data fetched. This function will make a number of calls
+ to create charts and dimensions and pass the collected values to netdata.
+ This is the only function you need to write for collecting http JSON data.
+
+ - a `configure` and an `update` function, which take care of your module configuration and data refresh
+ respectively. You can use the supplied ones.
+
+Your module will automatically be able to process any number of servers, with different settings (even different
+data collection frequencies). You will write just the work needed for one and `node.d.plugin` will do the rest.
+For each server you are going to fetch data from, you will have to create a `service` (more later).
+
+### writing the data collection module
+
+To provide a module called `mymodule`, you have create the file `/usr/libexec/netdata/node.d/mymodule.node.js`, with this structure:
+
+```js
+
+// the processor is needed only
+// if you need a custom processor
+// other than http
+netdata.processors.myprocessor = {
+ name: 'myprocessor',
+
+ process: function(service, callback) {
+
+ /* do data collection here */
+
+ callback(data);
+ }
+};
+
+// this is the mymodule definition
+var mymodule = {
+ processResponse: function(service, data) {
+
+ /* send information to the netdata server here */
+
+ },
+
+ configure: function(config) {
+ var eligible_services = 0;
+
+ if(typeof(config.servers) === 'undefined' || config.servers.length === 0) {
+
+ /*
+ * create a service using internal defaults;
+ * this is used for auto-detecting the settings
+ * if possible
+ */
+
+ netdata.service({
+ name: 'a name for this service',
+ update_every: this.update_every,
+ module: this,
+ processor: netdata.processors.myprocessor,
+ // any other information your processor needs
+ }).execute(this.processResponse);
+
+ eligible_services++;
+ }
+ else {
+
+ /*
+ * create a service for each server in the
+ * configuration file
+ */
+
+ var len = config.servers.length;
+ while(len--) {
+ var server = config.servers[len];
+
+ netdata.service({
+ name: server.name,
+ update_every: server.update_every,
+ module: this,
+ processor: netdata.processors.myprocessor,
+ // any other information your processor needs
+ }).execute(this.processResponse);
+
+ eligible_services++;
+ }
+ }
+
+ return eligible_services;
+ },
+
+ update: function(service, callback) {
+
+ /*
+ * this function is called when each service
+ * created by the configure function, needs to
+ * collect updated values.
+ *
+ * You normally will not need to change it.
+ */
+
+ service.execute(function(service, data) {
+ mymodule.processResponse(service, data);
+ callback();
+ });
+ },
+};
+
+module.exports = mymodule;
+```
+
+#### configure(config)
+
+`configure(config)` is called just once, when `node.d.plugin` starts.
+The config file will contain the contents of `/etc/netdata/node.d/mymodule.conf`.
+This file should have the following format:
+
+```js
+{
+ "enable_autodetect": false,
+ "update_every": 5,
+ "servers": [ { /* server 1 */ }, { /* server 2 */ } ]
+}
+```
+
+If the config file `/etc/netdata/node.d/mymodule.conf` does not give a `enable_autodetect` or `update_every`, these
+will be added by `node.d.plugin`. So you module will always have them.
+
+The configuration file `/etc/netdata/node.d/mymodule.conf` may contain whatever else is needed for `mymodule`.
+
+#### processResponse(data)
+
+`data` may be `null` or whatever the processor specified in the `service` returned.
+
+The `service` object defines a set of functions to allow you send information to the netdata core about:
+
+1. Charts and dimension definitions
+2. Updated values, from the collected values
+
+---
+
+*FIXME: document an operational node.d.plugin data collector - the best example is the
+[snmp collector](snmp/snmp.node.js)*
diff --git a/collectors/node.d.plugin/fronius/Makefile.inc b/collectors/node.d.plugin/fronius/Makefile.inc
new file mode 100644
index 000000000..da0743a88
--- /dev/null
+++ b/collectors/node.d.plugin/fronius/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_node_DATA += fronius/fronius.node.js
+# dist_nodeconfig_DATA += fronius/fronius.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += fronius/README.md fronius/Makefile.inc
+
diff --git a/conf.d/node.d/fronius.conf.md b/collectors/node.d.plugin/fronius/README.md
index 622086b27..dd2846990 100644
--- a/conf.d/node.d/fronius.conf.md
+++ b/collectors/node.d.plugin/fronius/README.md
@@ -1,3 +1,56 @@
+# fronius
+
+This module collects metrics from the configured solar power installation from Fronius Symo.
+
+**Requirements**
+ * Configuration file `fronius.conf` in the node.d netdata config dir (default: `/etc/netdata/node.d/fronius.conf`)
+ * Fronius Symo with network access (http)
+
+It produces per server:
+
+1. **Power**
+ * Current power input from the grid (positive values), output to the grid (negative values), in W
+ * Current power input from the solar panels, in W
+ * Current power stored in the accumulator (if present), in W (in theory, untested)
+
+2. **Consumption**
+ * Local consumption in W
+
+3. **Autonomy**
+ * Relative autonomy in %. 100 % autonomy means that the solar panels are delivering more power than it is needed by local consumption.
+ * Relative self consumption in %. The lower the better
+
+4. **Energy**
+ * The energy produced during the current day, in kWh
+ * The energy produced during the current year, in kWh
+
+5. **Inverter**
+ * The current power output from the connected inverters, in W, one dimension per inverter. At least one is always present.
+
+
+### configuration
+
+Sample:
+
+```json
+{
+ "enable_autodetect": false,
+ "update_every": 5,
+ "servers": [
+ {
+ "name": "Symo",
+ "hostname": "symo.ip.or.dns",
+ "update_every": 5,
+ "api_path": "/solar_api/v1/GetPowerFlowRealtimeData.fcgi"
+ }
+ ]
+}
+```
+
+If no configuration is given, the module will be disabled. Each `update_every` is optional, the default is `5`.
+
+---
+
[Fronius Symo 8.2](https://www.fronius.com/en/photovoltaics/products/all-products/inverters/fronius-symo/fronius-symo-8-2-3-m)
The plugin has been tested with a single inverter, namely Fronius Symo 8.2-3-M:
diff --git a/node.d/fronius.node.js b/collectors/node.d.plugin/fronius/fronius.node.js
index fc49e5d38..436f3a325 100644
--- a/node.d/fronius.node.js
+++ b/collectors/node.d.plugin/fronius/fronius.node.js
@@ -1,12 +1,13 @@
"use strict";
+// SPDX-License-Identifier: GPL-3.0-or-later
// This program will connect to one or more Fronius Symo Inverters.
// to get the Solar Power Generated (current, today).
// example configuration in netdata/conf.d/node.d/fronius.conf.md
-var url = require("url");
-var http = require("http");
+require("url");
+require("http");
var netdata = require("netdata");
netdata.debug("loaded " + __filename + " plugin");
diff --git a/collectors/node.d.plugin/named/Makefile.inc b/collectors/node.d.plugin/named/Makefile.inc
new file mode 100644
index 000000000..95f423012
--- /dev/null
+++ b/collectors/node.d.plugin/named/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_node_DATA += named/named.node.js
+# dist_nodeconfig_DATA += named/named.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += named/README.md named/Makefile.inc
+
diff --git a/conf.d/node.d/named.conf.md b/collectors/node.d.plugin/named/README.md
index fa843dd58..977a5015f 100644
--- a/conf.d/node.d/named.conf.md
+++ b/collectors/node.d.plugin/named/README.md
@@ -2,8 +2,6 @@
Using this netdata collector, you can monitor one or more ISC Bind servers.
-The source code for this plugin in [here](https://github.com/firehol/netdata/blob/master/node.d/named.node.js).
-
## Example netdata charts
Depending on the number of views your bind has, you may get a large number of charts.
diff --git a/node.d/named.node.js b/collectors/node.d.plugin/named/named.node.js
index 02c890c60..d13c608cb 100644
--- a/node.d/named.node.js
+++ b/collectors/node.d.plugin/named/named.node.js
@@ -1,4 +1,5 @@
'use strict';
+// SPDX-License-Identifier: GPL-3.0-or-later
// collect statistics from bind (named) v9.10+
//
@@ -36,8 +37,8 @@ statistics-channels {
};
*/
-var url = require('url');
-var http = require('http');
+require('url');
+require('http');
var XML = require('pixl-xml');
var netdata = require('netdata');
@@ -79,11 +80,11 @@ var named = {
multiplier: multiplier, // the multiplier
divisor: divisor, // the divisor
hidden: false // is hidden (boolean)
- }
+ };
}
}
- if(found === false)
+ if(!found)
return null;
chart = service.chart(id, chart);
diff --git a/conf.d/node.d.conf b/collectors/node.d.plugin/node.d.conf
index 95aec99ce..95aec99ce 100644
--- a/conf.d/node.d.conf
+++ b/collectors/node.d.plugin/node.d.conf
diff --git a/plugins.d/node.d.plugin b/collectors/node.d.plugin/node.d.plugin
index b16203912..2570220c2 100755..100644
--- a/plugins.d/node.d.plugin
+++ b/collectors/node.d.plugin/node.d.plugin
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-':' //; exec "$(command -v nodejs || command -v node || command -v js || echo "ERROR node.js IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@"
+':' //; exec "$(command -v nodejs || command -v node || echo "ERROR node IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@"
// shebang hack from:
// http://unix.stackexchange.com/questions/65235/universal-node-js-shebang
@@ -11,7 +11,7 @@
// netdata
// real-time performance and health monitoring, done right!
// (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
-// GPL v3+
+// SPDX-License-Identifier: GPL-3.0-or-later
// --------------------------------------------------------------------------------------------------------------------
@@ -21,7 +21,8 @@
// get NETDATA environment variables
var NETDATA_PLUGINS_DIR = process.env.NETDATA_PLUGINS_DIR || __dirname;
-var NETDATA_CONFIG_DIR = process.env.NETDATA_CONFIG_DIR || __dirname + '/../../../../etc/netdata';
+var NETDATA_USER_CONFIG_DIR = process.env.NETDATA_USER_CONFIG_DIR || '/usr/local/etc/netdata';
+var NETDATA_STOCK_CONFIG_DIR = process.env.NETDATA_STOCK_CONFIG_DIR || '/usr/local/lib/netdata/conf.d';
var NETDATA_UPDATE_EVERY = process.env.NETDATA_UPDATE_EVERY || 1;
var NODE_D_DIR = NETDATA_PLUGINS_DIR + '/../node.d';
@@ -45,20 +46,42 @@ var netdata = require('netdata');
// --------------------------------------------------------------------------------------------------------------------
// configuration
-function pluginConfig(filename) {
- var f = path.basename(filename);
+function netdata_read_json_config_file(module_filename) {
+ var f = path.basename(module_filename);
+
+ var ufilename, sfilename;
- // node.d.plugin configuration
var m = f.match('.plugin' + '$');
- if(m !== null)
- return netdata.options.paths.config + '/' + f.substring(0, m.index) + '.conf';
+ if(m !== null) {
+ ufilename = netdata.options.paths.config + '/' + f.substring(0, m.index) + '.conf';
+ sfilename = netdata.options.paths.stock_config + '/' + f.substring(0, m.index) + '.conf';
+ }
- // node.d modules configuration
m = f.match('.node.js' + '$');
- if(m !== null)
- return netdata.options.paths.config + '/node.d/' + f.substring(0, m.index) + '.conf';
+ if(m !== null) {
+ ufilename = netdata.options.paths.config + '/node.d/' + f.substring(0, m.index) + '.conf';
+ sfilename = netdata.options.paths.stock_config + '/node.d/' + f.substring(0, m.index) + '.conf';
+ }
+
+ try {
+ netdata.debug('loading module\'s ' + module_filename + ' user-config ' + ufilename);
+ return JSON.parse(fs.readFileSync(ufilename, 'utf8'));
+ }
+ catch(e) {
+ netdata.error('Cannot read user-configuration file ' + ufilename + ': ' + e.message + '.');
+ dumpError(e);
+ }
- return netdata.options.paths.config + '/node.d/' + f + '.conf';
+ try {
+ netdata.debug('loading module\'s ' + module_filename + ' stock-config ' + sfilename);
+ return JSON.parse(fs.readFileSync(sfilename, 'utf8'));
+ }
+ catch(e) {
+ netdata.error('Cannot read stock-configuration file ' + sfilename + ': ' + e.message + ', using internal defaults.');
+ dumpError(e);
+ }
+
+ return {};
}
// internal defaults
@@ -69,35 +92,31 @@ extend(true, netdata.options, {
paths: {
plugins: NETDATA_PLUGINS_DIR,
- config: NETDATA_CONFIG_DIR,
- modules: [],
+ config: NETDATA_USER_CONFIG_DIR,
+ stock_config: NETDATA_STOCK_CONFIG_DIR,
+ modules: []
},
modules_enable_autodetect: true,
modules_enable_all: true,
- modules: {},
+ modules: {}
});
-netdata.options.config_filename = pluginConfig(__filename);
// load configuration file
-try {
- netdata.options_loaded = JSON.parse(fs.readFileSync(netdata.options.config_filename, 'utf8'));
- extend(true, netdata.options, netdata.options_loaded);
+netdata.options_loaded = netdata_read_json_config_file(__filename);
+extend(true, netdata.options, netdata.options_loaded);
- if(!netdata.options.paths.plugins)
- netdata.options.paths.plugins = NETDATA_PLUGINS_DIR;
+if(!netdata.options.paths.plugins)
+ netdata.options.paths.plugins = NETDATA_PLUGINS_DIR;
- if(!netdata.options.paths.config)
- netdata.options.paths.config = NETDATA_CONFIG_DIR;
+if(!netdata.options.paths.config)
+ netdata.options.paths.config = NETDATA_USER_CONFIG_DIR;
- // console.error('merged netdata object:');
- // console.error(util.inspect(netdata, {depth: 10}));
-}
-catch(e) {
- netdata.error('Cannot read configuration file ' + netdata.options.config_filename + ': ' + e.message + ', using internal defaults.');
- netdata.options_loaded = undefined;
- dumpError(e);
-}
+if(!netdata.options.paths.stock_config)
+ netdata.options.paths.stock_config = NETDATA_STOCK_CONFIG_DIR;
+
+// console.error('merged netdata object:');
+// console.error(util.inspect(netdata, {depth: 10}));
// apply module paths to node.js process
@@ -206,9 +225,6 @@ function findModules() {
netdata.options.modules[n].filename = NODE_D_DIR + '/' + files[len];
netdata.options.modules[n].loaded = false;
- if(typeof(netdata.options.modules[n].config_filename) !== 'string')
- netdata.options.modules[n].config_filename = pluginConfig(files[len]);
-
// load the module
try {
netdata.debug('loading module ' + netdata.options.modules[n].filename);
@@ -228,16 +244,9 @@ function findModules() {
enable_autodetect: netdata.options.modules_enable_autodetect,
update_every: netdata.options.update_every
};
- try {
- netdata.debug('loading module\'s ' + netdata.options.modules[n].name + ' config ' + netdata.options.modules[n].config_filename);
- var c2 = JSON.parse(fs.readFileSync(netdata.options.modules[n].config_filename, 'utf8'));
- extend(true, c, c2);
- netdata.debug('loaded module\'s ' + netdata.options.modules[n].name + ' config ' + netdata.options.modules[n].config_filename);
- }
- catch(e) {
- netdata.error('Cannot load module\'s ' + netdata.options.modules[n].name + ' config from ' + netdata.options.modules[n].config_filename + ' exception: ' + e + ', using internal defaults.');
- dumpError(e);
- }
+
+ var c2 = netdata_read_json_config_file(files[len]);
+ extend(true, c, c2);
// call module auto-detection / configuration
try {
diff --git a/collectors/node.d.plugin/node.d.plugin.in b/collectors/node.d.plugin/node.d.plugin.in
new file mode 100755
index 000000000..05c126e90
--- /dev/null
+++ b/collectors/node.d.plugin/node.d.plugin.in
@@ -0,0 +1,303 @@
+#!/usr/bin/env bash
+':' //; exec "$(command -v nodejs || command -v node || echo "ERROR node IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@"
+
+// shebang hack from:
+// http://unix.stackexchange.com/questions/65235/universal-node-js-shebang
+
+// Initially this is run as a shell script.
+// Then, the second line, finds nodejs or node or js in the system path
+// and executes it with the shell parameters.
+
+// netdata
+// real-time performance and health monitoring, done right!
+// (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// --------------------------------------------------------------------------------------------------------------------
+
+'use strict';
+
+// --------------------------------------------------------------------------------------------------------------------
+// get NETDATA environment variables
+
+var NETDATA_PLUGINS_DIR = process.env.NETDATA_PLUGINS_DIR || __dirname;
+var NETDATA_USER_CONFIG_DIR = process.env.NETDATA_USER_CONFIG_DIR || '@configdir_POST@';
+var NETDATA_STOCK_CONFIG_DIR = process.env.NETDATA_STOCK_CONFIG_DIR || '@libconfigdir_POST@';
+var NETDATA_UPDATE_EVERY = process.env.NETDATA_UPDATE_EVERY || 1;
+var NODE_D_DIR = NETDATA_PLUGINS_DIR + '/../node.d';
+
+// make sure the modules are found
+process.mainModule.paths.unshift(NODE_D_DIR + '/node_modules');
+process.mainModule.paths.unshift(NODE_D_DIR);
+
+
+// --------------------------------------------------------------------------------------------------------------------
+// load required modules
+
+var fs = require('fs');
+var url = require('url');
+var util = require('util');
+var http = require('http');
+var path = require('path');
+var extend = require('extend');
+var netdata = require('netdata');
+
+
+// --------------------------------------------------------------------------------------------------------------------
+// configuration
+
+function netdata_read_json_config_file(module_filename) {
+ var f = path.basename(module_filename);
+
+ var ufilename, sfilename;
+
+ var m = f.match('.plugin' + '$');
+ if(m !== null) {
+ ufilename = netdata.options.paths.config + '/' + f.substring(0, m.index) + '.conf';
+ sfilename = netdata.options.paths.stock_config + '/' + f.substring(0, m.index) + '.conf';
+ }
+
+ m = f.match('.node.js' + '$');
+ if(m !== null) {
+ ufilename = netdata.options.paths.config + '/node.d/' + f.substring(0, m.index) + '.conf';
+ sfilename = netdata.options.paths.stock_config + '/node.d/' + f.substring(0, m.index) + '.conf';
+ }
+
+ try {
+ netdata.debug('loading module\'s ' + module_filename + ' user-config ' + ufilename);
+ return JSON.parse(fs.readFileSync(ufilename, 'utf8'));
+ }
+ catch(e) {
+ netdata.error('Cannot read user-configuration file ' + ufilename + ': ' + e.message + '.');
+ dumpError(e);
+ }
+
+ try {
+ netdata.debug('loading module\'s ' + module_filename + ' stock-config ' + sfilename);
+ return JSON.parse(fs.readFileSync(sfilename, 'utf8'));
+ }
+ catch(e) {
+ netdata.error('Cannot read stock-configuration file ' + sfilename + ': ' + e.message + ', using internal defaults.');
+ dumpError(e);
+ }
+
+ return {};
+}
+
+// internal defaults
+extend(true, netdata.options, {
+ filename: path.basename(__filename),
+
+ update_every: NETDATA_UPDATE_EVERY,
+
+ paths: {
+ plugins: NETDATA_PLUGINS_DIR,
+ config: NETDATA_USER_CONFIG_DIR,
+ stock_config: NETDATA_STOCK_CONFIG_DIR,
+ modules: []
+ },
+
+ modules_enable_autodetect: true,
+ modules_enable_all: true,
+ modules: {}
+});
+
+// load configuration file
+netdata.options_loaded = netdata_read_json_config_file(__filename);
+extend(true, netdata.options, netdata.options_loaded);
+
+if(!netdata.options.paths.plugins)
+ netdata.options.paths.plugins = NETDATA_PLUGINS_DIR;
+
+if(!netdata.options.paths.config)
+ netdata.options.paths.config = NETDATA_USER_CONFIG_DIR;
+
+if(!netdata.options.paths.stock_config)
+ netdata.options.paths.stock_config = NETDATA_STOCK_CONFIG_DIR;
+
+// console.error('merged netdata object:');
+// console.error(util.inspect(netdata, {depth: 10}));
+
+
+// apply module paths to node.js process
+function applyModulePaths() {
+ var len = netdata.options.paths.modules.length;
+ while(len--)
+ process.mainModule.paths.unshift(netdata.options.paths.modules[len]);
+}
+applyModulePaths();
+
+
+// --------------------------------------------------------------------------------------------------------------------
+// tracing
+
+function dumpError(err) {
+ if (typeof err === 'object') {
+ if (err.stack) {
+ netdata.debug(err.stack);
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// get command line arguments
+{
+ var found_myself = false;
+ var found_number = false;
+ var found_modules = false;
+ process.argv.forEach(function (val, index, array) {
+ netdata.debug('PARAM: ' + val);
+
+ if(!found_myself) {
+ if(val === __filename)
+ found_myself = true;
+ }
+ else {
+ switch(val) {
+ case 'debug':
+ netdata.options.DEBUG = true;
+ netdata.debug('DEBUG enabled');
+ break;
+
+ default:
+ if(found_number === true) {
+ if(found_modules === false) {
+ for(var i in netdata.options.modules)
+ netdata.options.modules[i].enabled = false;
+ }
+
+ if(typeof netdata.options.modules[val] === 'undefined')
+ netdata.options.modules[val] = {};
+
+ netdata.options.modules[val].enabled = true;
+ netdata.options.modules_enable_all = false;
+ netdata.debug('enabled module ' + val);
+ }
+ else {
+ try {
+ var x = parseInt(val);
+ if(x > 0) {
+ netdata.options.update_every = x;
+ if(netdata.options.update_every < NETDATA_UPDATE_EVERY) {
+ netdata.options.update_every = NETDATA_UPDATE_EVERY;
+ netdata.debug('Update frequency ' + x + 's is too low');
+ }
+
+ found_number = true;
+ netdata.debug('Update frequency set to ' + netdata.options.update_every + ' seconds');
+ }
+ else netdata.error('Ignoring parameter: ' + val);
+ }
+ catch(e) {
+ netdata.error('Cannot get value of parameter: ' + val);
+ dumpError(e);
+ }
+ }
+ break;
+ }
+ }
+ });
+}
+
+if(netdata.options.update_every < 1) {
+ netdata.debug('Adjusting update frequency to 1 second');
+ netdata.options.update_every = 1;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// find modules
+
+function findModules() {
+ var found = 0;
+
+ var files = fs.readdirSync(NODE_D_DIR);
+ var len = files.length;
+ while(len--) {
+ var m = files[len].match('.node.js' + '$');
+ if(m !== null) {
+ var n = files[len].substring(0, m.index);
+
+ if(typeof(netdata.options.modules[n]) === 'undefined')
+ netdata.options.modules[n] = { name: n, enabled: netdata.options.modules_enable_all };
+
+ if(netdata.options.modules[n].enabled === true) {
+ netdata.options.modules[n].name = n;
+ netdata.options.modules[n].filename = NODE_D_DIR + '/' + files[len];
+ netdata.options.modules[n].loaded = false;
+
+ // load the module
+ try {
+ netdata.debug('loading module ' + netdata.options.modules[n].filename);
+ netdata.options.modules[n].module = require(netdata.options.modules[n].filename);
+ netdata.options.modules[n].module.name = n;
+ netdata.debug('loaded module ' + netdata.options.modules[n].name + ' from ' + netdata.options.modules[n].filename);
+ }
+ catch(e) {
+ netdata.options.modules[n].enabled = false;
+ netdata.error('Cannot load module: ' + netdata.options.modules[n].filename + ' exception: ' + e);
+ dumpError(e);
+ continue;
+ }
+
+ // load its configuration
+ var c = {
+ enable_autodetect: netdata.options.modules_enable_autodetect,
+ update_every: netdata.options.update_every
+ };
+
+ var c2 = netdata_read_json_config_file(files[len]);
+ extend(true, c, c2);
+
+ // call module auto-detection / configuration
+ try {
+ netdata.modules_configuring++;
+ netdata.debug('Configuring module ' + netdata.options.modules[n].name);
+ var serv = netdata.configure(netdata.options.modules[n].module, c, function() {
+ netdata.debug('Configured module ' + netdata.options.modules[n].name);
+ netdata.modules_configuring--;
+ });
+
+ netdata.debug('Configuring module ' + netdata.options.modules[n].name + ' reports ' + serv + ' eligible services.');
+ }
+ catch(e) {
+ netdata.modules_configuring--;
+ netdata.options.modules[n].enabled = false;
+ netdata.error('Failed module auto-detection: ' + netdata.options.modules[n].name + ' exception: ' + e + ', disabling module.');
+ dumpError(e);
+ continue;
+ }
+
+ netdata.options.modules[n].loaded = true;
+ found++;
+ }
+ }
+ }
+
+ // netdata.debug(netdata.options.modules);
+ return found;
+}
+
+if(findModules() === 0) {
+ netdata.error('Cannot load any .node.js module from: ' + NODE_D_DIR);
+ netdata.disableNodePlugin();
+ process.exit(1);
+}
+
+
+// --------------------------------------------------------------------------------------------------------------------
+// start
+
+function start_when_configuring_ends() {
+ if(netdata.modules_configuring > 0) {
+ netdata.debug('Waiting modules configuration, still running ' + netdata.modules_configuring);
+ setTimeout(start_when_configuring_ends, 500);
+ return;
+ }
+
+ netdata.modules_configuring = 0;
+ netdata.start();
+}
+start_when_configuring_ends();
+
+//netdata.debug('netdata object:')
+//netdata.debug(netdata);
diff --git a/node.d/node_modules/asn1-ber.js b/collectors/node.d.plugin/node_modules/asn1-ber.js
index 57809f486..55c8f688e 100644
--- a/node.d/node_modules/asn1-ber.js
+++ b/collectors/node.d.plugin/node_modules/asn1-ber.js
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
var Ber = require('./lib/ber/index')
diff --git a/node.d/node_modules/extend.js b/collectors/node.d.plugin/node_modules/extend.js
index 0fdd8be22..3cd2e9155 100644
--- a/node.d/node_modules/extend.js
+++ b/collectors/node.d.plugin/node_modules/extend.js
@@ -1,4 +1,5 @@
// https://github.com/justmoon/node-extend
+// SPDX-License-Identifier: MIT
'use strict';
diff --git a/node.d/node_modules/lib/ber/errors.js b/collectors/node.d.plugin/node_modules/lib/ber/errors.js
index 0106747e6..1c0df7b13 100644
--- a/node.d/node_modules/lib/ber/errors.js
+++ b/collectors/node.d.plugin/node_modules/lib/ber/errors.js
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
module.exports = {
InvalidAsn1Error: function(msg) {
diff --git a/node.d/node_modules/lib/ber/index.js b/collectors/node.d.plugin/node_modules/lib/ber/index.js
index 65985c1e1..eb69ec526 100644
--- a/node.d/node_modules/lib/ber/index.js
+++ b/collectors/node.d.plugin/node_modules/lib/ber/index.js
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
var errors = require('./errors')
var types = require('./types')
diff --git a/node.d/node_modules/lib/ber/reader.js b/collectors/node.d.plugin/node_modules/lib/ber/reader.js
index f93d829aa..06decf4b9 100644
--- a/node.d/node_modules/lib/ber/reader.js
+++ b/collectors/node.d.plugin/node_modules/lib/ber/reader.js
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
var assert = require('assert');
diff --git a/node.d/node_modules/lib/ber/types.js b/collectors/node.d.plugin/node_modules/lib/ber/types.js
index 345824bb1..7519ddcf5 100644
--- a/node.d/node_modules/lib/ber/types.js
+++ b/collectors/node.d.plugin/node_modules/lib/ber/types.js
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
module.exports = {
EOC: 0,
diff --git a/node.d/node_modules/lib/ber/writer.js b/collectors/node.d.plugin/node_modules/lib/ber/writer.js
index bf9805886..d3a718f14 100644
--- a/node.d/node_modules/lib/ber/writer.js
+++ b/collectors/node.d.plugin/node_modules/lib/ber/writer.js
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
var assert = require('assert');
var ASN1 = require('./types');
diff --git a/node.d/node_modules/net-snmp.js b/collectors/node.d.plugin/node_modules/net-snmp.js
index ac9a8d350..484597dcb 100644
--- a/node.d/node_modules/net-snmp.js
+++ b/collectors/node.d.plugin/node_modules/net-snmp.js
@@ -1,5 +1,6 @@
// Copyright 2013 Stephen Vickers <stephen.vickers.sv@gmail.com>
+// SPDX-License-Identifier: MIT
var ber = require ("asn1-ber").Ber;
var dgram = require ("dgram");
@@ -577,6 +578,10 @@ var Session = function (target, community, options) {
? parseInt(options.sourcePort)
: undefined;
+ this.idBitsSize = (options && options.idBitsSize)
+ ? parseInt(options.idBitsSize)
+ : 32;
+
this.reqs = {};
this.reqCount = 0;
@@ -608,8 +613,11 @@ Session.prototype.cancelRequests = function (error) {
}
};
-function _generateId () {
- return Math.floor (Math.random () + Math.random () * 10000000)
+function _generateId (bitSize) {
+ if (bitSize === 16) {
+ return Math.floor(Math.random() * 10000) % 65535;
+ }
+ return Math.floor(Math.random() * 100000000) % 4294967295;
}
Session.prototype.get = function (oids, responseCb) {
@@ -1043,7 +1051,7 @@ Session.prototype.simpleGet = function (pduClass, feedCb, varbinds,
var req = {};
try {
- var id = _generateId ();
+ var id = _generateId (this.idBitsSize);
var pdu = new pduClass (id, varbinds, options);
var message = new RequestMessage (this.version, this.community, pdu);
@@ -1289,7 +1297,7 @@ Session.prototype.trap = function () {
pduVarbinds.push (varbind);
}
- var id = _generateId ();
+ var id = _generateId (this.idBitsSize);
if (this.version == Version2c) {
if (typeof typeOrOid != "string")
diff --git a/node.d/node_modules/netdata.js b/collectors/node.d.plugin/node_modules/netdata.js
index 4ab8308c1..603922c6e 100644
--- a/node.d/node_modules/netdata.js
+++ b/collectors/node.d.plugin/node_modules/netdata.js
@@ -3,7 +3,7 @@
// netdata
// real-time performance and health monitoring, done right!
// (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
-// GPL v3+
+// SPDX-License-Identifier: GPL-3.0-or-later
var url = require('url');
var http = require('http');
diff --git a/node.d/node_modules/pixl-xml.js b/collectors/node.d.plugin/node_modules/pixl-xml.js
index 481acbaeb..48de89e77 100644
--- a/node.d/node_modules/pixl-xml.js
+++ b/collectors/node.d.plugin/node_modules/pixl-xml.js
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
/*
JavaScript XML Library
Plus a bunch of object utility functions
diff --git a/collectors/node.d.plugin/sma_webbox/Makefile.inc b/collectors/node.d.plugin/sma_webbox/Makefile.inc
new file mode 100644
index 000000000..38f2fe97a
--- /dev/null
+++ b/collectors/node.d.plugin/sma_webbox/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_node_DATA += sma_webbox/sma_webbox.node.js
+# dist_nodeconfig_DATA += sma_webbox/sma_webbox.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += sma_webbox/README.md sma_webbox/Makefile.inc
+
diff --git a/conf.d/node.d/sma_webbox.conf.md b/collectors/node.d.plugin/sma_webbox/README.md
index 19fdc9dd3..1512c7008 100644
--- a/conf.d/node.d/sma_webbox.conf.md
+++ b/collectors/node.d.plugin/sma_webbox/README.md
@@ -1,5 +1,5 @@
-[SMA Sunny Webbox](http://www.solar-is-future.com/sma-technology-for-our-future/products/sunny-webbox/index.html)
+[SMA Sunny Webbox](http://files.sma.de/dl/4253/WEBBOX-DUS131916W.pdf)
Example netdata configuration for node.d/sma_webbox.conf
diff --git a/node.d/sma_webbox.node.js b/collectors/node.d.plugin/sma_webbox/sma_webbox.node.js
index 3d99943d4..b9a168adc 100644
--- a/node.d/sma_webbox.node.js
+++ b/collectors/node.d.plugin/sma_webbox/sma_webbox.node.js
@@ -1,4 +1,5 @@
'use strict';
+// SPDX-License-Identifier: GPL-3.0-or-later
// This program will connect to one or more SMA Sunny Webboxes
// to get the Solar Power Generated (current, today, total).
@@ -23,8 +24,8 @@
}
*/
-var url = require('url');
-var http = require('http');
+require('url');
+require('http');
var netdata = require('netdata');
if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
diff --git a/collectors/node.d.plugin/snmp/Makefile.inc b/collectors/node.d.plugin/snmp/Makefile.inc
new file mode 100644
index 000000000..26448a1ce
--- /dev/null
+++ b/collectors/node.d.plugin/snmp/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_node_DATA += snmp/snmp.node.js
+# dist_nodeconfig_DATA += snmp/snmp.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += snmp/README.md snmp/Makefile.inc
+
diff --git a/conf.d/node.d/snmp.conf.md b/collectors/node.d.plugin/snmp/README.md
index 6b496f7a8..a307a3642 100644
--- a/conf.d/node.d/snmp.conf.md
+++ b/collectors/node.d.plugin/snmp/README.md
@@ -10,8 +10,6 @@ This collector supports:
- 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.
@@ -23,7 +21,7 @@ In this example:
- 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
+```json
{
"enable_autodetect": false,
"update_every": 5,
@@ -105,7 +103,7 @@ Each of the 24 new charts will have its id (1-24) appended at:
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
+```json
{
"enable_autodetect": false,
"update_every": 10,
@@ -154,7 +152,7 @@ The `options` given for each server, are:
- `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
+## Retrieving names from snmp
You can append a value retrieved from SNMP to the title, by adding `titleoid` to the chart.
@@ -177,7 +175,7 @@ If it works, restart netdata to activate the snmp collector and refresh the dash
## 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).
+Keep in mind that many SNMP switches and 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.
@@ -210,7 +208,7 @@ This switch also reports various other metrics, like snmp, packets per port, etc
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
+```json
{
"enable_autodetect": false,
"update_every": 5,
diff --git a/node.d/snmp.node.js b/collectors/node.d.plugin/snmp/snmp.node.js
index 3e7027958..a051d3d3a 100644
--- a/node.d/snmp.node.js
+++ b/collectors/node.d.plugin/snmp/snmp.node.js
@@ -1,4 +1,5 @@
'use strict';
+// SPDX-License-Identifier: GPL-3.0-or-later
// netdata snmp module
// This program will connect to one or more SNMP Agents
//
@@ -170,7 +171,7 @@ netdata.processors.snmp = {
var oid = this.fixoid(dim.oid);
var oidname = this.fixoid(dim.oidname);
-
+
if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c + ', dimension: ' + d + ', OID: ' + oid + ", OID name: " + oidname);
@@ -275,14 +276,16 @@ netdata.processors.snmp = {
switch(varbinds[i].type) {
case net_snmp.ObjectType.OctetString:
- if(service.snmp_oids_index[varbinds[i].oid].type !== 'title')
+ if (service.snmp_oids_index[varbinds[i].oid].type !== 'title' && service.snmp_oids_index[varbinds[i].oid].type !== 'name') {
// parse floating point values, exposed as strings
value = parseFloat(varbinds[i].value) * 1000;
- if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof(varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as float in string)");
- else
+ if (__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof(varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as float in string)");
+ }
+ else {
// just use the string
value = varbinds[i].value;
- if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof(varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as string)");
+ if (__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof(varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as string)");
+ }
break;
case net_snmp.ObjectType.Counter64:
@@ -306,7 +309,7 @@ netdata.processors.snmp = {
if(value !== null) {
switch(service.snmp_oids_index[varbinds[i].oid].type) {
case 'title': service.snmp_oids_index[varbinds[i].oid].link.title += ' ' + value; break;
- case 'name' : service.snmp_oids_index[varbinds[i].oid].link.name = value; break;
+ case 'name' : service.snmp_oids_index[varbinds[i].oid].link.name = value.toString().replace(/\W/g, '_'); break;
case 'value': service.snmp_oids_index[varbinds[i].oid].link.value = value; break;
}
}
@@ -445,7 +448,7 @@ var snmp = {
var id = c + from.toString();
var chart = extend(true, {}, service_request_chart);
chart.title += from.toString();
-
+
if(typeof chart.titleoid !== 'undefined')
chart.titleoid += from.toString();
diff --git a/collectors/node.d.plugin/stiebeleltron/Makefile.inc b/collectors/node.d.plugin/stiebeleltron/Makefile.inc
new file mode 100644
index 000000000..0c6e1e213
--- /dev/null
+++ b/collectors/node.d.plugin/stiebeleltron/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_node_DATA += stiebeleltron/stiebeleltron.node.js
+# dist_nodeconfig_DATA += stiebeleltron/stiebeleltron.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += stiebeleltron/README.md stiebeleltron/Makefile.inc
+
diff --git a/conf.d/node.d/stiebeleltron.conf.md b/collectors/node.d.plugin/stiebeleltron/README.md
index 6ae5aa1c7..002a31571 100644
--- a/conf.d/node.d/stiebeleltron.conf.md
+++ b/collectors/node.d.plugin/stiebeleltron/README.md
@@ -1,3 +1,55 @@
+# stiebel eltron
+
+This module collects metrics from the configured heat pump and hot water installation from Stiebel Eltron ISG web.
+
+**Requirements**
+ * Configuration file `stiebeleltron.conf` in the node.d netdata config dir (default: `/etc/netdata/node.d/stiebeleltron.conf`)
+ * Stiebel Eltron ISG web with network access (http), without password login
+
+The charts are configurable, however, the provided default configuration collects the following:
+
+1. **General**
+ * Outside temperature in C
+ * Condenser temperature in C
+ * Heating circuit pressure in bar
+ * Flow rate in l/min
+ * Output of water and heat pumps in %
+
+2. **Heating**
+ * Heat circuit 1 temperature in C (set/actual)
+ * Heat circuit 2 temperature in C (set/actual)
+ * Flow temperature in C (set/actual)
+ * Buffer temperature in C (set/actual)
+ * Pre-flow temperature in C
+
+3. **Hot Water**
+ * Hot water temperature in C (set/actual)
+
+4. **Room Temperature**
+ * Heat circuit 1 room temperature in C (set/actual)
+ * Heat circuit 2 room temperature in C (set/actual)
+
+5. **Eletric Reheating**
+ * Dual Mode Reheating temperature in C (hot water/heating)
+
+6. **Process Data**
+ * Remaining compressor rest time in s
+
+7. **Runtime**
+ * Compressor runtime hours (hot water/heating)
+ * Reheating runtime hours (reheating 1/reheating 2)
+
+8. **Energy**
+ * Compressor today in kWh (hot water/heating)
+ * Compressor Total in kWh (hot water/heating)
+
+
+### configuration
+
+If no configuration is given, the module will be disabled. Each `update_every` is optional, the default is `10`.
+
+---
+
[Stiebel Eltron Heat pump system with ISG](https://www.stiebel-eltron.com/en/home/products-solutions/renewables/controller_energymanagement/internet_servicegateway/isg_web.html)
Original author: BrainDoctor (github)
@@ -24,7 +76,7 @@ In my case, the ISG is relatively slow with responding (at least 1s, but also up
* The dimensions support variable digits, the default is `1`. Most of the values printed by ISG are using 1 digit, some use 2.
* The dimensions also support the `multiplier` and `divisor` attributes, however the divisor gets overridden by `digits`, if specified. Default is `1`.
* The test string for the regex is always the whole HTML output from the url. For each parameter you need to have a regular expression that extracts the value from the HTML source in the first capture group.
- Recommended: [regexr.com](regexr.com) for testing and matching, [freeformatter.com](https://www.freeformatter.com/json-escape.html) for escaping the newly created regex for the JSON config.
+ Recommended: [regexr.com](https://regexr.com/) for testing and matching, [freeformatter.com](https://www.freeformatter.com/json-escape.html) for escaping the newly created regex for the JSON config.
The charts are being generated using the configuration below. So if your installation is in another language or has other metrics, just adapt the structure or regexes.
### Configuration template
diff --git a/node.d/stiebeleltron.node.js b/collectors/node.d.plugin/stiebeleltron/stiebeleltron.node.js
index 77317f2fb..250c26540 100644
--- a/node.d/stiebeleltron.node.js
+++ b/collectors/node.d.plugin/stiebeleltron/stiebeleltron.node.js
@@ -1,12 +1,13 @@
'use strict';
+// SPDX-License-Identifier: GPL-3.0-or-later
// This program will connect to one Stiebel Eltron ISG for heatpump heating
// to get the heat pump metrics.
// example configuration in netdata/conf.d/node.d/stiebeleltron.conf.md
-var url = require("url");
-var http = require("http");
+require("url");
+require("http");
var netdata = require("netdata");
netdata.debug("loaded " + __filename + " plugin");
diff --git a/collectors/plugins.d/Makefile.am b/collectors/plugins.d/Makefile.am
new file mode 100644
index 000000000..59250a997
--- /dev/null
+++ b/collectors/plugins.d/Makefile.am
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+SUBDIRS = \
+ $(NULL)
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
diff --git a/collectors/plugins.d/Makefile.in b/collectors/plugins.d/Makefile.in
new file mode 100644
index 000000000..b2c112811
--- /dev/null
+++ b/collectors/plugins.d/Makefile.in
@@ -0,0 +1,647 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors/plugins.d
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(dist_noinst_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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
+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 \
+ distdir
+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
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+SUBDIRS = \
+ $(NULL)
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/plugins.d/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/plugins.d/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+# 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; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(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
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-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
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @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; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic cscopelist-am ctags ctags-am \
+ distclean distclean-generic distclean-tags 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 installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/collectors/plugins.d/README.md b/collectors/plugins.d/README.md
new file mode 100644
index 000000000..d3aa5b5b0
--- /dev/null
+++ b/collectors/plugins.d/README.md
@@ -0,0 +1,472 @@
+# Netdata External Plugins
+
+`plugins.d` is the netdata internal plugin that collects metrics
+from external processes, thus allowing netdata to use **external plugins**.
+
+## Provided External Plugins
+
+plugin|language|O/S|description
+:---:|:---:|:---:|:---
+[apps.plugin](../apps.plugin/)|`C`|linux, freebsd|monitors the whole process tree on Linux and FreeBSD and breaks down system resource usage by **process**, **user** and **user group**.
+[charts.d.plugin](../charts.d.plugin/)|`BASH`|all|a **plugin orchestrator** for data collection modules written in `BASH` v4+.
+[fping.plugin](../fping.plugin/)|`C`|all|measures network latency, jitter and packet loss between the monitored node and any number of remote network end points.
+[freeipmi.plugin](../freeipmi.plugin/)|`C`|linux|collects metrics from enterprise hardware sensors, on Linux servers.
+[node.d.plugin](../node.d.plugin/)|`node.js`|all|a **plugin orchestrator** for data collection modules written in `node.js`.
+[python.d.plugin](../python.d.plugin/)|`python`|all|a **plugin orchestrator** for data collection modules written in `python` v2 or v3 (both are supported).
+
+Plugin orchestrators may also be described as **modular plugins**. They are modular since they accept custom made modules to be included. Writing modules for these plugins is easier than accessing the native netdata API directly. You will find modules already available for each orchestrator under the directory of the particular modular plugin (e.g. under python.d.plugin for the python orchestrator).
+Each of these modular plugins has each own methods for defining modules. Please check the examples and their documentation.
+
+## Motivation
+
+This plugin allows netdata to use **external plugins** for data collection:
+
+1. external data collection plugins may be written in any computer language.
+
+2. external data collection plugins may use O/S capabilities or `setuid` to
+ run with escalated privileges (compared to the netdata daemon).
+ The communication between the external plugin and netdata is unidirectional
+ (from the plugin to netdata), so that netdata cannot manipulate an external
+ plugin running with escalated privileges.
+
+## Operation
+
+Each of the external plugins is expected to run forever.
+Netdata will start it when it starts and stop it when it exits.
+
+If the external plugin exits or crashes, netdata will log an error.
+If the external plugin exits or crashes without pushing metrics to netdata, netdata will not start it again.
+- Plugins that exit with any value other than zero, will be disabled. Plugins that exit with zero, will be restarted after some time.
+- Plugins may also be disabled by netdata if they output things that netdata does not understand.
+
+The `stdout` of external plugins is connected to netdata to receive metrics,
+with the API defined below.
+
+The `stderr` of external plugins is connected to netdata `error.log`.
+
+Plugins can create any number of charts with any number of dimensions each. Each chart can have its own characteristics independently of the others generated by the same plugin. For example, one chart may have an update frequency of 1 second, another may have 5 seconds and a third may have 10 seconds.
+
+## Configuration
+
+Netdata will supply the environment variables `NETDATA_USER_CONFIG_DIR` (for user supplied) and `NETDATA_STOCK_CONFIG_DIR` (for netdata supplied) configuration files to identify the directory where configuration files are stored. It is up to the plugin to read the configuration it needs.
+
+The `netdata.conf` section [plugins] section contains a list of all the plugins found at the system where netdata runs, with a boolean setting to enable them or not.
+
+Example:
+
+```
+[plugins]
+ # enable running new plugins = yes
+ # check for new plugins every = 60
+
+ # charts.d = yes
+ # fping = yes
+ # node.d = yes
+ # python.d = yes
+```
+
+The setting `enable running new plugins` changes the default behavior for all external plugins.
+So if set to `no`, only the plugins that are explicitly set to `yes` will be run.
+
+The setting `check for new plugins every` controls the time the directory `/usr/libexec/netdata/plugins.d`
+will be rescanned for new plugins. So, new plugins can give added anytime.
+
+For each of the external plugins enabled, another `netdata.conf` section
+is created, in the form of `[plugin:NAME]`, where `NAME` is the name of the external plugin.
+This section allows controlling the update frequency of the plugin and provide
+additional command line arguments to it.
+
+For example, for `apps.plugin` the following section is available:
+
+```
+[plugin:apps]
+ # update every = 1
+ # command options =
+```
+
+- `update every` controls the granularity of the external plugin.
+- `command options` allows giving additional command line options to the plugin.
+
+
+Netdata will provide to the extrenal plugins the environment variable `NETDATA_UPDATE_EVERY`, in seconds (the default is 1). This is the **minimum update frequency** for all charts. A plugin that is updating values more frequently than this, is just wasting resources.
+
+Netdata will call the plugin with just one command line parameter: the number of seconds the user requested this plugin to update its data (by default is also 1).
+
+Other than the above, the plugin configuration is up to the plugin.
+
+Keep in mind, that the user may use netdata configuration to overwrite chart and dimension parameters. This is transparent to the plugin.
+
+### Autoconfiguration
+
+Plugins should attempt to autoconfigure themselves when possible.
+
+For example, if your plugin wants to monitor `squid`, you can search for it on port `3128` or `8080`. If any succeeds, you can proceed. If it fails you can output an error (on stderr) saying that you cannot find `squid` running and giving instructions about the plugin configuration. Then you can stop (exit with non-zero value), so that netdata will not attempt to start the plugin again.
+
+## External Plugins API
+
+Any program that can print a few values to its standard output can become a netdata external plugin.
+
+There are 7 lines netdata parses. lines starting with:
+
+- `CHART` - create or update a chart
+- `DIMENSION` - add or update a dimension to the chart just created
+- `BEGIN` - initialize data collection for a chart
+- `SET` - set the value of a dimension for the initialized chart
+- `END` - complete data collection for the initialized chart
+- `FLUSH` - ignore the last collected values
+- `DISABLE` - disable this plugin
+
+a single program can produce any number of charts with any number of dimensions each.
+
+Charts can be added any time (not just the beginning).
+
+### command line parameters
+
+The plugin **MUST** accept just **one** parameter: **the number of seconds it is
+expected to update the values for its charts**. The value passed by netdata
+to the plugin is controlled via its configuration file (so there is no need
+for the plugin to handle this configuration option).
+
+The external plugin can overwrite the update frequency. For example, the server may
+request per second updates, but the plugin may ignore it and update its charts
+every 5 seconds.
+
+### environment variables
+
+There are a few environment variables that are set by `netdata` and are
+available for the plugin to use.
+
+variable|description
+:------:|:----------
+`NETDATA_USER_CONFIG_DIR`|The directory where all netdata related user configuration should be stored. If the plugin requires custom user configuration, this is the place the user has saved it (normally under `/etc/netdata`).
+`NETDATA_STOCK_CONFIG_DIR`|The directory where all netdata related stock configuration should be stored. If the plugin is shipped with configuration files, this is the place they can be found (normally under `/usr/lib/netdata/conf.d`).
+`NETDATA_PLUGINS_DIR`|The directory where all netdata plugins are stored.
+`NETDATA_WEB_DIR`|The directory where the web files of netdata are saved.
+`NETDATA_CACHE_DIR`|The directory where the cache files of netdata are stored. Use this directory if the plugin requires a place to store data. A new directory should be created for the plugin for this purpose, inside this directory.
+`NETDATA_LOG_DIR`|The directory where the log files are stored. By default the `stderr` output of the plugin will be saved in the `error.log` file of netdata.
+`NETDATA_HOST_PREFIX`|This is used in environments where system directories like `/sys` and `/proc` have to be accessed at a different path.
+`NETDATA_DEBUG_FLAGS`|This is a number (probably in hex starting with `0x`), that enables certain netdata debugging features. Check **[[Tracing Options]]** for more information.
+`NETDATA_UPDATE_EVERY`|The minimum number of seconds between chart refreshes. This is like the **internal clock** of netdata (it is user configurable, defaulting to `1`). There is no meaning for a plugin to update its values more frequently than this number of seconds.
+
+
+### The output of the plugin
+
+The plugin should output instructions for netdata to its output (`stdout`). Since this uses pipes, please make sure you flush stdout after every iteration.
+
+#### DISABLE
+
+`DISABLE` will disable this plugin. This will prevent netdata from restarting the plugin. You can also exit with the value `1` to have the same effect.
+
+#### CHART
+
+`CHART` defines a new chart.
+
+the template is:
+
+> CHART type.id name title units [family [context [charttype [priority [update_every [options [plugin [module]]]]]]]]
+
+ where:
+ - `type.id`
+
+ uniquely identifies the chart,
+ this is what will be needed to add values to the chart
+
+ the `type` part controls the menu the charts will appear in
+
+ - `name`
+
+ is the name that will be presented to the user instead of `id` in `type.id`. This means that only the `id` part of `type.id` is changed. When a name has been given, the chart is index (and can be referred) as both `type.id` and `type.name`. You can set name to `''`, or `null`, or `(null)` to disable it.
+
+ - `title`
+
+ the text above the chart
+
+ - `units`
+
+ the label of the vertical axis of the chart,
+ all dimensions added to a chart should have the same units
+ of measurement
+
+ - `family`
+
+ is used to group charts together
+ (for example all eth0 charts should say: eth0),
+ if empty or missing, the `id` part of `type.id` will be used
+
+ this controls the sub-menu on the dashboard
+
+ - `context`
+
+ the context is giving the template of the chart. For example, if multiple charts present the same information for a different family, they should have the same `context`
+
+ this is used for looking up rendering information for the chart (colors, sizes, informational texts) and also apply alarms to it
+
+ - `charttype`
+
+ one of `line`, `area` or `stacked`,
+ if empty or missing, the `line` will be used
+
+ - `priority`
+
+ is the relative priority of the charts as rendered on the web page,
+ lower numbers make the charts appear before the ones with higher numbers,
+ if empty or missing, `1000` will be used
+
+ - `update_every`
+
+ overwrite the update frequency set by the server,
+ if empty or missing, the user configured value will be used
+
+ - `options`
+
+ a space separated list of options, enclosed in quotes. 4 options are currently supported: `obsolete` to mark a chart as obsolete (netdata will hide it and delete it after some time), `detail` to mark a chart as insignificant (this may be used by dashboards to make the charts smaller, or somehow visualize properly a less important chart), `store_first` to make netdata store the first collected value, assuming there was an invisible previous value set to zero (this is used by statsd charts - if the first data collected value of incremental dimensions is not zero based, unrealistic spikes will appear with this option set) and `hidden` to perform all operations on a chart, but do not offer it on dashboards (the chart will be send to backends). `CHART` options have been added in netdata v1.7 and the `hidden` option was added in 1.10.
+
+ - `plugin` and `module`
+
+ both are just names that are used to let the user identify the plugin and the module that generated the chart. If `plugin` is unset or empty, netdata will automatically set the filename of the plugin that generated the chart. `module` has not default.
+
+
+#### DIMENSION
+
+`DIMENSION` defines a new dimension for the chart
+
+the template is:
+
+> DIMENSION id [name [algorithm [multiplier [divisor [hidden]]]]]
+
+ where:
+
+ - `id`
+
+ the `id` of this dimension (it is a text value, not numeric),
+ this will be needed later to add values to the dimension
+
+ We suggest to avoid using `.` in dimension ids. Backends expect metrics to be `.` separated and people will get confused if a dimension id contains a dot.
+
+ - `name`
+
+ the name of the dimension as it will appear at the legend of the chart,
+ if empty or missing the `id` will be used
+
+ - `algorithm`
+
+ one of:
+
+ * `absolute`
+
+ the value is to drawn as-is (interpolated to second boundary),
+ if `algorithm` is empty, invalid or missing, `absolute` is used
+
+ * `incremental`
+
+ the value increases over time,
+ the difference from the last value is presented in the chart,
+ the server interpolates the value and calculates a per second figure
+
+ * `percentage-of-absolute-row`
+
+ the % of this value compared to the total of all dimensions
+
+ * `percentage-of-incremental-row`
+
+ the % of this value compared to the incremental total of
+ all dimensions
+
+ - `multiplier`
+
+ an integer value to multiply the collected value,
+ if empty or missing, `1` is used
+
+ - `divisor`
+
+ an integer value to divide the collected value,
+ if empty or missing, `1` is used
+
+ - `hidden`
+
+ giving the keyword `hidden` will make this dimension hidden,
+ it will take part in the calculations but will not be presented in the chart
+
+
+#### VARIABLE
+
+> VARIABLE [SCOPE] name = value
+
+`VARIABLE` defines a variable that can be used in alarms. This is to used for setting constants (like the max connections a server may accept).
+
+Variables support 2 scopes:
+
+- `GLOBAL` or `HOST` to define the variable at the host level.
+- `LOCAL` or `CHART` to define the variable at the chart level. Use chart-local variables when the same variable may exist for different charts (i.e. netdata monitors 2 mysql servers, and you need to set the `max_connections` each server accepts). Using chart-local variables is the ideal to build alarm templates.
+
+The position of the `VARIABLE` line, sets its default scope (in case you do not specify a scope). So, defining a `VARIABLE` before any `CHART`, or between `END` and `BEGIN` (outside any chart), sets `GLOBAL` scope, while defining a `VARIABLE` just after a `CHART` or a `DIMENSION`, or within the `BEGIN` - `END` block of a chart, sets `LOCAL` scope.
+
+These variables can be set and updated at any point.
+
+Variable names should use alphanumeric characters, the `.` and the `_`.
+
+The `value` is floating point (netdata used `long double`).
+
+Variables are transferred to upstream netdata servers (streaming and database replication).
+
+## Data collection
+
+data collection is defined as a series of `BEGIN` -> `SET` -> `END` lines
+
+> BEGIN type.id [microseconds]
+
+ - `type.id`
+
+ is the unique identification of the chart (as given in `CHART`)
+
+ - `microseconds`
+
+ is the number of microseconds since the last update of the chart. It is optional.
+
+ Under heavy system load, the system may have some latency transferring
+ data from the plugins to netdata via the pipe. This number improves
+ accuracy significantly, since the plugin is able to calculate the
+ duration between its iterations better than netdata.
+
+ The first time the plugin is started, no microseconds should be given
+ to netdata.
+
+> SET id = value
+
+ - `id`
+
+ is the unique identification of the dimension (of the chart just began)
+
+ - `value`
+
+ is the collected value, only integer values are collected. If you want to push fractional values, multiply this value by 100 or 1000 and set the `DIMENSION` divider to 1000.
+
+> END
+
+ END does not take any parameters, it commits the collected values for all dimensions to the chart. If a dimensions was not `SET`, its value will be empty for this commit.
+
+More `SET` lines may appear to update all the dimensions of the chart.
+All of them in one `BEGIN` -> `END` block.
+
+All `SET` lines within a single `BEGIN` -> `END` block have to refer to the
+same chart.
+
+If more charts need to be updated, each chart should have its own
+`BEGIN` -> `SET` -> `END` block.
+
+If, for any reason, a plugin has issued a `BEGIN` but wants to cancel it,
+it can issue a `FLUSH`. The `FLUSH` command will instruct netdata to ignore
+all the values collected since the last `BEGIN` command.
+
+If a plugin does not behave properly (outputs invalid lines, or does not
+follow these guidelines), will be disabled by netdata.
+
+### collected values
+
+netdata will collect any **signed** value in the 64bit range:
+`-9.223.372.036.854.775.808` to `+9.223.372.036.854.775.807`
+
+If a value is not collected, leave it empty, like this:
+
+`SET id = `
+
+or do not output the line at all.
+
+## Modular Plugins
+
+1. **python**, use `python.d.plugin`, there are many examples in the [python.d directory](../python.d.plugin)
+
+ python is ideal for netdata plugins. It is a simple, yet powerful way to collect data, it has a very small memory footprint, although it is not the most CPU efficient way to do it.
+
+2. **node.js**, use `node.d.plugin`, there are a few examples in the [node.d directory](../node.d.plugin)
+
+ node.js is the fastest scripting language for collecting data. If your plugin needs to do a lot of work, compute values, etc, node.js is probably the best choice before moving to compiled code. Keep in mind though that node.js is not memory efficient; it will probably need more RAM compared to python.
+
+3. **BASH**, use `charts.d.plugin`, there are many examples in the [charts.d directory](../charts.d.plugin)
+
+ BASH is the simplest scripting language for collecting values. It is the less efficient though in terms of CPU resources. You can use it to collect data quickly, but extensive use of it might use a lot of system resources.
+
+4. **C**
+
+ Of course, C is the most efficient way of collecting data. This is why netdata itself is written in C.
+
+---
+
+## Writing Plugins Properly
+
+There are a few rules for writing plugins properly:
+
+1. Respect system resources
+
+ Pay special attention to efficiency:
+
+ - Initialize everything once, at the beginning. Initialization is not an expensive operation. Your plugin will most probably be started once and run forever. So, do whatever heavy operation is needed at the beginning, just once.
+ - Do the absolutely minimum while iterating to collect values repeatedly.
+ - If you need to connect to another server to collect values, avoid re-connects if possible. Connect just once, with keep-alive (for HTTP) enabled and collect values using the same connection.
+ - Avoid any CPU or memory heavy operation while collecting data. If you control memory allocation, avoid any memory allocation white iterating to collect values.
+ - Avoid running external commands when possible. If you are writing shell scripts avoid especially pipes (each pipe is another fork, a very expensive operation).
+
+2. The best way to iterate at a constant pace is this pseudo code:
+
+```js
+ var update_every = argv[1] * 1000; /* seconds * 1000 = milliseconds */
+
+ readConfiguration();
+
+ if(!verifyWeCanCollectValues()) {
+ print "DISABLE";
+ exit(1);
+ }
+
+ createCharts(); /* print CHART and DIMENSION statements */
+
+ var loops = 0;
+ var last_run = 0;
+ var next_run = 0;
+ var dt_since_last_run = 0;
+ var now = 0;
+
+ FOREVER {
+ /* find the current time in milliseconds */
+ now = currentTimeStampInMilliseconds();
+
+ /*
+ * find the time of the next loop
+ * this makes sure we are always aligned
+ * with the netdata daemon
+ */
+ next_run = now - (now % update_every) + update_every;
+
+ /*
+ * wait until it is time
+ * it is important to do it in a loop
+ * since many wait functions can be interrupted
+ */
+ while( now < next_run ) {
+ sleepMilliseconds(next_run - now);
+ now = currentTimeStampInMilliseconds();
+ }
+
+ /* calculate the time passed since the last run */
+ if ( loops > 0 )
+ dt_since_last_run = (now - last_run) * 1000; /* in microseconds */
+
+ /* prepare for the next loop */
+ last_run = now;
+ loops++;
+
+ /* do your magic here to collect values */
+ collectValues();
+
+ /* send the collected data to netdata */
+ printValues(dt_since_last_run); /* print BEGIN, SET, END statements */
+ }
+```
+
+ Using the above procedure, your plugin will be synchronized to start data collection on steps of `update_every`. There will be no need to keep track of latencies in data collection.
+
+ Netdata interpolates values to second boundaries, so even if your plugin is not perfectly aligned it does not matter. Netdata will find out. When your plugin works in increments of `update_every`, there will be no gaps in the charts due to the possible cumulative micro-delays in data collection. Gaps will only appear if the data collection is really delayed.
+
+3. If you are not sure of memory leaks, exit every one hour. Netdata will re-start your process.
+
+4. If possible, try to autodetect if your plugin should be enabled, without any configuration.
diff --git a/src/plugins_d.c b/collectors/plugins.d/plugins_d.c
index 5693dda06..465ecd796 100644
--- a/src/plugins_d.c
+++ b/collectors/plugins.d/plugins_d.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugins_d.h"
char *plugin_directories[PLUGINSD_MAX_DIRECTORIES] = { NULL };
char *netdata_configured_plugins_dir_base;
diff --git a/src/plugins_d.h b/collectors/plugins.d/plugins_d.h
index 692d7cae1..adccf3f0f 100644
--- a/src/plugins_d.h
+++ b/collectors/plugins.d/plugins_d.h
@@ -1,6 +1,22 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#ifndef NETDATA_PLUGINS_D_H
#define NETDATA_PLUGINS_D_H 1
+#include "../../daemon/common.h"
+
+#define NETDATA_PLUGIN_HOOK_PLUGINSD \
+ { \
+ .name = "PLUGINSD", \
+ .config_section = NULL, \
+ .config_name = NULL, \
+ .enabled = 1, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = pluginsd_main \
+ },
+
+
#define PLUGINSD_FILE_SUFFIX ".plugin"
#define PLUGINSD_FILE_SUFFIX_LEN strlen(PLUGINSD_FILE_SUFFIX)
#define PLUGINSD_CMD_MAX (FILENAME_MAX*2)
diff --git a/collectors/proc.plugin/Makefile.am b/collectors/proc.plugin/Makefile.am
new file mode 100644
index 000000000..19554bed8
--- /dev/null
+++ b/collectors/proc.plugin/Makefile.am
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
diff --git a/collectors/proc.plugin/Makefile.in b/collectors/proc.plugin/Makefile.in
new file mode 100644
index 000000000..f6db90c87
--- /dev/null
+++ b/collectors/proc.plugin/Makefile.in
@@ -0,0 +1,464 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = collectors/proc.plugin
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(dist_noinst_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/proc.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/proc.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+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
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/collectors/proc.plugin/README.md b/collectors/proc.plugin/README.md
new file mode 100644
index 000000000..9d444f3d0
--- /dev/null
+++ b/collectors/proc.plugin/README.md
@@ -0,0 +1,200 @@
+
+# proc.plugin
+
+ - `/proc/net/dev` (all network interfaces for all their values)
+ - `/proc/diskstats` (all disks for all their values)
+ - `/proc/net/snmp` (total IPv4, TCP and UDP usage)
+ - `/proc/net/snmp6` (total IPv6 usage)
+ - `/proc/net/netstat` (more IPv4 usage)
+ - `/proc/net/stat/nf_conntrack` (connection tracking performance)
+ - `/proc/net/stat/synproxy` (synproxy performance)
+ - `/proc/net/ip_vs/stats` (IPVS connection statistics)
+ - `/proc/stat` (CPU utilization)
+ - `/proc/meminfo` (memory information)
+ - `/proc/vmstat` (system performance)
+ - `/proc/net/rpc/nfsd` (NFS server statistics for both v3 and v4 NFS servers)
+ - `/sys/fs/cgroup` (Control Groups - Linux Containers)
+ - `/proc/self/mountinfo` (mount points)
+ - `/proc/interrupts` (total and per core hardware interrupts)
+ - `/proc/softirqs` (total and per core software interrupts)
+ - `/proc/loadavg` (system load and total processes running)
+ - `/proc/sys/kernel/random/entropy_avail` (random numbers pool availability - used in cryptography)
+ - `ksm` Kernel Same-Page Merging performance (several files under `/sys/kernel/mm/ksm`).
+ - `netdata` (internal netdata resources utilization)
+
+
+---
+
+# Monitoring Disks
+
+> Live demo of disk monitoring at: **[http://london.netdata.rocks](https://registry.my-netdata.io/#menu_disk)**
+
+Performance monitoring for Linux disks is quite complicated. The main reason is the plethora of disk technologies available. There are many different hardware disk technologies, but there are even more **virtual disk** technologies that can provide additional storage features.
+
+Hopefully, the Linux kernel provides many metrics that can provide deep insights of what our disks our doing. The kernel measures all these metrics on all layers of storage: **virtual disks**, **physical disks** and **partitions of disks**.
+
+Let's see the list of metrics provided by netdata for each of the above:
+
+### I/O bandwidth/s (kb/s)
+
+The amount of data transferred from and to the disk.
+
+### I/O operations/s
+
+The number of I/O operations completed.
+
+### Queued I/O operations
+
+The number of currently queued I/O operations. For traditional disks that execute commands one after another, one of them is being run by the disk and the rest are just waiting in a queue.
+
+### Backlog size (time in ms)
+
+The expected duration of the currently queued I/O operations.
+
+### Utilization (time percentage)
+
+The percentage of time the disk was busy with something. This is a very interesting metric, since for most disks, that execute commands sequentially, **this is the key indication of congestion**. A sequential disk that is 100% of the available time busy, has no time to do anything more, so even if the bandwidth or the number of operations executed by the disk is low, its capacity has been reached.
+
+Of course, for newer disk technologies (like fusion cards) that are capable to execute multiple commands in parallel, this metric is just meaningless.
+
+### Average I/O operation time (ms)
+
+The average time for I/O requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them.
+
+### Average I/O operation size (kb)
+
+The average amount of data of the completed I/O operations.
+
+### Average Service Time (ms)
+
+The average service time for completed I/O operations. This metric is calculated using the total busy time of the disk and the number of completed operations. If the disk is able to execute multiple parallel operations the reporting average service time will be misleading.
+
+### Merged I/O operations/s
+
+The Linux kernel is capable of merging I/O operations. So, if two requests to read data from the disk are adjacent, the Linux kernel may merge them to one before giving them to disk. This metric measures the number of operations that have been merged by the Linux kernel.
+
+### Total I/O time
+
+The sum of the duration of all completed I/O operations. This number can exceed the interval if the disk is able to execute multiple I/O operations in parallel.
+
+### Space usage
+
+For mounted disks, netdata will provide a chart for their space, with 3 dimensions:
+
+1. free
+2. used
+3. reserved for root
+
+### inode usage
+
+For mounted disks, netdata will provide a chart for their inodes (number of file and directories), with 3 dimensions:
+
+1. free
+2. used
+3. reserved for root
+
+---
+
+## disk names
+
+netdata will automatically set the name of disks on the dashboard, from the mount point they are mounted, of course only when they are mounted. Changes in mount points are not currently detected (you will have to restart netdata to change the name of the disk).
+
+---
+
+## performance metrics
+
+By default netdata will enable monitoring metrics only when they are not zero. If they are constantly zero they are ignored. Metrics that will start having values, after netdata is started, will be detected and charts will be automatically added to the dashboard (a refresh of the dashboard is needed for them to appear though).
+
+netdata categorizes all block devices in 3 categories:
+
+1. physical disks (i.e. block devices that does not have slaves and are not partitions)
+2. virtual disks (i.e. block devices that have slaves - like RAID devices)
+3. disk partitions (i.e. block devices that are part of a physical disk)
+
+Performance metrics are enabled by default for all disk devices, except partitions and not-mounted virtual disks. Of course, you can enable/disable monitoring any block device by editing the netdata configuration file.
+
+### netdata configuration
+
+You can get the running netdata configuration using this:
+
+```sh
+cd /etc/netdata
+curl "http://localhost:19999/netdata.conf" >netdata.conf.new
+mv netdata.conf.new netdata.conf
+```
+
+Then edit `netdata.conf` and find the following section. This is the basic plugin configuration.
+
+```
+[plugin:proc:/proc/diskstats]
+ # enable new disks detected at runtime = yes
+ # performance metrics for physical disks = auto
+ # performance metrics for virtual disks = no
+ # performance metrics for partitions = no
+ # performance metrics for mounted filesystems = no
+ # performance metrics for mounted virtual disks = auto
+ # space metrics for mounted filesystems = auto
+ # bandwidth for all disks = auto
+ # operations for all disks = auto
+ # merged operations for all disks = auto
+ # i/o time for all disks = auto
+ # queued operations for all disks = auto
+ # utilization percentage for all disks = auto
+ # backlog for all disks = auto
+ # space usage for all disks = auto
+ # inodes usage for all disks = auto
+ # filename to monitor = /proc/diskstats
+ # path to get block device infos = /sys/dev/block/%lu:%lu/%s
+ # path to get h/w sector size = /sys/block/%s/queue/hw_sector_size
+ # path to get h/w sector size for partitions = /sys/dev/block/%lu:%lu/subsystem/%s/../queue
+/hw_sector_size
+
+```
+
+For each virtual disk, physical disk and partition you will have a section like this:
+
+```
+[plugin:proc:/proc/diskstats:sda]
+ # enable = yes
+ # enable performance metrics = auto
+ # bandwidth = auto
+ # operations = auto
+ # merged operations = auto
+ # i/o time = auto
+ # queued operations = auto
+ # utilization percentage = auto
+ # backlog = auto
+```
+
+For all configuration options:
+- `auto` = enable monitoring if the collected values are not zero
+- `yes` = enable monitoring
+- `no` = disable monitoring
+
+Of course, to set options, you will have to uncomment them. The comments show the internal defaults.
+
+After saving `/etc/netdata/netdata.conf`, restart your netdata to apply them.
+
+#### Disabling performance metrics for individual device and to multiple devices by device type
+You can pretty easy disable performance metrics for individual device, for ex.:
+```
+[plugin:proc:/proc/diskstats:sda]
+ enable performance metrics = no
+```
+But sometimes you need disable performance metrics for all devices with the same type, to do it you need to figure out device type from `/proc/diskstats` for ex.:
+```
+ 7 0 loop0 1651 0 3452 168 0 0 0 0 0 8 168
+ 7 1 loop1 4955 0 11924 880 0 0 0 0 0 64 880
+ 7 2 loop2 36 0 216 4 0 0 0 0 0 4 4
+ 7 6 loop6 0 0 0 0 0 0 0 0 0 0 0
+ 7 7 loop7 0 0 0 0 0 0 0 0 0 0 0
+ 251 2 zram2 27487 0 219896 188 79953 0 639624 1640 0 1828 1828
+ 251 3 zram3 27348 0 218784 152 79952 0 639616 1960 0 2060 2104
+```
+All zram devices starts with `251` number and all loop devices starts with `7`.
+So, to disable performance metrics for all loop devices you could add `performance metrics for disks with major 7 = no` to `[plugin:proc:/proc/diskstats]` section.
+```
+[plugin:proc:/proc/diskstats]
+ performance metrics for disks with major 7 = no
+```
+
diff --git a/src/ipc.c b/collectors/proc.plugin/ipc.c
index a9076fca4..6c6bee519 100644
--- a/src/ipc.c
+++ b/collectors/proc.plugin/ipc.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
#include <sys/sem.h>
#include <sys/msg.h>
@@ -166,7 +168,7 @@ int do_ipc(int update_every, usec_t dt) {
static int initialized = 0, read_limits_next = -1;
static struct ipc_limits limits;
static struct ipc_status status;
- static RRDSETVAR *arrays_max = NULL, *semaphores_max = NULL;
+ static RRDVAR *arrays_max = NULL, *semaphores_max = NULL;
static RRDSET *st_semaphores = NULL, *st_arrays = NULL;
static RRDDIM *rd_semaphores = NULL, *rd_arrays = NULL;
@@ -195,9 +197,9 @@ int do_ipc(int update_every, usec_t dt) {
, NULL
, "IPC Semaphores"
, "semaphores"
- , "linux"
+ , PLUGIN_PROC_NAME
, "ipc"
- , 1000
+ , NETDATA_CHART_PRIO_SYSTEM_IPC_SEMAPHORES
, localhost->rrd_update_every
, RRDSET_TYPE_AREA
);
@@ -213,9 +215,9 @@ int do_ipc(int update_every, usec_t dt) {
, NULL
, "IPC Semaphore Arrays"
, "arrays"
- , "linux"
+ , PLUGIN_PROC_NAME
, "ipc"
- , 1000
+ , NETDATA_CHART_PRIO_SYSTEM_IPC_SEM_ARRAYS
, localhost->rrd_update_every
, RRDSET_TYPE_AREA
);
@@ -223,8 +225,8 @@ int do_ipc(int update_every, usec_t dt) {
}
// variables
- semaphores_max = rrdsetvar_custom_chart_variable_create(st_semaphores, "ipc.semaphores.max");
- arrays_max = rrdsetvar_custom_chart_variable_create(st_arrays, "ipc.semaphores.arrays.max");
+ semaphores_max = rrdvar_custom_host_variable_create(localhost, "ipc_semaphores_max");
+ arrays_max = rrdvar_custom_host_variable_create(localhost, "ipc_semaphores_arrays_max");
}
if(unlikely(read_limits_next < 0)) {
@@ -232,8 +234,8 @@ int do_ipc(int update_every, usec_t dt) {
error("Unable to fetch semaphore limits.");
}
else {
- if(semaphores_max) rrdsetvar_custom_chart_variable_set(semaphores_max, limits.semmns);
- if(arrays_max) rrdsetvar_custom_chart_variable_set(arrays_max, limits.semmni);
+ if(semaphores_max) rrdvar_custom_host_variable_set(localhost, semaphores_max, limits.semmns);
+ if(arrays_max) rrdvar_custom_host_variable_set(localhost, arrays_max, limits.semmni);
st_arrays->red = limits.semmni;
st_semaphores->red = limits.semmns;
diff --git a/src/plugin_proc.c b/collectors/proc.plugin/plugin_proc.c
index e0afb0d6d..0c3244d61 100644
--- a/src/plugin_proc.c
+++ b/collectors/proc.plugin/plugin_proc.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
static struct proc_module {
const char *name;
@@ -37,6 +39,7 @@ static struct proc_module {
{ .name = "/proc/net/netstat", .dim = "netstat", .func = do_proc_net_netstat }, // this has to be before /proc/net/snmp, because there is a shared metric
{ .name = "/proc/net/snmp", .dim = "snmp", .func = do_proc_net_snmp },
{ .name = "/proc/net/snmp6", .dim = "snmp6", .func = do_proc_net_snmp6 },
+ { .name = "/proc/net/sctp/snmp", .dim = "sctp", .func = do_proc_net_sctp_snmp },
{ .name = "/proc/net/softnet_stat", .dim = "softnet", .func = do_proc_net_softnet_stat },
{ .name = "/proc/net/ip_vs/stats", .dim = "ipvs", .func = do_proc_net_ip_vs_stats },
@@ -91,8 +94,12 @@ void *proc_main(void *ptr) {
usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
heartbeat_t hb;
heartbeat_init(&hb);
+ size_t iterations = 0;
while(!netdata_exit) {
+ iterations++;
+ (void)iterations;
+
usec_t hb_dt = heartbeat_next(&hb, step);
usec_t duration = 0ULL;
@@ -106,10 +113,19 @@ void *proc_main(void *ptr) {
debug(D_PROCNETDEV_LOOP, "PROC calling %s.", pm->name);
+//#ifdef NETDATA_LOG_ALLOCATIONS
+// if(pm->func == do_proc_interrupts)
+// log_thread_memory_allocations = iterations;
+//#endif
pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
- pm->duration = heartbeat_dt_usec(&hb) - duration;
+ pm->duration = heartbeat_monotonic_dt_to_now_usec(&hb) - duration;
duration += pm->duration;
+//#ifdef NETDATA_LOG_ALLOCATIONS
+// if(pm->func == do_proc_interrupts)
+// log_thread_memory_allocations = 0;
+//#endif
+
if(unlikely(netdata_exit)) break;
}
diff --git a/src/plugin_proc.h b/collectors/proc.plugin/plugin_proc.h
index a7f9b4e38..bfefe1ad4 100644
--- a/src/plugin_proc.h
+++ b/collectors/proc.plugin/plugin_proc.h
@@ -1,7 +1,28 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#ifndef NETDATA_PLUGIN_PROC_H
#define NETDATA_PLUGIN_PROC_H 1
-void *proc_main(void *ptr);
+#include "../../daemon/common.h"
+
+#if (TARGET_OS == OS_LINUX)
+
+#define NETDATA_PLUGIN_HOOK_LINUX_PROC \
+ { \
+ .name = "PLUGIN[proc]", \
+ .config_section = CONFIG_SECTION_PLUGINS, \
+ .config_name = "proc", \
+ .enabled = 1, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = proc_main \
+ },
+
+
+#define PLUGIN_PROC_CONFIG_NAME "proc"
+#define PLUGIN_PROC_NAME PLUGIN_PROC_CONFIG_NAME ".plugin"
+
+extern void *proc_main(void *ptr);
extern int do_proc_net_dev(int update_every, usec_t dt);
extern int do_proc_diskstats(int update_every, usec_t dt);
@@ -29,7 +50,8 @@ extern int do_proc_spl_kstat_zfs_arcstats(int update_every, usec_t dt);
extern int do_sys_fs_btrfs(int update_every, usec_t dt);
extern int do_proc_net_sockstat(int update_every, usec_t dt);
extern int do_proc_net_sockstat6(int update_every, usec_t dt);
-
+extern int do_proc_net_sctp_snmp(int update_every, usec_t dt);
+extern int do_ipc(int update_every, usec_t dt);
extern int get_numa_node_count(void);
// metrics that need to be shared among data collectors
@@ -39,4 +61,14 @@ extern unsigned long long tcpext_TCPSynRetrans;
extern void netdev_rename_device_add(const char *host_device, const char *container_device, const char *container_name);
extern void netdev_rename_device_del(const char *host_device);
+#include "proc_self_mountinfo.h"
+#include "zfs_common.h"
+
+#else // (TARGET_OS == OS_LINUX)
+
+#define NETDATA_PLUGIN_HOOK_LINUX_PROC
+
+#endif // (TARGET_OS == OS_LINUX)
+
+
#endif /* NETDATA_PLUGIN_PROC_H */
diff --git a/src/proc_diskstats.c b/collectors/proc.plugin/proc_diskstats.c
index 8cde3334b..387b395a3 100644
--- a/src/proc_diskstats.c
+++ b/collectors/proc.plugin/proc_diskstats.c
@@ -1,13 +1,16 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
#define RRD_TYPE_DISK "disk"
+#define PLUGIN_PROC_MODULE_DISKSTATS_NAME "/proc/diskstats"
+#define CONFIG_SECTION_PLUGIN_PROC_DISKSTATS "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_DISKSTATS_NAME
#define DISK_TYPE_UNKNOWN 0
#define DISK_TYPE_PHYSICAL 1
#define DISK_TYPE_PARTITION 2
#define DISK_TYPE_VIRTUAL 3
-#define CONFIG_SECTION_DISKSTATS "plugin:proc:/proc/diskstats"
#define DEFAULT_EXCLUDED_DISKS "loop* ram*"
static struct disk {
@@ -48,6 +51,12 @@ static struct disk {
char *bcache_filename_stats_total_cache_bypass_hits;
char *bcache_filename_stats_total_cache_bypass_misses;
char *bcache_filename_stats_total_cache_readaheads;
+ char *bcache_filename_cache_read_races;
+ char *bcache_filename_cache_io_errors;
+ char *bcache_filename_priority_stats;
+
+ usec_t bcache_priority_stats_update_every_usec;
+ usec_t bcache_priority_stats_elapsed_usec;
RRDSET *st_io;
RRDDIM *rd_io_reads;
@@ -111,6 +120,17 @@ static struct disk {
RRDDIM *rd_bcache_readaheads;
RRDDIM *rd_bcache_rate_writeback;
+ RRDSET *st_bcache_cache_allocations;
+ RRDDIM *rd_bcache_cache_allocations_unused;
+ RRDDIM *rd_bcache_cache_allocations_clean;
+ RRDDIM *rd_bcache_cache_allocations_dirty;
+ RRDDIM *rd_bcache_cache_allocations_metadata;
+ RRDDIM *rd_bcache_cache_allocations_unknown;
+
+ RRDSET *st_bcache_cache_read_races;
+ RRDDIM *rd_bcache_cache_read_races;
+ RRDDIM *rd_bcache_cache_io_errors;
+
struct disk *next;
} *disk_root = NULL;
@@ -125,7 +145,9 @@ static char *path_to_sys_devices_virtual_block_device = NULL;
static char *path_to_device_mapper = NULL;
static char *path_to_device_label = NULL;
static char *path_to_device_id = NULL;
+static char *path_to_veritas_volume_groups = NULL;
static int name_disks_by_id = CONFIG_BOOLEAN_NO;
+static int global_bcache_priority_stats_update_every = 0; // disabled by default
static int global_enable_new_disks_detected_at_runtime = CONFIG_BOOLEAN_YES,
global_enable_performance_for_physical_disks = CONFIG_BOOLEAN_AUTO,
@@ -170,6 +192,98 @@ static unsigned long long int bcache_read_number_with_units(const char *filename
return 0;
}
+void bcache_read_priority_stats(struct disk *d, const char *family, int update_every, usec_t dt) {
+ static procfile *ff = NULL;
+ static char *separators = " \t:%[]";
+
+ static ARL_BASE *arl_base = NULL;
+
+ static unsigned long long unused;
+ static unsigned long long clean;
+ static unsigned long long dirty;
+ static unsigned long long metadata;
+ static unsigned long long unknown;
+
+ // check if it is time to update this metric
+ d->bcache_priority_stats_elapsed_usec += dt;
+ if(likely(d->bcache_priority_stats_elapsed_usec < d->bcache_priority_stats_update_every_usec)) return;
+ d->bcache_priority_stats_elapsed_usec = 0;
+
+ // initialize ARL
+ if(unlikely(!arl_base)) {
+ arl_base = arl_create("bcache/priority_stats", NULL, 60);
+ arl_expect(arl_base, "Unused", &unused);
+ arl_expect(arl_base, "Clean", &clean);
+ arl_expect(arl_base, "Dirty", &dirty);
+ arl_expect(arl_base, "Metadata", &metadata);
+ }
+
+ ff = procfile_reopen(ff, d->bcache_filename_priority_stats, separators, PROCFILE_FLAG_DEFAULT);
+ if(likely(ff)) ff = procfile_readall(ff);
+ if(unlikely(!ff)) {
+ separators = " \t:%[]";
+ return;
+ }
+
+ // do not reset the separators on every iteration
+ separators = NULL;
+
+ arl_begin(arl_base);
+ unused = clean = dirty = metadata = unknown = 0;
+
+ size_t lines = procfile_lines(ff), l;
+
+ for(l = 0; l < lines ;l++) {
+ size_t words = procfile_linewords(ff, l);
+ if(unlikely(words < 2)) {
+ if(unlikely(words)) error("Cannot read '%s' line %zu. Expected 2 params, read %zu.", d->bcache_filename_priority_stats, l, words);
+ continue;
+ }
+
+ if(unlikely(arl_check(arl_base,
+ procfile_lineword(ff, l, 0),
+ procfile_lineword(ff, l, 1)))) break;
+ }
+
+ unknown = 100 - unused - clean - dirty - metadata;
+
+ // create / update the cache allocations chart
+ {
+ if(unlikely(!d->st_bcache_cache_allocations)) {
+ d->st_bcache_cache_allocations = rrdset_create_localhost(
+ "disk_bcache_cache_alloc"
+ , d->device
+ , d->disk
+ , family
+ , "disk.bcache_cache_alloc"
+ , "BCache Cache Allocations"
+ , "percentage"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_BCACHE_CACHE_ALLOC
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ d->rd_bcache_cache_allocations_unused = rrddim_add(d->st_bcache_cache_allocations, "unused", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ d->rd_bcache_cache_allocations_dirty = rrddim_add(d->st_bcache_cache_allocations, "dirty", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ d->rd_bcache_cache_allocations_clean = rrddim_add(d->st_bcache_cache_allocations, "clean", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ d->rd_bcache_cache_allocations_metadata = rrddim_add(d->st_bcache_cache_allocations, "metadata", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ d->rd_bcache_cache_allocations_unknown = rrddim_add(d->st_bcache_cache_allocations, "undefined", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+
+ d->bcache_priority_stats_update_every_usec = update_every * USEC_PER_SEC;
+ }
+ else rrdset_next(d->st_bcache_cache_allocations);
+
+ rrddim_set_by_pointer(d->st_bcache_cache_allocations, d->rd_bcache_cache_allocations_unused, unused);
+ rrddim_set_by_pointer(d->st_bcache_cache_allocations, d->rd_bcache_cache_allocations_dirty, dirty);
+ rrddim_set_by_pointer(d->st_bcache_cache_allocations, d->rd_bcache_cache_allocations_clean, clean);
+ rrddim_set_by_pointer(d->st_bcache_cache_allocations, d->rd_bcache_cache_allocations_metadata, metadata);
+ rrddim_set_by_pointer(d->st_bcache_cache_allocations, d->rd_bcache_cache_allocations_unknown, unknown);
+ rrdset_done(d->st_bcache_cache_allocations);
+ }
+}
+
static inline int is_major_enabled(int major) {
static int8_t *major_configs = NULL;
static size_t major_size = 0;
@@ -191,67 +305,101 @@ 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(CONFIG_SECTION_DISKSTATS, buffer, 1);
+ major_configs[major] = (char)config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, buffer, 1);
}
return (int)major_configs[major];
}
-static inline int get_disk_name_from_path(const char *path, char *result, size_t result_size, unsigned long major, unsigned long minor, char *disk) {
- char filename[FILENAME_MAX + 1];
- int found = 0;
+static inline int get_disk_name_from_path(const char *path, char *result, size_t result_size, unsigned long major, unsigned long minor, char *disk, char *prefix, int depth) {
+ //info("DEVICE-MAPPER ('%s', %lu:%lu): examining directory '%s' (allowed depth %d).", disk, major, minor, path, depth);
- result_size--;
+ int found = 0;
DIR *dir = opendir(path);
if (!dir) {
- error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot open directory '%s'. Disabling device-mapper support.", disk, major, minor, path);
- goto cleanup;
+ error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot open directory '%s'.", disk, major, minor, path);
+ goto failed;
}
struct dirent *de = NULL;
while ((de = readdir(dir))) {
- if(de->d_type != DT_LNK) continue;
+ if(de->d_type == DT_DIR) {
+ if((de->d_name[0] == '.' && de->d_name[1] == '\0') || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0'))
+ continue;
- snprintfz(filename, FILENAME_MAX, "%s/%s", path, de->d_name);
- ssize_t len = readlink(filename, result, result_size);
- if(len <= 0) {
- error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot read link '%s'.", disk, major, minor, filename);
- continue;
- }
+ if(depth <= 0) {
+ error("DEVICE-MAPPER ('%s', %lu:%lu): Depth limit reached for path '%s/%s'. Ignoring path.", disk, major, minor, path, de->d_name);
+ break;
+ }
+ else {
+ char *path_nested = NULL;
+ char *prefix_nested = NULL;
- result[len] = '\0';
- if(result[0] != '/')
- snprintfz(filename, FILENAME_MAX, "%s/%s", path, result);
- else
- strncpyz(filename, result, FILENAME_MAX);
+ {
+ char buffer[FILENAME_MAX + 1];
+ snprintfz(buffer, FILENAME_MAX, "%s/%s", path, de->d_name);
+ path_nested = strdupz(buffer);
- struct stat sb;
- if(stat(filename, &sb) == -1) {
- error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot stat() file '%s'.", disk, major, minor, filename);
- continue;
- }
+ snprintfz(buffer, FILENAME_MAX, "%s%s%s", (prefix)?prefix:"", (prefix)?"_":"", de->d_name);
+ prefix_nested = strdupz(buffer);
+ }
- if((sb.st_mode & S_IFMT) != S_IFBLK) {
- // info("DEVICE-MAPPER ('%s', %lu:%lu): file '%s' is not a block device.", disk, major, minor, filename);
- continue;
- }
+ found = get_disk_name_from_path(path_nested, result, result_size, major, minor, disk, prefix_nested, depth - 1);
+ freez(path_nested);
+ freez(prefix_nested);
- if(major(sb.st_rdev) != major || minor(sb.st_rdev) != minor) {
- // info("DEVICE-MAPPER ('%s', %lu:%lu): filename '%s' does not match %lu:%lu.", disk, major, minor, filename, (unsigned long)major(sb.st_rdev), (unsigned long)minor(sb.st_rdev));
- continue;
+ if(found) break;
+ }
}
+ else if(de->d_type == DT_LNK || de->d_type == DT_BLK) {
+ char filename[FILENAME_MAX + 1];
+
+ if(de->d_type == DT_LNK) {
+ snprintfz(filename, FILENAME_MAX, "%s/%s", path, de->d_name);
+ ssize_t len = readlink(filename, result, result_size - 1);
+ if(len <= 0) {
+ error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot read link '%s'.", disk, major, minor, filename);
+ continue;
+ }
+
+ result[len] = '\0';
+ if(result[0] != '/')
+ snprintfz(filename, FILENAME_MAX, "%s/%s", path, result);
+ else
+ strncpyz(filename, result, FILENAME_MAX);
+ }
+ else {
+ snprintfz(filename, FILENAME_MAX, "%s/%s", path, de->d_name);
+ }
+
+ struct stat sb;
+ if(stat(filename, &sb) == -1) {
+ error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot stat() file '%s'.", disk, major, minor, filename);
+ continue;
+ }
+
+ if((sb.st_mode & S_IFMT) != S_IFBLK) {
+ //info("DEVICE-MAPPER ('%s', %lu:%lu): file '%s' is not a block device.", disk, major, minor, filename);
+ continue;
+ }
+
+ if(major(sb.st_rdev) != major || minor(sb.st_rdev) != minor) {
+ //info("DEVICE-MAPPER ('%s', %lu:%lu): filename '%s' does not match %lu:%lu.", disk, major, minor, filename, (unsigned long)major(sb.st_rdev), (unsigned long)minor(sb.st_rdev));
+ continue;
+ }
- // info("DEVICE-MAPPER ('%s', %lu:%lu): filename '%s' matches.", disk, major, minor, filename);
+ //info("DEVICE-MAPPER ('%s', %lu:%lu): filename '%s' matches.", disk, major, minor, filename);
- strncpy(result, de->d_name, result_size);
- found = 1;
- break;
+ snprintfz(result, result_size - 1, "%s%s%s", (prefix)?prefix:"", (prefix)?"_":"", de->d_name);
+ found = 1;
+ break;
+ }
}
closedir(dir);
-cleanup:
+failed:
if(!found)
result[0] = '\0';
@@ -262,10 +410,11 @@ cleanup:
static inline char *get_disk_name(unsigned long major, unsigned long minor, char *disk) {
char result[FILENAME_MAX + 1] = "";
- if(!path_to_device_mapper || !*path_to_device_mapper || !get_disk_name_from_path(path_to_device_mapper, result, FILENAME_MAX + 1, major, minor, disk))
- if(!path_to_device_label || !*path_to_device_label || !get_disk_name_from_path(path_to_device_label, result, FILENAME_MAX + 1, major, minor, disk))
- if(name_disks_by_id != CONFIG_BOOLEAN_YES || !path_to_device_id || !*path_to_device_id || !get_disk_name_from_path(path_to_device_id, result, FILENAME_MAX + 1, major, minor, disk))
- strncpy(result, disk, FILENAME_MAX);
+ if(!path_to_device_mapper || !*path_to_device_mapper || !get_disk_name_from_path(path_to_device_mapper, result, FILENAME_MAX + 1, major, minor, disk, NULL, 0))
+ if(!path_to_device_label || !*path_to_device_label || !get_disk_name_from_path(path_to_device_label, result, FILENAME_MAX + 1, major, minor, disk, NULL, 0))
+ if(!path_to_veritas_volume_groups || !*path_to_veritas_volume_groups || !get_disk_name_from_path(path_to_veritas_volume_groups, result, FILENAME_MAX + 1, major, minor, disk, "vx", 2))
+ if(name_disks_by_id != CONFIG_BOOLEAN_YES || !path_to_device_id || !*path_to_device_id || !get_disk_name_from_path(path_to_device_id, result, FILENAME_MAX + 1, major, minor, disk, NULL, 0))
+ strncpy(result, disk, FILENAME_MAX);
if(!result[0])
strncpy(result, disk, FILENAME_MAX);
@@ -281,7 +430,7 @@ static void get_disk_config(struct disk *d) {
def_enable = CONFIG_BOOLEAN_NO;
char var_name[4096 + 1];
- snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", d->disk);
+ snprintfz(var_name, 4096, CONFIG_SECTION_PLUGIN_PROC_DISKSTATS ":%s", d->disk);
def_enable = config_get_boolean_ondemand(var_name, "enable", def_enable);
if(unlikely(def_enable == CONFIG_BOOLEAN_NO)) {
@@ -532,6 +681,24 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
else
error("bcache file '%s' cannot be read.", buffer2);
+ snprintfz(buffer2, FILENAME_MAX, "%s/cache/cache0/priority_stats", buffer); // only one cache is supported by bcache
+ if(access(buffer2, R_OK) == 0)
+ d->bcache_filename_priority_stats = strdupz(buffer2);
+ else
+ error("bcache file '%s' cannot be read.", buffer2);
+
+ snprintfz(buffer2, FILENAME_MAX, "%s/cache/internal/cache_read_races", buffer);
+ if(access(buffer2, R_OK) == 0)
+ d->bcache_filename_cache_read_races = strdupz(buffer2);
+ else
+ error("bcache file '%s' cannot be read.", buffer2);
+
+ snprintfz(buffer2, FILENAME_MAX, "%s/cache/cache0/io_errors", buffer);
+ if(access(buffer2, R_OK) == 0)
+ d->bcache_filename_cache_io_errors = strdupz(buffer2);
+ else
+ error("bcache file '%s' cannot be read.", buffer2);
+
snprintfz(buffer2, FILENAME_MAX, "%s/dirty_data", buffer);
if(access(buffer2, R_OK) == 0)
d->bcache_filename_dirty_data = strdupz(buffer2);
@@ -615,55 +782,59 @@ int do_proc_diskstats(int update_every, usec_t dt) {
if(unlikely(!globals_initialized)) {
globals_initialized = 1;
- global_enable_new_disks_detected_at_runtime = config_get_boolean(CONFIG_SECTION_DISKSTATS, "enable new disks detected at runtime", global_enable_new_disks_detected_at_runtime);
- global_enable_performance_for_physical_disks = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "performance metrics for physical disks", global_enable_performance_for_physical_disks);
- global_enable_performance_for_virtual_disks = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
- global_enable_performance_for_partitions = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "performance metrics for partitions", global_enable_performance_for_partitions);
-
- global_do_io = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "bandwidth for all disks", global_do_io);
- global_do_ops = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "operations for all disks", global_do_ops);
- global_do_mops = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "merged operations for all disks", global_do_mops);
- global_do_iotime = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "i/o time for all disks", global_do_iotime);
- global_do_qops = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "queued operations for all disks", global_do_qops);
- global_do_util = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "utilization percentage for all disks", global_do_util);
- global_do_backlog = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "backlog for all disks", global_do_backlog);
- global_do_bcache = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "bcache for all disks", global_do_bcache);
-
- global_cleanup_removed_disks = config_get_boolean(CONFIG_SECTION_DISKSTATS, "remove charts of removed disks" , global_cleanup_removed_disks);
+ global_enable_new_disks_detected_at_runtime = config_get_boolean(CONFIG_SECTION_PLUGIN_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(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "performance metrics for physical disks", global_enable_performance_for_physical_disks);
+ global_enable_performance_for_virtual_disks = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
+ global_enable_performance_for_partitions = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "performance metrics for partitions", global_enable_performance_for_partitions);
+
+ global_do_io = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "bandwidth for all disks", global_do_io);
+ global_do_ops = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "operations for all disks", global_do_ops);
+ global_do_mops = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "merged operations for all disks", global_do_mops);
+ global_do_iotime = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "i/o time for all disks", global_do_iotime);
+ global_do_qops = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "queued operations for all disks", global_do_qops);
+ global_do_util = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "utilization percentage for all disks", global_do_util);
+ global_do_backlog = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "backlog for all disks", global_do_backlog);
+ global_do_bcache = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "bcache for all disks", global_do_bcache);
+ global_bcache_priority_stats_update_every = (int)config_get_number(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "bcache priority stats update every", global_bcache_priority_stats_update_every);
+
+ global_cleanup_removed_disks = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "remove charts of removed disks" , global_cleanup_removed_disks);
char buffer[FILENAME_MAX + 1];
snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s");
- path_to_sys_block_device = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device", buffer);
+ path_to_sys_block_device = config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "path to get block device", buffer);
snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/bcache");
- path_to_sys_block_device_bcache = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device bcache", buffer);
+ path_to_sys_block_device_bcache = config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "path to get block device bcache", buffer);
snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/block/%s");
- path_to_sys_devices_virtual_block_device = config_get(CONFIG_SECTION_DISKSTATS, "path to get virtual block device", buffer);
+ path_to_sys_devices_virtual_block_device = config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "path to get virtual block device", buffer);
snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/%s");
- path_to_sys_dev_block_major_minor_string = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device infos", buffer);
+ path_to_sys_dev_block_major_minor_string = config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "path to get block device infos", buffer);
//snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/queue/hw_sector_size");
- //path_to_get_hw_sector_size = config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size", buffer);
+ //path_to_get_hw_sector_size = config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "path to get h/w sector size", buffer);
//snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
- //path_to_get_hw_sector_size_partitions = config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size for partitions", buffer);
+ //path_to_get_hw_sector_size_partitions = config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "path to get h/w sector size for partitions", buffer);
snprintfz(buffer, FILENAME_MAX, "%s/dev/mapper", netdata_configured_host_prefix);
- path_to_device_mapper = config_get(CONFIG_SECTION_DISKSTATS, "path to device mapper", buffer);
+ path_to_device_mapper = config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "path to device mapper", buffer);
snprintfz(buffer, FILENAME_MAX, "%s/dev/disk/by-label", netdata_configured_host_prefix);
- path_to_device_label = config_get(CONFIG_SECTION_DISKSTATS, "path to /dev/disk/by-label", buffer);
+ path_to_device_label = config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "path to /dev/disk/by-label", buffer);
snprintfz(buffer, FILENAME_MAX, "%s/dev/disk/by-id", netdata_configured_host_prefix);
- path_to_device_id = config_get(CONFIG_SECTION_DISKSTATS, "path to /dev/disk/by-id", buffer);
+ path_to_device_id = config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "path to /dev/disk/by-id", buffer);
- name_disks_by_id = config_get_boolean(CONFIG_SECTION_DISKSTATS, "name disks by id", name_disks_by_id);
+ snprintfz(buffer, FILENAME_MAX, "%s/dev/vx/dsk", netdata_configured_host_prefix);
+ path_to_veritas_volume_groups = config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "path to /dev/vx/dsk", buffer);
+
+ name_disks_by_id = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "name disks by id", name_disks_by_id);
excluded_disks = simple_pattern_create(
- config_get(CONFIG_SECTION_DISKSTATS, "exclude disks", DEFAULT_EXCLUDED_DISKS)
+ config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "exclude disks", DEFAULT_EXCLUDED_DISKS)
, NULL
, SIMPLE_PATTERN_EXACT
);
@@ -674,7 +845,7 @@ int do_proc_diskstats(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/diskstats");
- ff = procfile_open(config_get(CONFIG_SECTION_DISKSTATS, "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(config_get(CONFIG_SECTION_PLUGIN_PROC_DISKSTATS, "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(unlikely(!ff)) return 0;
@@ -790,9 +961,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.io"
, "Disk I/O Bandwidth"
, "kilobytes/s"
- , "proc"
- , "diskstats"
- , 2000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_DISK_IO
, update_every
, RRDSET_TYPE_AREA
);
@@ -821,9 +992,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.ops"
, "Disk Completed I/O Operations"
, "operations/s"
- , "proc"
- , "diskstats"
- , 2001
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_DISK_OPS
, update_every
, RRDSET_TYPE_LINE
);
@@ -854,9 +1025,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.qops"
, "Disk Current I/O Operations"
, "operations"
- , "proc"
- , "diskstats"
- , 2002
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_DISK_QOPS
, update_every
, RRDSET_TYPE_LINE
);
@@ -885,9 +1056,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.backlog"
, "Disk Backlog"
, "backlog (ms)"
- , "proc"
- , "diskstats"
- , 2003
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_DISK_BACKLOG
, update_every
, RRDSET_TYPE_AREA
);
@@ -916,9 +1087,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.util"
, "Disk Utilization Time"
, "% of time working"
- , "proc"
- , "diskstats"
- , 2004
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_DISK_UTIL
, update_every
, RRDSET_TYPE_AREA
);
@@ -947,9 +1118,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.mops"
, "Disk Merged Operations"
, "merged operations/s"
- , "proc"
- , "diskstats"
- , 2021
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_DISK_MOPS
, update_every
, RRDSET_TYPE_LINE
);
@@ -980,9 +1151,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.iotime"
, "Disk Total I/O Time"
, "milliseconds/s"
- , "proc"
- , "diskstats"
- , 2022
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_DISK_IOTIME
, update_every
, RRDSET_TYPE_LINE
);
@@ -1016,9 +1187,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.await"
, "Average Completed I/O Operation Time"
, "ms per operation"
- , "proc"
- , "diskstats"
- , 2005
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_DISK_AWAIT
, update_every
, RRDSET_TYPE_LINE
);
@@ -1047,9 +1218,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.avgsz"
, "Average Completed I/O Operation Bandwidth"
, "kilobytes per operation"
- , "proc"
- , "diskstats"
- , 2006
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_DISK_AVGSZ
, update_every
, RRDSET_TYPE_AREA
);
@@ -1078,9 +1249,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.svctm"
, "Average Service Time"
, "ms per operation"
- , "proc"
- , "diskstats"
- , 2007
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_DISK_SVCTM
, update_every
, RRDSET_TYPE_LINE
);
@@ -1112,6 +1283,8 @@ int do_proc_diskstats(int update_every, usec_t dt) {
stats_total_cache_hit_ratio = 0,
cache_available_percent = 0,
cache_readaheads = 0,
+ cache_read_races = 0,
+ cache_io_errors = 0,
cache_congested = 0,
dirty_data = 0,
writeback_rate = 0;
@@ -1160,11 +1333,18 @@ int do_proc_diskstats(int update_every, usec_t dt) {
if(d->bcache_filename_stats_total_cache_readaheads)
cache_readaheads = bcache_read_number_with_units(d->bcache_filename_stats_total_cache_readaheads);
+ if(d->bcache_filename_cache_read_races)
+ read_single_number_file(d->bcache_filename_cache_read_races, &cache_read_races);
+
+ if(d->bcache_filename_cache_io_errors)
+ read_single_number_file(d->bcache_filename_cache_io_errors, &cache_io_errors);
+
+ if(d->bcache_filename_priority_stats && global_bcache_priority_stats_update_every >= 1)
+ bcache_read_priority_stats(d, family, global_bcache_priority_stats_update_every, dt);
// update the charts
{
-
if(unlikely(!d->st_bcache_hit_ratio)) {
d->st_bcache_hit_ratio = rrdset_create_localhost(
"disk_bcache_hit_ratio"
@@ -1174,9 +1354,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.bcache_hit_ratio"
, "BCache Cache Hit Ratio"
, "percentage"
- , "proc"
- , "diskstats"
- , 2120
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_BCACHE_HIT_RATIO
, update_every
, RRDSET_TYPE_LINE
);
@@ -1206,9 +1386,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.bcache_rates"
, "BCache Rates"
, "KB/s"
- , "proc"
- , "diskstats"
- , 2121
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_BCACHE_RATES
, update_every
, RRDSET_TYPE_AREA
);
@@ -1233,9 +1413,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.bcache_size"
, "BCache Cache Sizes"
, "MB"
- , "proc"
- , "diskstats"
- , 2122
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_BCACHE_SIZE
, update_every
, RRDSET_TYPE_AREA
);
@@ -1258,9 +1438,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.bcache_usage"
, "BCache Cache Usage"
, "percent"
- , "proc"
- , "diskstats"
- , 2123
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_BCACHE_USAGE
, update_every
, RRDSET_TYPE_AREA
);
@@ -1273,6 +1453,34 @@ int do_proc_diskstats(int update_every, usec_t dt) {
rrdset_done(d->st_bcache_usage);
}
+ {
+
+ if(unlikely(!d->st_bcache_cache_read_races)) {
+ d->st_bcache_cache_read_races = rrdset_create_localhost(
+ "disk_bcache_cache_read_races"
+ , d->device
+ , d->disk
+ , family
+ , "disk.bcache_cache_read_races"
+ , "BCache Cache Read Races"
+ , "operations/s"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_BCACHE_CACHE_READ_RACES
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ d->rd_bcache_cache_read_races = rrddim_add(d->st_bcache_cache_read_races, "races", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_bcache_cache_io_errors = rrddim_add(d->st_bcache_cache_read_races, "errors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(d->st_bcache_cache_read_races);
+
+ rrddim_set_by_pointer(d->st_bcache_cache_read_races, d->rd_bcache_cache_read_races, cache_read_races);
+ rrddim_set_by_pointer(d->st_bcache_cache_read_races, d->rd_bcache_cache_io_errors, cache_io_errors);
+ rrdset_done(d->st_bcache_cache_read_races);
+ }
+
if(d->do_bcache == CONFIG_BOOLEAN_YES || (d->do_bcache == CONFIG_BOOLEAN_AUTO && (stats_total_cache_hits != 0 || stats_total_cache_misses != 0 || stats_total_cache_miss_collisions != 0))) {
if(unlikely(!d->st_bcache)) {
@@ -1284,9 +1492,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.bcache"
, "BCache Cache I/O Operations"
, "operations/s"
- , "proc"
- , "diskstats"
- , 2124
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_BCACHE_OPS
, update_every
, RRDSET_TYPE_LINE
);
@@ -1318,9 +1526,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, "disk.bcache_bypass"
, "BCache Cache Bypass I/O Operations"
, "operations/s"
- , "proc"
- , "diskstats"
- , 2125
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_BCACHE_BYPASS
, update_every
, RRDSET_TYPE_LINE
);
@@ -1356,9 +1564,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
, NULL
, "Disk I/O"
, "kilobytes/s"
- , "proc"
- , "diskstats"
- , 150
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_DISKSTATS_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_IO
, update_every
, RRDSET_TYPE_AREA
);
@@ -1421,6 +1629,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
freez(t->bcache_filename_stats_total_cache_bypass_hits);
freez(t->bcache_filename_stats_total_cache_bypass_misses);
freez(t->bcache_filename_stats_total_cache_readaheads);
+ freez(t->bcache_filename_cache_read_races);
+ freez(t->bcache_filename_cache_io_errors);
+ freez(t->bcache_filename_priority_stats);
freez(t->disk);
freez(t->device);
diff --git a/src/proc_interrupts.c b/collectors/proc.plugin/proc_interrupts.c
index 867f39eb2..73b117179 100644
--- a/src/proc_interrupts.c
+++ b/collectors/proc.plugin/proc_interrupts.c
@@ -1,4 +1,9 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_INTERRUPTS_NAME "/proc/interrupts"
+#define CONFIG_SECTION_PLUGIN_PROC_INTERRUPTS "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_INTERRUPTS_NAME
#define MAX_INTERRUPT_NAME 50
@@ -51,16 +56,16 @@ static inline struct interrupt *get_interrupts_array(size_t lines, int cpus) {
int do_proc_interrupts(int update_every, usec_t dt) {
(void)dt;
static procfile *ff = NULL;
- static int cpus = -1, do_per_core = -1;
+ static int cpus = -1, do_per_core = CONFIG_BOOLEAN_INVALID;
struct interrupt *irrs = NULL;
- if(unlikely(do_per_core == -1))
- do_per_core = config_get_boolean("plugin:proc:/proc/interrupts", "interrupts per core", 1);
+ if(unlikely(do_per_core == CONFIG_BOOLEAN_INVALID))
+ do_per_core = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_INTERRUPTS, "interrupts per core", CONFIG_BOOLEAN_AUTO);
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/interrupts");
- ff = procfile_open(config_get("plugin:proc:/proc/interrupts", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(config_get(CONFIG_SECTION_PLUGIN_PROC_INTERRUPTS, "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(unlikely(!ff))
return 1;
@@ -109,8 +114,8 @@ int do_proc_interrupts(int update_every, usec_t dt) {
if(unlikely(!irr->id || !irr->id[0])) continue;
size_t idlen = strlen(irr->id);
- if(unlikely(idlen && irr->id[idlen - 1] == ':'))
- irr->id[idlen - 1] = '\0';
+ if(irr->id[idlen - 1] == ':')
+ irr->id[--idlen] = '\0';
int c;
for(c = 0; c < cpus ;c++) {
@@ -125,7 +130,6 @@ int do_proc_interrupts(int update_every, usec_t dt) {
if(unlikely(isdigit(irr->id[0]) && (uint32_t)(cpus + 2) < words)) {
strncpyz(irr->name, procfile_lineword(ff, l, words - 1), MAX_INTERRUPT_NAME);
size_t nlen = strlen(irr->name);
- idlen = strlen(irr->id);
if(likely(nlen + 1 + idlen <= MAX_INTERRUPT_NAME)) {
irr->name[nlen] = '_';
strncpyz(&irr->name[nlen + 1], irr->id, MAX_INTERRUPT_NAME - nlen - 1);
@@ -154,9 +158,9 @@ int do_proc_interrupts(int update_every, usec_t dt) {
, NULL
, "System interrupts"
, "interrupts/s"
- , "proc"
- , "interrupts"
- , 1000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_INTERRUPTS_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_INTERRUPTS
, update_every
, RRDSET_TYPE_STACKED
);
@@ -165,34 +169,30 @@ int do_proc_interrupts(int update_every, usec_t dt) {
for(l = 0; l < lines ;l++) {
struct interrupt *irr = irrindex(irrs, l, cpus);
- if(unlikely(!irr->used)) continue;
-
- // some interrupt may have changed without changing the total number of lines
- // if the same number of interrupts have been added and removed between two
- // calls of this function.
- if(unlikely(!irr->rd || strncmp(irr->rd->name, irr->name, MAX_INTERRUPT_NAME) != 0)) {
- irr->rd = rrddim_find(st_system_interrupts, irr->id);
-
- if(unlikely(!irr->rd))
+ if(irr->used && irr->total) {
+ // some interrupt may have changed without changing the total number of lines
+ // if the same number of interrupts have been added and removed between two
+ // calls of this function.
+ if(unlikely(!irr->rd || strncmp(irr->rd->name, irr->name, MAX_INTERRUPT_NAME) != 0)) {
irr->rd = rrddim_add(st_system_interrupts, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- else
rrddim_set_name(st_system_interrupts, irr->rd, irr->name);
- // also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop
- if(likely(do_per_core)) {
- int c;
- for (c = 0; c < cpus ;c++) irr->cpu[c].rd = NULL;
+ // also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop
+ if(likely(do_per_core != CONFIG_BOOLEAN_NO)) {
+ int c;
+ for(c = 0; c < cpus; c++) irr->cpu[c].rd = NULL;
+ }
}
- }
- rrddim_set_by_pointer(st_system_interrupts, irr->rd, irr->total);
+ rrddim_set_by_pointer(st_system_interrupts, irr->rd, irr->total);
+ }
}
rrdset_done(st_system_interrupts);
// --------------------------------------------------------------------
- if(likely(do_per_core)) {
+ if(likely(do_per_core != CONFIG_BOOLEAN_NO)) {
static RRDSET **core_st = NULL;
static int old_cpus = 0;
@@ -219,9 +219,9 @@ int do_proc_interrupts(int update_every, usec_t dt) {
, "cpu.interrupts"
, title
, "interrupts/s"
- , "proc"
- , "interrupts"
- , 1100 + c
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_INTERRUPTS_NAME
+ , NETDATA_CHART_PRIO_INTERRUPTS_PER_CORE + c
, update_every
, RRDSET_TYPE_STACKED
);
@@ -230,19 +230,14 @@ int do_proc_interrupts(int update_every, usec_t dt) {
for(l = 0; l < lines ;l++) {
struct interrupt *irr = irrindex(irrs, l, cpus);
-
- if(unlikely(!irr->used)) continue;
-
- if(unlikely(!irr->cpu[c].rd)) {
- irr->cpu[c].rd = rrddim_find(core_st[c], irr->id);
-
- if(unlikely(!irr->cpu[c].rd))
+ if(irr->used && (do_per_core == CONFIG_BOOLEAN_YES || irr->cpu[c].value)) {
+ if(unlikely(!irr->cpu[c].rd)) {
irr->cpu[c].rd = rrddim_add(core_st[c], irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- else
rrddim_set_name(core_st[c], irr->cpu[c].rd, irr->name);
- }
+ }
- rrddim_set_by_pointer(core_st[c], irr->cpu[c].rd, irr->cpu[c].value);
+ rrddim_set_by_pointer(core_st[c], irr->cpu[c].rd, irr->cpu[c].value);
+ }
}
rrdset_done(core_st[c]);
diff --git a/src/proc_loadavg.c b/collectors/proc.plugin/proc_loadavg.c
index 868f7d50a..db95b1689 100644
--- a/src/proc_loadavg.c
+++ b/collectors/proc.plugin/proc_loadavg.c
@@ -1,4 +1,9 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_LOADAVG_NAME "/proc/loadavg"
+#define CONFIG_SECTION_PLUGIN_PROC_LOADAVG "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_LOADAVG_NAME
// linux calculates this once every 5 seconds
#define MIN_LOADAVG_UPDATE_EVERY 5
@@ -12,7 +17,7 @@ int do_proc_loadavg(int update_every, usec_t dt) {
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/loadavg");
- ff = procfile_open(config_get("plugin:proc:/proc/loadavg", "filename to monitor", filename), " \t,:|/", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(config_get(CONFIG_SECTION_PLUGIN_PROC_LOADAVG, "filename to monitor", filename), " \t,:|/", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
return 1;
}
@@ -22,8 +27,8 @@ int do_proc_loadavg(int update_every, usec_t dt) {
return 0; // we return 0, so that we will retry to open it next time
if(unlikely(do_loadavg == -1)) {
- do_loadavg = config_get_boolean("plugin:proc:/proc/loadavg", "enable load average", 1);
- do_all_processes = config_get_boolean("plugin:proc:/proc/loadavg", "enable total processes", 1);
+ do_loadavg = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_LOADAVG, "enable load average", 1);
+ do_all_processes = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_LOADAVG, "enable total processes", 1);
}
if(unlikely(procfile_lines(ff) < 1)) {
@@ -60,9 +65,9 @@ int do_proc_loadavg(int update_every, usec_t dt) {
, NULL
, "System Load Average"
, "load"
- , "proc"
- , "loadavg"
- , 100
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_LOADAVG_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_LOAD
, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every
, RRDSET_TYPE_LINE
);
@@ -100,9 +105,9 @@ int do_proc_loadavg(int update_every, usec_t dt) {
, NULL
, "System Active Processes"
, "processes"
- , "proc"
- , "loadavg"
- , 750
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_LOADAVG_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_ACTIVE_PROCESSES
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/proc_meminfo.c b/collectors/proc.plugin/proc_meminfo.c
index 3915bf0e9..f77159ebd 100644
--- a/src/proc_meminfo.c
+++ b/collectors/proc.plugin/proc_meminfo.c
@@ -1,4 +1,9 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_MEMINFO_NAME "/proc/meminfo"
+#define CONFIG_SECTION_PLUGIN_PROC_MEMINFO "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_MEMINFO_NAME
int do_proc_meminfo(int update_every, usec_t dt) {
(void)dt;
@@ -56,15 +61,15 @@ int do_proc_meminfo(int update_every, usec_t dt) {
HardwareCorrupted = 0;
if(unlikely(!arl_base)) {
- do_ram = config_get_boolean("plugin:proc:/proc/meminfo", "system ram", 1);
- do_swap = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "system swap", CONFIG_BOOLEAN_AUTO);
- do_hwcorrupt = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hardware corrupted ECC", CONFIG_BOOLEAN_AUTO);
- do_committed = config_get_boolean("plugin:proc:/proc/meminfo", "committed memory", 1);
- do_writeback = config_get_boolean("plugin:proc:/proc/meminfo", "writeback memory", 1);
- do_kernel = config_get_boolean("plugin:proc:/proc/meminfo", "kernel memory", 1);
- do_slab = config_get_boolean("plugin:proc:/proc/meminfo", "slab memory", 1);
- do_hugepages = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hugepages", CONFIG_BOOLEAN_AUTO);
- do_transparent_hugepages = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "transparent hugepages", CONFIG_BOOLEAN_AUTO);
+ do_ram = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "system ram", 1);
+ do_swap = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "system swap", CONFIG_BOOLEAN_AUTO);
+ do_hwcorrupt = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "hardware corrupted ECC", CONFIG_BOOLEAN_AUTO);
+ do_committed = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "committed memory", 1);
+ do_writeback = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "writeback memory", 1);
+ do_kernel = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "kernel memory", 1);
+ do_slab = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "slab memory", 1);
+ do_hugepages = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "hugepages", CONFIG_BOOLEAN_AUTO);
+ do_transparent_hugepages = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "transparent hugepages", CONFIG_BOOLEAN_AUTO);
arl_base = arl_create("meminfo", NULL, 60);
arl_expect(arl_base, "MemTotal", &MemTotal);
@@ -116,7 +121,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", netdata_configured_host_prefix, "/proc/meminfo");
- ff = procfile_open(config_get("plugin:proc:/proc/meminfo", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(config_get(CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
return 1;
}
@@ -158,9 +163,9 @@ int do_proc_meminfo(int update_every, usec_t dt) {
, NULL
, "System RAM"
, "MB"
- , "proc"
- , "meminfo"
- , 200
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_MEMINFO_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_RAM
, update_every
, RRDSET_TYPE_STACKED
);
@@ -193,8 +198,8 @@ int do_proc_meminfo(int update_every, usec_t dt) {
, NULL
, "Available RAM for applications"
, "MB"
- , "proc"
- , "meminfo"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_MEM_SYSTEM_AVAILABLE
, update_every
, RRDSET_TYPE_AREA
@@ -229,9 +234,9 @@ int do_proc_meminfo(int update_every, usec_t dt) {
, NULL
, "System Swap"
, "MB"
- , "proc"
- , "meminfo"
- , 201
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_MEMINFO_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_SWAP
, update_every
, RRDSET_TYPE_STACKED
);
@@ -266,8 +271,8 @@ int do_proc_meminfo(int update_every, usec_t dt) {
, NULL
, "Corrupted Memory, detected by ECC"
, "MB"
- , "proc"
- , "meminfo"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_MEM_HW
, update_every
, RRDSET_TYPE_LINE
@@ -299,8 +304,8 @@ int do_proc_meminfo(int update_every, usec_t dt) {
, NULL
, "Committed (Allocated) Memory"
, "MB"
- , "proc"
- , "meminfo"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_MEM_SYSTEM_COMMITTED
, update_every
, RRDSET_TYPE_AREA
@@ -332,8 +337,8 @@ int do_proc_meminfo(int update_every, usec_t dt) {
, NULL
, "Writeback Memory"
, "MB"
- , "proc"
- , "meminfo"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_MEM_KERNEL
, update_every
, RRDSET_TYPE_LINE
@@ -372,8 +377,8 @@ int do_proc_meminfo(int update_every, usec_t dt) {
, NULL
, "Memory Used by Kernel"
, "MB"
- , "proc"
- , "meminfo"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_MEM_KERNEL + 1
, update_every
, RRDSET_TYPE_STACKED
@@ -411,8 +416,8 @@ int do_proc_meminfo(int update_every, usec_t dt) {
, NULL
, "Reclaimable Kernel Memory"
, "MB"
- , "proc"
- , "meminfo"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_MEM_SLAB
, update_every
, RRDSET_TYPE_STACKED
@@ -448,8 +453,8 @@ int do_proc_meminfo(int update_every, usec_t dt) {
, NULL
, "Dedicated HugePages Memory"
, "MB"
- , "proc"
- , "meminfo"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_MEM_HUGEPAGES + 1
, update_every
, RRDSET_TYPE_STACKED
@@ -489,8 +494,8 @@ int do_proc_meminfo(int update_every, usec_t dt) {
, NULL
, "Transparent HugePages Memory"
, "MB"
- , "proc"
- , "meminfo"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_MEM_HUGEPAGES
, update_every
, RRDSET_TYPE_STACKED
diff --git a/src/proc_net_dev.c b/collectors/proc.plugin/proc_net_dev.c
index 341b9e0ca..97cbc060a 100644
--- a/src/proc_net_dev.c
+++ b/collectors/proc.plugin/proc_net_dev.c
@@ -1,4 +1,9 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_NETDEV_NAME "/proc/net/dev"
+#define CONFIG_SECTION_PLUGIN_PROC_NETDEV "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_NETDEV_NAME
// ----------------------------------------------------------------------------
// netdev list
@@ -61,6 +66,7 @@ static struct netdev {
kernel_uint_t tcollisions;
kernel_uint_t tcarrier;
kernel_uint_t tcompressed;
+ kernel_uint_t speed_max;
// charts
RRDSET *st_bandwidth;
@@ -296,7 +302,7 @@ static inline void netdev_rename_cgroup(struct netdev *d, struct netdev_rename *
snprintfz(buffer, RRD_ID_LENGTH_MAX, "net %s", r->container_device);
d->chart_family = strdupz(buffer);
- d->priority = 43000;
+ d->priority = NETDATA_CHART_PRIO_CGROUP_NET_IFACE;
d->flipped = 1;
}
@@ -405,7 +411,7 @@ static struct netdev *get_netdev(const char *name) {
d->chart_id_net_packets = strdupz(d->name);
d->chart_family = strdupz(d->name);
- d->priority = 7000;
+ d->priority = NETDATA_CHART_PRIO_FIRST_NET_IFACE;
netdev_rename_lock(d);
@@ -430,30 +436,31 @@ int do_proc_net_dev(int update_every, usec_t dt) {
static int enable_new_interfaces = -1;
static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
static char *path_to_sys_devices_virtual_net = NULL;
+ static char *path_to_sys_net_speed = NULL;
if(unlikely(enable_new_interfaces == -1)) {
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/net/%s");
- path_to_sys_devices_virtual_net = config_get("plugin:proc:/proc/net/dev", "path to get virtual interfaces", filename);
+ path_to_sys_devices_virtual_net = config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "path to get virtual interfaces", filename);
- enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_BOOLEAN_AUTO);
+ enable_new_interfaces = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "enable new interfaces detected at runtime", CONFIG_BOOLEAN_AUTO);
- do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_BOOLEAN_AUTO);
- do_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_BOOLEAN_AUTO);
- do_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_BOOLEAN_AUTO);
- do_drops = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_BOOLEAN_AUTO);
- do_fifo = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_BOOLEAN_AUTO);
- do_compressed = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_BOOLEAN_AUTO);
- do_events = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_bandwidth = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "bandwidth for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_packets = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "packets for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_errors = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "errors for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_drops = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "drops for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_fifo = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "fifo for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_compressed = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "compressed packets for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_events = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "frames, collisions, carrier counters for all interfaces", CONFIG_BOOLEAN_AUTO);
- disabled_list = simple_pattern_create(config_get("plugin:proc:/proc/net/dev", "disable by default interfaces matching", "lo fireqos* *-ifb"), NULL, SIMPLE_PATTERN_EXACT);
+ disabled_list = simple_pattern_create(config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "disable by default interfaces matching", "lo fireqos* *-ifb"), NULL, SIMPLE_PATTERN_EXACT);
}
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/dev");
- ff = procfile_open(config_get("plugin:proc:/proc/net/dev", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, (*netdata_configured_host_prefix)?"/proc/1/net/dev":"/proc/net/dev");
+ ff = procfile_open(config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -498,6 +505,14 @@ int do_proc_net_dev(int update_every, usec_t dt) {
else
d->virtual = 0;
+ // set nic speed if present
+ if(likely(!d->virtual)) {
+ snprintfz(buffer, FILENAME_MAX, "%s/sys/class/net/%s/speed", netdata_configured_host_prefix, d->name);
+ path_to_sys_net_speed = config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "path to get net device speed", buffer);
+ int ret = read_single_number_file(path_to_sys_net_speed, (unsigned long long*)&d->speed_max);
+ if(ret) error("Cannot read '%s'.", path_to_sys_net_speed);
+ }
+
snprintfz(buffer, FILENAME_MAX, "plugin:proc:/proc/net/dev:%s", d->name);
d->enabled = config_get_boolean_ondemand(buffer, "enabled", d->enabled);
d->virtual = config_get_boolean(buffer, "virtual", d->virtual);
@@ -575,13 +590,16 @@ int do_proc_net_dev(int update_every, usec_t dt) {
, "net.net"
, "Bandwidth"
, "kilobits/s"
- , "proc"
- , "net/dev"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETDEV_NAME
, d->priority
, update_every
, RRDSET_TYPE_AREA
);
+ RRDSETVAR *nic_speed_max = rrdsetvar_custom_chart_variable_create(d->st_bandwidth, "nic_speed_max");
+ if(nic_speed_max) rrdsetvar_custom_chart_variable_set(nic_speed_max, (calculated_number)d->speed_max);
+
d->rd_rbytes = rrddim_add(d->st_bandwidth, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
d->rd_tbytes = rrddim_add(d->st_bandwidth, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
@@ -616,8 +634,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
, "net.packets"
, "Packets"
, "packets/s"
- , "proc"
- , "net/dev"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETDEV_NAME
, d->priority + 1
, update_every
, RRDSET_TYPE_LINE
@@ -661,8 +679,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
, "net.errors"
, "Interface Errors"
, "errors/s"
- , "proc"
- , "net/dev"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETDEV_NAME
, d->priority + 2
, update_every
, RRDSET_TYPE_LINE
@@ -704,8 +722,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
, "net.drops"
, "Interface Drops"
, "drops/s"
- , "proc"
- , "net/dev"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETDEV_NAME
, d->priority + 3
, update_every
, RRDSET_TYPE_LINE
@@ -747,8 +765,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
, "net.fifo"
, "Interface FIFO Buffer Errors"
, "errors"
- , "proc"
- , "net/dev"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETDEV_NAME
, d->priority + 4
, update_every
, RRDSET_TYPE_LINE
@@ -790,8 +808,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
, "net.compressed"
, "Compressed Packets"
, "packets/s"
- , "proc"
- , "net/dev"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETDEV_NAME
, d->priority + 5
, update_every
, RRDSET_TYPE_LINE
@@ -833,8 +851,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
, "net.events"
, "Network Interface Events"
, "events/s"
- , "proc"
- , "net/dev"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETDEV_NAME
, d->priority + 6
, update_every
, RRDSET_TYPE_LINE
@@ -869,9 +887,9 @@ int do_proc_net_dev(int update_every, usec_t dt) {
, NULL
, "Physical Network Interfaces Aggregated Bandwidth"
, "kilobits/s"
- , "proc"
- , "net/dev"
- , 500
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETDEV_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_NET
, update_every
, RRDSET_TYPE_AREA
);
diff --git a/src/proc_net_ip_vs_stats.c b/collectors/proc.plugin/proc_net_ip_vs_stats.c
index d76972f3c..43dcf2a88 100644
--- a/src/proc_net_ip_vs_stats.c
+++ b/collectors/proc.plugin/proc_net_ip_vs_stats.c
@@ -1,20 +1,24 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
-#define RRD_TYPE_NET_IPVS "ipvs"
+#include "plugin_proc.h"
+
+#define RRD_TYPE_NET_IPVS "ipvs"
+#define PLUGIN_PROC_MODULE_NET_IPVS_NAME "/proc/net/ip_vs_stats"
+#define CONFIG_SECTION_PLUGIN_PROC_NET_IPVS "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_NET_IPVS_NAME
int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
(void)dt;
static int do_bandwidth = -1, do_sockets = -1, do_packets = -1;
static procfile *ff = NULL;
- if(do_bandwidth == -1) do_bandwidth = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS bandwidth", 1);
- if(do_sockets == -1) do_sockets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS connections", 1);
- if(do_packets == -1) do_packets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS packets", 1);
+ if(do_bandwidth == -1) do_bandwidth = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_NET_IPVS, "IPVS bandwidth", 1);
+ if(do_sockets == -1) do_sockets = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_NET_IPVS, "IPVS connections", 1);
+ if(do_packets == -1) do_packets = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_NET_IPVS, "IPVS packets", 1);
if(!ff) {
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/ip_vs_stats");
- ff = procfile_open(config_get("plugin:proc:/proc/net/ip_vs_stats", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(config_get(CONFIG_SECTION_PLUGIN_PROC_NET_IPVS, "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
}
if(!ff) return 1;
@@ -50,9 +54,9 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
, NULL
, "IPVS New Connections"
, "connections/s"
- , "proc"
- , "net/ip_vs_stats"
- , 3101
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_IPVS_NAME
+ , NETDATA_CHART_PRIO_IPVS_SOCKETS
, update_every
, RRDSET_TYPE_LINE
);
@@ -78,9 +82,9 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
, NULL
, "IPVS Packets"
, "packets/s"
- , "proc"
- , "net/ip_vs_stats"
- , 3102
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_IPVS_NAME
+ , NETDATA_CHART_PRIO_IPVS_PACKETS
, update_every
, RRDSET_TYPE_LINE
);
@@ -108,9 +112,9 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
, NULL
, "IPVS Bandwidth"
, "kilobits/s"
- , "proc"
- , "net/ip_vs_stats"
- , 3100
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_IPVS_NAME
+ , NETDATA_CHART_PRIO_IPVS_NET
, update_every
, RRDSET_TYPE_AREA
);
diff --git a/src/proc_net_netstat.c b/collectors/proc.plugin/proc_net_netstat.c
index dd070e4c3..2dc3c59c0 100644
--- a/src/proc_net_netstat.c
+++ b/collectors/proc.plugin/proc_net_netstat.c
@@ -1,6 +1,12 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
-unsigned long long tcpext_TCPSynRetrans;
+#include "plugin_proc.h"
+
+#define RRD_TYPE_NET_NETSTAT "ip"
+#define PLUGIN_PROC_MODULE_NETSTAT_NAME "/proc/net/netstat"
+#define CONFIG_SECTION_PLUGIN_PROC_NETSTAT "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_NETSTAT_NAME
+
+unsigned long long tcpext_TCPSynRetrans = 0;
static void parse_line_pair(procfile *ff, ARL_BASE *base, size_t header_line, size_t values_line) {
size_t hwords = procfile_linewords(ff, header_line);
@@ -23,7 +29,7 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
static int do_bandwidth = -1, do_inerrors = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1, do_bcast_p = -1, do_ecn = -1, \
do_tcpext_reorder = -1, do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1, do_tcpext_memory = -1,
- do_tcpext_listen = -1;
+ do_tcpext_syn_queue = -1, do_tcpext_accept_queue = -1;
static uint32_t hash_ipext = 0, hash_tcpext = 0;
static procfile *ff = NULL;
@@ -32,61 +38,61 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
static ARL_BASE *arl_ipext = NULL;
// --------------------------------------------------------------------
- // IPv4
+ // IP
- // IPv4 bandwidth
+ // IP bandwidth
static unsigned long long ipext_InOctets = 0;
static unsigned long long ipext_OutOctets = 0;
- // IPv4 input errors
+ // IP input errors
static unsigned long long ipext_InNoRoutes = 0;
static unsigned long long ipext_InTruncatedPkts = 0;
static unsigned long long ipext_InCsumErrors = 0;
- // IPv4 multicast bandwidth
+ // IP multicast bandwidth
static unsigned long long ipext_InMcastOctets = 0;
static unsigned long long ipext_OutMcastOctets = 0;
- // IPv4 multicast packets
+ // IP multicast packets
static unsigned long long ipext_InMcastPkts = 0;
static unsigned long long ipext_OutMcastPkts = 0;
- // IPv4 broadcast bandwidth
+ // IP broadcast bandwidth
static unsigned long long ipext_InBcastOctets = 0;
static unsigned long long ipext_OutBcastOctets = 0;
- // IPv4 broadcast packets
+ // IP broadcast packets
static unsigned long long ipext_InBcastPkts = 0;
static unsigned long long ipext_OutBcastPkts = 0;
- // IPv4 ECN
+ // IP ECN
static unsigned long long ipext_InNoECTPkts = 0;
static unsigned long long ipext_InECT1Pkts = 0;
static unsigned long long ipext_InECT0Pkts = 0;
static unsigned long long ipext_InCEPkts = 0;
// --------------------------------------------------------------------
- // IPv4 TCP
+ // IP TCP
- // IPv4 TCP Reordering
+ // IP TCP Reordering
static unsigned long long tcpext_TCPRenoReorder = 0;
static unsigned long long tcpext_TCPFACKReorder = 0;
static unsigned long long tcpext_TCPSACKReorder = 0;
static unsigned long long tcpext_TCPTSReorder = 0;
- // IPv4 TCP SYN Cookies
+ // IP TCP SYN Cookies
static unsigned long long tcpext_SyncookiesSent = 0;
static unsigned long long tcpext_SyncookiesRecv = 0;
static unsigned long long tcpext_SyncookiesFailed = 0;
- // IPv4 TCP Out Of Order Queue
+ // IP TCP Out Of Order Queue
// http://www.spinics.net/lists/netdev/msg204696.html
static unsigned long long tcpext_TCPOFOQueue = 0; // Number of packets queued in OFO queue
static unsigned long long tcpext_TCPOFODrop = 0; // Number of packets meant to be queued in OFO but dropped because socket rcvbuf limit hit.
static unsigned long long tcpext_TCPOFOMerge = 0; // Number of packets in OFO that were merged with other packets.
static unsigned long long tcpext_OfoPruned = 0; // packets dropped from out-of-order queue because of socket buffer overrun
- // IPv4 TCP connection resets
+ // IP TCP connection resets
// https://github.com/ecki/net-tools/blob/bd8bceaed2311651710331a7f8990c3e31be9840/statistics.c
static unsigned long long tcpext_TCPAbortOnData = 0; // connections reset due to unexpected data
static unsigned long long tcpext_TCPAbortOnClose = 0; // connections reset due to early user close
@@ -99,9 +105,12 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
static unsigned long long tcpext_ListenOverflows = 0; // times the listen queue of a socket overflowed
static unsigned long long tcpext_ListenDrops = 0; // SYNs to LISTEN sockets ignored
- // IPv4 TCP memory pressures
+ // IP TCP memory pressures
static unsigned long long tcpext_TCPMemoryPressures = 0;
+ static unsigned long long tcpext_TCPReqQFullDrop = 0;
+ static unsigned long long tcpext_TCPReqQFullDoCookies = 0;
+
// shared: tcpext_TCPSynRetrans
@@ -109,26 +118,28 @@ 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_BOOLEAN_AUTO);
- do_inerrors = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "input errors", CONFIG_BOOLEAN_AUTO);
- do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast bandwidth", CONFIG_BOOLEAN_AUTO);
- do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast bandwidth", CONFIG_BOOLEAN_AUTO);
- do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast packets", CONFIG_BOOLEAN_AUTO);
- do_bcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast packets", CONFIG_BOOLEAN_AUTO);
- do_ecn = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "ECN packets", CONFIG_BOOLEAN_AUTO);
-
- do_tcpext_reorder = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP reorders", CONFIG_BOOLEAN_AUTO);
- do_tcpext_syscookies = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP SYN cookies", CONFIG_BOOLEAN_AUTO);
- do_tcpext_ofo = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP out-of-order queue", CONFIG_BOOLEAN_AUTO);
- do_tcpext_connaborts = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP connection aborts", CONFIG_BOOLEAN_AUTO);
- do_tcpext_memory = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP memory pressures", CONFIG_BOOLEAN_AUTO);
- do_tcpext_listen = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP listen issues", CONFIG_BOOLEAN_AUTO);
+ do_bandwidth = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_inerrors = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "input errors", CONFIG_BOOLEAN_AUTO);
+ do_mcast = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "multicast bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_bcast = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "broadcast bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_mcast_p = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "multicast packets", CONFIG_BOOLEAN_AUTO);
+ do_bcast_p = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "broadcast packets", CONFIG_BOOLEAN_AUTO);
+ do_ecn = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "ECN packets", CONFIG_BOOLEAN_AUTO);
+
+ do_tcpext_reorder = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "TCP reorders", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_syscookies = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "TCP SYN cookies", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_ofo = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "TCP out-of-order queue", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_connaborts = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "TCP connection aborts", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_memory = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "TCP memory pressures", CONFIG_BOOLEAN_AUTO);
+
+ do_tcpext_syn_queue = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "TCP SYN queue", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_accept_queue = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "TCP accept queue", CONFIG_BOOLEAN_AUTO);
arl_ipext = arl_create("netstat/ipext", NULL, 60);
arl_tcpext = arl_create("netstat/tcpext", NULL, 60);
// --------------------------------------------------------------------
- // IPv4
+ // IP
if(do_bandwidth != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InOctets", &ipext_InOctets);
@@ -169,7 +180,7 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
}
// --------------------------------------------------------------------
- // IPv4 TCP
+ // IP TCP
if(do_tcpext_reorder != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "TCPFACKReorder", &tcpext_TCPFACKReorder);
@@ -204,11 +215,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
arl_expect(arl_tcpext, "TCPMemoryPressures", &tcpext_TCPMemoryPressures);
}
- if(do_tcpext_listen != CONFIG_BOOLEAN_NO) {
+ if(do_tcpext_accept_queue != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "ListenOverflows", &tcpext_ListenOverflows);
arl_expect(arl_tcpext, "ListenDrops", &tcpext_ListenDrops);
}
+ if(do_tcpext_syn_queue != CONFIG_BOOLEAN_NO) {
+ arl_expect(arl_tcpext, "TCPReqQFullDrop", &tcpext_TCPReqQFullDrop);
+ arl_expect(arl_tcpext, "TCPReqQFullDoCookies", &tcpext_TCPReqQFullDoCookies);
+ }
+
// shared metrics
arl_expect(arl_tcpext, "TCPSynRetrans", &tcpext_TCPSynRetrans);
}
@@ -216,7 +232,7 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/netstat");
- ff = procfile_open(config_get("plugin:proc:/proc/net/netstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(config_get(CONFIG_SECTION_PLUGIN_PROC_NETSTAT, "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -248,111 +264,111 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO && (ipext_InOctets || ipext_OutOctets))) {
do_bandwidth = CONFIG_BOOLEAN_YES;
- static RRDSET *st_system_ipv4 = NULL;
+ static RRDSET *st_system_ip = NULL;
static RRDDIM *rd_in = NULL, *rd_out = NULL;
- if(unlikely(!st_system_ipv4)) {
- st_system_ipv4 = rrdset_create_localhost(
+ if(unlikely(!st_system_ip)) {
+ st_system_ip = rrdset_create_localhost(
"system"
- , "ipv4"
+ , RRD_TYPE_NET_NETSTAT
, NULL
, "network"
, NULL
- , "IPv4 Bandwidth"
+ , "IP Bandwidth"
, "kilobits/s"
- , "proc"
- , "net/netstat"
- , 501
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_IP
, update_every
, RRDSET_TYPE_AREA
);
- rd_in = rrddim_add(st_system_ipv4, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
- rd_out = rrddim_add(st_system_ipv4, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_in = rrddim_add(st_system_ip, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_system_ip, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
else
- rrdset_next(st_system_ipv4);
+ rrdset_next(st_system_ip);
- rrddim_set_by_pointer(st_system_ipv4, rd_in, ipext_InOctets);
- rrddim_set_by_pointer(st_system_ipv4, rd_out, ipext_OutOctets);
+ rrddim_set_by_pointer(st_system_ip, rd_in, ipext_InOctets);
+ rrddim_set_by_pointer(st_system_ip, rd_out, ipext_OutOctets);
- rrdset_done(st_system_ipv4);
+ rrdset_done(st_system_ip);
}
// --------------------------------------------------------------------
if(do_inerrors == CONFIG_BOOLEAN_YES || (do_inerrors == CONFIG_BOOLEAN_AUTO && (ipext_InNoRoutes || ipext_InTruncatedPkts))) {
do_inerrors = CONFIG_BOOLEAN_YES;
- static RRDSET *st_ipv4_inerrors = NULL;
+ static RRDSET *st_ip_inerrors = NULL;
static RRDDIM *rd_noroutes = NULL, *rd_truncated = NULL, *rd_checksum = NULL;
- if(unlikely(!st_ipv4_inerrors)) {
- st_ipv4_inerrors = rrdset_create_localhost(
- "ipv4"
+ if(unlikely(!st_ip_inerrors)) {
+ st_ip_inerrors = rrdset_create_localhost(
+ RRD_TYPE_NET_NETSTAT
, "inerrors"
, NULL
, "errors"
, NULL
- , "IPv4 Input Errors"
+ , "IP Input Errors"
, "packets/s"
- , "proc"
- , "net/netstat"
- , 4000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_ERRORS
, update_every
, RRDSET_TYPE_LINE
);
- rrdset_flag_set(st_ipv4_inerrors, RRDSET_FLAG_DETAIL);
+ rrdset_flag_set(st_ip_inerrors, RRDSET_FLAG_DETAIL);
- rd_noroutes = rrddim_add(st_ipv4_inerrors, "InNoRoutes", "noroutes", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_truncated = rrddim_add(st_ipv4_inerrors, "InTruncatedPkts", "truncated", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_checksum = rrddim_add(st_ipv4_inerrors, "InCsumErrors", "checksum", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_noroutes = rrddim_add(st_ip_inerrors, "InNoRoutes", "noroutes", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_truncated = rrddim_add(st_ip_inerrors, "InTruncatedPkts", "truncated", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_checksum = rrddim_add(st_ip_inerrors, "InCsumErrors", "checksum", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
- rrdset_next(st_ipv4_inerrors);
+ rrdset_next(st_ip_inerrors);
- rrddim_set_by_pointer(st_ipv4_inerrors, rd_noroutes, ipext_InNoRoutes);
- rrddim_set_by_pointer(st_ipv4_inerrors, rd_truncated, ipext_InTruncatedPkts);
- rrddim_set_by_pointer(st_ipv4_inerrors, rd_checksum, ipext_InCsumErrors);
+ rrddim_set_by_pointer(st_ip_inerrors, rd_noroutes, ipext_InNoRoutes);
+ rrddim_set_by_pointer(st_ip_inerrors, rd_truncated, ipext_InTruncatedPkts);
+ rrddim_set_by_pointer(st_ip_inerrors, rd_checksum, ipext_InCsumErrors);
- rrdset_done(st_ipv4_inerrors);
+ rrdset_done(st_ip_inerrors);
}
// --------------------------------------------------------------------
if(do_mcast == CONFIG_BOOLEAN_YES || (do_mcast == CONFIG_BOOLEAN_AUTO && (ipext_InMcastOctets || ipext_OutMcastOctets))) {
do_mcast = CONFIG_BOOLEAN_YES;
- static RRDSET *st_ipv4_mcast = NULL;
+ static RRDSET *st_ip_mcast = NULL;
static RRDDIM *rd_in = NULL, *rd_out = NULL;
- if(unlikely(!st_ipv4_mcast)) {
- st_ipv4_mcast = rrdset_create_localhost(
- "ipv4"
+ if(unlikely(!st_ip_mcast)) {
+ st_ip_mcast = rrdset_create_localhost(
+ RRD_TYPE_NET_NETSTAT
, "mcast"
, NULL
, "multicast"
, NULL
- , "IPv4 Multicast Bandwidth"
+ , "IP Multicast Bandwidth"
, "kilobits/s"
- , "proc"
- , "net/netstat"
- , 9000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_MCAST
, update_every
, RRDSET_TYPE_AREA
);
- rrdset_flag_set(st_ipv4_mcast, RRDSET_FLAG_DETAIL);
+ rrdset_flag_set(st_ip_mcast, RRDSET_FLAG_DETAIL);
- rd_in = rrddim_add(st_ipv4_mcast, "InMcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
- rd_out = rrddim_add(st_ipv4_mcast, "OutMcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_in = rrddim_add(st_ip_mcast, "InMcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_ip_mcast, "OutMcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
else
- rrdset_next(st_ipv4_mcast);
+ rrdset_next(st_ip_mcast);
- rrddim_set_by_pointer(st_ipv4_mcast, rd_in, ipext_InMcastOctets);
- rrddim_set_by_pointer(st_ipv4_mcast, rd_out, ipext_OutMcastOctets);
+ rrddim_set_by_pointer(st_ip_mcast, rd_in, ipext_InMcastOctets);
+ rrddim_set_by_pointer(st_ip_mcast, rd_out, ipext_OutMcastOctets);
- rrdset_done(st_ipv4_mcast);
+ rrdset_done(st_ip_mcast);
}
// --------------------------------------------------------------------
@@ -360,37 +376,37 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(do_bcast == CONFIG_BOOLEAN_YES || (do_bcast == CONFIG_BOOLEAN_AUTO && (ipext_InBcastOctets || ipext_OutBcastOctets))) {
do_bcast = CONFIG_BOOLEAN_YES;
- static RRDSET *st_ipv4_bcast = NULL;
+ static RRDSET *st_ip_bcast = NULL;
static RRDDIM *rd_in = NULL, *rd_out = NULL;
- if(unlikely(!st_ipv4_bcast)) {
- st_ipv4_bcast = rrdset_create_localhost(
- "ipv4"
+ if(unlikely(!st_ip_bcast)) {
+ st_ip_bcast = rrdset_create_localhost(
+ RRD_TYPE_NET_NETSTAT
, "bcast"
, NULL
, "broadcast"
, NULL
- , "IPv4 Broadcast Bandwidth"
+ , "IP Broadcast Bandwidth"
, "kilobits/s"
- , "proc"
- , "net/netstat"
- , 8000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_BCAST
, update_every
, RRDSET_TYPE_AREA
);
- rrdset_flag_set(st_ipv4_bcast, RRDSET_FLAG_DETAIL);
+ rrdset_flag_set(st_ip_bcast, RRDSET_FLAG_DETAIL);
- rd_in = rrddim_add(st_ipv4_bcast, "InBcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
- rd_out = rrddim_add(st_ipv4_bcast, "OutBcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_in = rrddim_add(st_ip_bcast, "InBcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_ip_bcast, "OutBcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
else
- rrdset_next(st_ipv4_bcast);
+ rrdset_next(st_ip_bcast);
- rrddim_set_by_pointer(st_ipv4_bcast, rd_in, ipext_InBcastOctets);
- rrddim_set_by_pointer(st_ipv4_bcast, rd_out, ipext_OutBcastOctets);
+ rrddim_set_by_pointer(st_ip_bcast, rd_in, ipext_InBcastOctets);
+ rrddim_set_by_pointer(st_ip_bcast, rd_out, ipext_OutBcastOctets);
- rrdset_done(st_ipv4_bcast);
+ rrdset_done(st_ip_bcast);
}
// --------------------------------------------------------------------
@@ -398,36 +414,36 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(do_mcast_p == CONFIG_BOOLEAN_YES || (do_mcast_p == CONFIG_BOOLEAN_AUTO && (ipext_InMcastPkts || ipext_OutMcastPkts))) {
do_mcast_p = CONFIG_BOOLEAN_YES;
- static RRDSET *st_ipv4_mcastpkts = NULL;
+ static RRDSET *st_ip_mcastpkts = NULL;
static RRDDIM *rd_in = NULL, *rd_out = NULL;
- if(unlikely(!st_ipv4_mcastpkts)) {
- st_ipv4_mcastpkts = rrdset_create_localhost(
- "ipv4"
+ if(unlikely(!st_ip_mcastpkts)) {
+ st_ip_mcastpkts = rrdset_create_localhost(
+ RRD_TYPE_NET_NETSTAT
, "mcastpkts"
, NULL
, "multicast"
, NULL
- , "IPv4 Multicast Packets"
+ , "IP Multicast Packets"
, "packets/s"
- , "proc"
- , "net/netstat"
- , 8600
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_MCAST_PACKETS
, update_every
, RRDSET_TYPE_LINE
);
- rrdset_flag_set(st_ipv4_mcastpkts, RRDSET_FLAG_DETAIL);
+ rrdset_flag_set(st_ip_mcastpkts, RRDSET_FLAG_DETAIL);
- rd_in = rrddim_add(st_ipv4_mcastpkts, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_out = rrddim_add(st_ipv4_mcastpkts, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in = rrddim_add(st_ip_mcastpkts, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_ip_mcastpkts, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st_ipv4_mcastpkts);
+ else rrdset_next(st_ip_mcastpkts);
- rrddim_set_by_pointer(st_ipv4_mcastpkts, rd_in, ipext_InMcastPkts);
- rrddim_set_by_pointer(st_ipv4_mcastpkts, rd_out, ipext_OutMcastPkts);
+ rrddim_set_by_pointer(st_ip_mcastpkts, rd_in, ipext_InMcastPkts);
+ rrddim_set_by_pointer(st_ip_mcastpkts, rd_out, ipext_OutMcastPkts);
- rrdset_done(st_ipv4_mcastpkts);
+ rrdset_done(st_ip_mcastpkts);
}
// --------------------------------------------------------------------
@@ -435,37 +451,37 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(do_bcast_p == CONFIG_BOOLEAN_YES || (do_bcast_p == CONFIG_BOOLEAN_AUTO && (ipext_InBcastPkts || ipext_OutBcastPkts))) {
do_bcast_p = CONFIG_BOOLEAN_YES;
- static RRDSET *st_ipv4_bcastpkts = NULL;
+ static RRDSET *st_ip_bcastpkts = NULL;
static RRDDIM *rd_in = NULL, *rd_out = NULL;
- if(unlikely(!st_ipv4_bcastpkts)) {
- st_ipv4_bcastpkts = rrdset_create_localhost(
- "ipv4"
+ if(unlikely(!st_ip_bcastpkts)) {
+ st_ip_bcastpkts = rrdset_create_localhost(
+ RRD_TYPE_NET_NETSTAT
, "bcastpkts"
, NULL
, "broadcast"
, NULL
- , "IPv4 Broadcast Packets"
+ , "IP Broadcast Packets"
, "packets/s"
- , "proc"
- , "net/netstat"
- , 8500
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_BCAST_PACKETS
, update_every
, RRDSET_TYPE_LINE
);
- rrdset_flag_set(st_ipv4_bcastpkts, RRDSET_FLAG_DETAIL);
+ rrdset_flag_set(st_ip_bcastpkts, RRDSET_FLAG_DETAIL);
- rd_in = rrddim_add(st_ipv4_bcastpkts, "InBcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_out = rrddim_add(st_ipv4_bcastpkts, "OutBcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in = rrddim_add(st_ip_bcastpkts, "InBcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_ip_bcastpkts, "OutBcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
- rrdset_next(st_ipv4_bcastpkts);
+ rrdset_next(st_ip_bcastpkts);
- rrddim_set_by_pointer(st_ipv4_bcastpkts, rd_in, ipext_InBcastPkts);
- rrddim_set_by_pointer(st_ipv4_bcastpkts, rd_out, ipext_OutBcastPkts);
+ rrddim_set_by_pointer(st_ip_bcastpkts, rd_in, ipext_InBcastPkts);
+ rrddim_set_by_pointer(st_ip_bcastpkts, rd_out, ipext_OutBcastPkts);
- rrdset_done(st_ipv4_bcastpkts);
+ rrdset_done(st_ip_bcastpkts);
}
// --------------------------------------------------------------------
@@ -478,16 +494,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(unlikely(!st_ecnpkts)) {
st_ecnpkts = rrdset_create_localhost(
- "ipv4"
+ RRD_TYPE_NET_NETSTAT
, "ecnpkts"
, NULL
, "ecn"
, NULL
- , "IPv4 ECN Statistics"
+ , "IP ECN Statistics"
, "packets/s"
- , "proc"
- , "net/netstat"
- , 8700
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_ECN
, update_every
, RRDSET_TYPE_LINE
);
@@ -530,16 +546,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(unlikely(!st_tcpmemorypressures)) {
st_tcpmemorypressures = rrdset_create_localhost(
- "ipv4"
+ RRD_TYPE_NET_NETSTAT
, "tcpmemorypressures"
, NULL
, "tcp"
, NULL
, "TCP Memory Pressures"
, "events/s"
- , "proc"
- , "net/netstat"
- , 3000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_TCP_MEM
, update_every
, RRDSET_TYPE_LINE
);
@@ -564,16 +580,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(unlikely(!st_tcpconnaborts)) {
st_tcpconnaborts = rrdset_create_localhost(
- "ipv4"
+ RRD_TYPE_NET_NETSTAT
, "tcpconnaborts"
, NULL
, "tcp"
, NULL
, "TCP Connection Aborts"
, "connections/s"
- , "proc"
- , "net/netstat"
- , 3010
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_TCP_CONNABORTS
, update_every
, RRDSET_TYPE_LINE
);
@@ -608,16 +624,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(unlikely(!st_tcpreorders)) {
st_tcpreorders = rrdset_create_localhost(
- "ipv4"
+ RRD_TYPE_NET_NETSTAT
, "tcpreorders"
, NULL
, "tcp"
, NULL
, "TCP Reordered Packets by Detection Method"
, "packets/s"
- , "proc"
- , "net/netstat"
- , 3020
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_TCP_REORDERS
, update_every
, RRDSET_TYPE_LINE
);
@@ -643,40 +659,40 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(do_tcpext_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && (tcpext_TCPOFOQueue || tcpext_TCPOFODrop || tcpext_TCPOFOMerge))) {
do_tcpext_ofo = CONFIG_BOOLEAN_YES;
- static RRDSET *st_ipv4_tcpofo = NULL;
+ static RRDSET *st_ip_tcpofo = NULL;
static RRDDIM *rd_inqueue = NULL, *rd_dropped = NULL, *rd_merged = NULL, *rd_pruned = NULL;
- if(unlikely(!st_ipv4_tcpofo)) {
+ if(unlikely(!st_ip_tcpofo)) {
- st_ipv4_tcpofo = rrdset_create_localhost(
- "ipv4"
+ st_ip_tcpofo = rrdset_create_localhost(
+ RRD_TYPE_NET_NETSTAT
, "tcpofo"
, NULL
, "tcp"
, NULL
, "TCP Out-Of-Order Queue"
, "packets/s"
- , "proc"
- , "net/netstat"
- , 3050
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_TCP_OFO
, update_every
, RRDSET_TYPE_LINE
);
- rd_inqueue = rrddim_add(st_ipv4_tcpofo, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_dropped = rrddim_add(st_ipv4_tcpofo, "TCPOFODrop", "dropped", -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_merged = rrddim_add(st_ipv4_tcpofo, "TCPOFOMerge", "merged", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_pruned = rrddim_add(st_ipv4_tcpofo, "OfoPruned", "pruned", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_inqueue = rrddim_add(st_ip_tcpofo, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_dropped = rrddim_add(st_ip_tcpofo, "TCPOFODrop", "dropped", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_merged = rrddim_add(st_ip_tcpofo, "TCPOFOMerge", "merged", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_pruned = rrddim_add(st_ip_tcpofo, "OfoPruned", "pruned", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
- rrdset_next(st_ipv4_tcpofo);
+ rrdset_next(st_ip_tcpofo);
- rrddim_set_by_pointer(st_ipv4_tcpofo, rd_inqueue, tcpext_TCPOFOQueue);
- rrddim_set_by_pointer(st_ipv4_tcpofo, rd_dropped, tcpext_TCPOFODrop);
- rrddim_set_by_pointer(st_ipv4_tcpofo, rd_merged, tcpext_TCPOFOMerge);
- rrddim_set_by_pointer(st_ipv4_tcpofo, rd_pruned, tcpext_OfoPruned);
+ rrddim_set_by_pointer(st_ip_tcpofo, rd_inqueue, tcpext_TCPOFOQueue);
+ rrddim_set_by_pointer(st_ip_tcpofo, rd_dropped, tcpext_TCPOFODrop);
+ rrddim_set_by_pointer(st_ip_tcpofo, rd_merged, tcpext_TCPOFOMerge);
+ rrddim_set_by_pointer(st_ip_tcpofo, rd_pruned, tcpext_OfoPruned);
- rrdset_done(st_ipv4_tcpofo);
+ rrdset_done(st_ip_tcpofo);
}
// --------------------------------------------------------------------
@@ -690,16 +706,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
if(unlikely(!st_syncookies)) {
st_syncookies = rrdset_create_localhost(
- "ipv4"
+ RRD_TYPE_NET_NETSTAT
, "tcpsyncookies"
, NULL
, "tcp"
, NULL
, "TCP SYN Cookies"
, "packets/s"
- , "proc"
- , "net/netstat"
- , 3100
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_TCP_SYNCOOKIES
, update_every
, RRDSET_TYPE_LINE
);
@@ -720,40 +736,81 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcpext_listen == CONFIG_BOOLEAN_YES || (do_tcpext_listen == CONFIG_BOOLEAN_AUTO && (tcpext_ListenOverflows || tcpext_ListenDrops))) {
- do_tcpext_listen = CONFIG_BOOLEAN_YES;
+ if(do_tcpext_syn_queue == CONFIG_BOOLEAN_YES || (do_tcpext_syn_queue == CONFIG_BOOLEAN_AUTO && (tcpext_TCPReqQFullDrop || tcpext_TCPReqQFullDoCookies))) {
+ do_tcpext_syn_queue = CONFIG_BOOLEAN_YES;
- static RRDSET *st_listen = NULL;
- static RRDDIM *rd_overflows = NULL, *rd_drops = NULL;
+ static RRDSET *st_syn_queue = NULL;
+ static RRDDIM
+ *rd_TCPReqQFullDrop = NULL,
+ *rd_TCPReqQFullDoCookies = NULL;
- if(unlikely(!st_listen)) {
+ if(unlikely(!st_syn_queue)) {
- st_listen = rrdset_create_localhost(
- "ipv4"
- , "tcplistenissues"
+ st_syn_queue = rrdset_create_localhost(
+ RRD_TYPE_NET_NETSTAT
+ , "tcp_syn_queue"
, NULL
, "tcp"
, NULL
- , "TCP Listen Socket Issues"
+ , "TCP SYN Queue Issues"
, "packets/s"
- , "proc"
- , "net/netstat"
- , 3015
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_TCP_SYN_QUEUE
, update_every
, RRDSET_TYPE_LINE
);
- rd_overflows = rrddim_add(st_listen, "ListenOverflows", "overflows", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_drops = rrddim_add(st_listen, "ListenDrops", "drops", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_TCPReqQFullDrop = rrddim_add(st_syn_queue, "TCPReqQFullDrop", "drops", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_TCPReqQFullDoCookies = rrddim_add(st_syn_queue, "TCPReqQFullDoCookies", "cookies", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
- rrdset_next(st_listen);
+ rrdset_next(st_syn_queue);
- rrddim_set_by_pointer(st_listen, rd_overflows, tcpext_ListenOverflows);
- rrddim_set_by_pointer(st_listen, rd_drops, tcpext_ListenDrops);
+ rrddim_set_by_pointer(st_syn_queue, rd_TCPReqQFullDrop, tcpext_TCPReqQFullDrop);
+ rrddim_set_by_pointer(st_syn_queue, rd_TCPReqQFullDoCookies, tcpext_TCPReqQFullDoCookies);
- rrdset_done(st_listen);
+ rrdset_done(st_syn_queue);
}
+
+ // --------------------------------------------------------------------
+
+ if(do_tcpext_accept_queue == CONFIG_BOOLEAN_YES || (do_tcpext_accept_queue == CONFIG_BOOLEAN_AUTO && (tcpext_ListenOverflows || tcpext_ListenDrops))) {
+ do_tcpext_accept_queue = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st_accept_queue = NULL;
+ static RRDDIM *rd_overflows = NULL,
+ *rd_drops = NULL;
+
+ if(unlikely(!st_accept_queue)) {
+
+ st_accept_queue = rrdset_create_localhost(
+ RRD_TYPE_NET_NETSTAT
+ , "tcp_accept_queue"
+ , NULL
+ , "tcp"
+ , NULL
+ , "TCP Accept Queue Issues"
+ , "packets/s"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NETSTAT_NAME
+ , NETDATA_CHART_PRIO_IP_TCP_ACCEPT_QUEUE
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_overflows = rrddim_add(st_accept_queue, "ListenOverflows", "overflows", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_drops = rrddim_add(st_accept_queue, "ListenDrops", "drops", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else
+ rrdset_next(st_accept_queue);
+
+ rrddim_set_by_pointer(st_accept_queue, rd_overflows, tcpext_ListenOverflows);
+ rrddim_set_by_pointer(st_accept_queue, rd_drops, tcpext_ListenDrops);
+
+ rrdset_done(st_accept_queue);
+ }
+
}
}
diff --git a/src/proc_net_rpc_nfs.c b/collectors/proc.plugin/proc_net_rpc_nfs.c
index a4c778cba..f5702859c 100644
--- a/src/proc_net_rpc_nfs.c
+++ b/collectors/proc.plugin/proc_net_rpc_nfs.c
@@ -1,4 +1,9 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_NFS_NAME "/proc/net/rpc/nfs"
+#define CONFIG_SECTION_PLUGIN_PROC_NFS "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_NFS_NAME
struct nfs_procs {
char name[30];
@@ -143,18 +148,18 @@ 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", 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);
+ ff = procfile_open(config_get(CONFIG_SECTION_PLUGIN_PROC_NFS, "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(!ff) return 1;
ff = procfile_readall(ff);
if(!ff) return 0; // we return 0, so that we will retry to open it next time
- if(do_net == -1) do_net = config_get_boolean("plugin:proc:/proc/net/rpc/nfs", "network", 1);
- if(do_rpc == -1) do_rpc = config_get_boolean("plugin:proc:/proc/net/rpc/nfs", "rpc", 1);
- if(do_proc2 == -1) do_proc2 = config_get_boolean("plugin:proc:/proc/net/rpc/nfs", "NFS v2 procedures", 1);
- if(do_proc3 == -1) do_proc3 = config_get_boolean("plugin:proc:/proc/net/rpc/nfs", "NFS v3 procedures", 1);
- if(do_proc4 == -1) do_proc4 = config_get_boolean("plugin:proc:/proc/net/rpc/nfs", "NFS v4 procedures", 1);
+ if(do_net == -1) do_net = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_NFS, "network", 1);
+ if(do_rpc == -1) do_rpc = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_NFS, "rpc", 1);
+ if(do_proc2 == -1) do_proc2 = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_NFS, "NFS v2 procedures", 1);
+ if(do_proc3 == -1) do_proc3 = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_NFS, "NFS v3 procedures", 1);
+ if(do_proc4 == -1) do_proc4 = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_NFS, "NFS v4 procedures", 1);
// if they are enabled, reset them to 1
// later we do them =2 to avoid doing strcmp() for all lines
@@ -286,9 +291,9 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
, NULL
, "NFS Client Network"
, "operations/s"
- , "proc"
- , "net/rpc/nfs"
- , 2207
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFS_NAME
+ , NETDATA_CHART_PRIO_NFS_NET
, update_every
, RRDSET_TYPE_STACKED
);
@@ -326,9 +331,9 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
, NULL
, "NFS Client Remote Procedure Calls Statistics"
, "calls/s"
- , "proc"
- , "net/rpc/nfs"
- , 2208
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFS_NAME
+ , NETDATA_CHART_PRIO_NFS_RPC
, update_every
, RRDSET_TYPE_LINE
);
@@ -359,9 +364,9 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
, NULL
, "NFS v2 Client Remote Procedure Calls"
, "calls/s"
- , "proc"
- , "net/rpc/nfs"
- , 2209
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFS_NAME
+ , NETDATA_CHART_PRIO_NFS_PROC2
, update_every
, RRDSET_TYPE_STACKED
);
@@ -392,9 +397,9 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
, NULL
, "NFS v3 Client Remote Procedure Calls"
, "calls/s"
- , "proc"
- , "net/rpc/nfs"
- , 2210
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFS_NAME
+ , NETDATA_CHART_PRIO_NFS_PROC3
, update_every
, RRDSET_TYPE_STACKED
);
@@ -425,9 +430,9 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
, NULL
, "NFS v4 Client Remote Procedure Calls"
, "calls/s"
- , "proc"
- , "net/rpc/nfs"
- , 2211
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFS_NAME
+ , NETDATA_CHART_PRIO_NFS_PROC4
, update_every
, RRDSET_TYPE_STACKED
);
diff --git a/src/proc_net_rpc_nfsd.c b/collectors/proc.plugin/proc_net_rpc_nfsd.c
index 8aca31aed..20b87e9dd 100644
--- a/src/proc_net_rpc_nfsd.c
+++ b/collectors/proc.plugin/proc_net_rpc_nfsd.c
@@ -1,4 +1,8 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_NFSD_NAME "/proc/net/rpc/nfsd"
struct nfsd_procs {
char name[30];
@@ -515,9 +519,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS Server Read Cache"
, "reads/s"
- , "proc"
- , "net/rpc/nfsd"
- , 2100
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_READCACHE
, update_every
, RRDSET_TYPE_STACKED
);
@@ -553,9 +557,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS Server File Handles"
, "handles/s"
- , "proc"
- , "net/rpc/nfsd"
- , 2101
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_FILEHANDLES
, update_every
, RRDSET_TYPE_LINE
);
@@ -593,9 +597,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS Server I/O"
, "kilobytes/s"
- , "proc"
- , "net/rpc/nfsd"
- , 2102
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_IO
, update_every
, RRDSET_TYPE_AREA
);
@@ -626,9 +630,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS Server Threads"
, "threads"
- , "proc"
- , "net/rpc/nfsd"
- , 2103
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_THREADS
, update_every
, RRDSET_TYPE_LINE
);
@@ -654,9 +658,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS Server Threads Full Count"
, "ops/s"
- , "proc"
- , "net/rpc/nfsd"
- , 2104
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_THREADS_FULLCNT
, update_every
, RRDSET_TYPE_LINE
);
@@ -691,9 +695,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS Server Threads Usage Histogram"
, "percentage"
- , "proc"
- , "net/rpc/nfsd"
- , 2105
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_THREADS_HISTOGRAM
, update_every
, RRDSET_TYPE_LINE
);
@@ -750,9 +754,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS Server Read Ahead Depth"
, "percentage"
- , "proc"
- , "net/rpc/nfsd"
- , 2105
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_READAHEAD
, update_every
, RRDSET_TYPE_STACKED
);
@@ -804,9 +808,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS Server Network Statistics"
, "packets/s"
- , "proc"
- , "net/rpc/nfsd"
- , 2107
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_NET
, update_every
, RRDSET_TYPE_STACKED
);
@@ -843,9 +847,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS Server Remote Procedure Calls Statistics"
, "calls/s"
- , "proc"
- , "net/rpc/nfsd"
- , 2108
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_RPC
, update_every
, RRDSET_TYPE_LINE
);
@@ -879,9 +883,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS v2 Server Remote Procedure Calls"
, "calls/s"
- , "proc"
- , "net/rpc/nfsd"
- , 2109
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_PROC2
, update_every
, RRDSET_TYPE_STACKED
);
@@ -912,9 +916,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS v3 Server Remote Procedure Calls"
, "calls/s"
- , "proc"
- , "net/rpc/nfsd"
- , 2110
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_PROC3
, update_every
, RRDSET_TYPE_STACKED
);
@@ -945,9 +949,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS v4 Server Remote Procedure Calls"
, "calls/s"
- , "proc"
- , "net/rpc/nfsd"
- , 2111
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_PROC4
, update_every
, RRDSET_TYPE_STACKED
);
@@ -978,9 +982,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
, NULL
, "NFS v4 Server Operations"
, "operations/s"
- , "proc"
- , "net/rpc/nfsd"
- , 2112
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NFSD_NAME
+ , NETDATA_CHART_PRIO_NFSD_PROC4OPS
, update_every
, RRDSET_TYPE_STACKED
);
diff --git a/collectors/proc.plugin/proc_net_sctp_snmp.c b/collectors/proc.plugin/proc_net_sctp_snmp.c
new file mode 100644
index 000000000..bd1062e98
--- /dev/null
+++ b/collectors/proc.plugin/proc_net_sctp_snmp.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+#define PLUGIN_PROC_MODULE_NET_SCTP_SNMP_NAME "/proc/net/sctp/snmp"
+
+int do_proc_net_sctp_snmp(int update_every, usec_t dt) {
+ (void)dt;
+
+ static procfile *ff = NULL;
+
+ static int
+ do_associations = -1,
+ do_transitions = -1,
+ do_packet_errors = -1,
+ do_packets = -1,
+ do_fragmentation = -1,
+ do_chunk_types = -1;
+
+ static ARL_BASE *arl_base = NULL;
+
+ static unsigned long long SctpCurrEstab = 0ULL;
+ static unsigned long long SctpActiveEstabs = 0ULL;
+ static unsigned long long SctpPassiveEstabs = 0ULL;
+ static unsigned long long SctpAborteds = 0ULL;
+ static unsigned long long SctpShutdowns = 0ULL;
+ static unsigned long long SctpOutOfBlues = 0ULL;
+ static unsigned long long SctpChecksumErrors = 0ULL;
+ static unsigned long long SctpOutCtrlChunks = 0ULL;
+ static unsigned long long SctpOutOrderChunks = 0ULL;
+ static unsigned long long SctpOutUnorderChunks = 0ULL;
+ static unsigned long long SctpInCtrlChunks = 0ULL;
+ static unsigned long long SctpInOrderChunks = 0ULL;
+ static unsigned long long SctpInUnorderChunks = 0ULL;
+ static unsigned long long SctpFragUsrMsgs = 0ULL;
+ static unsigned long long SctpReasmUsrMsgs = 0ULL;
+ static unsigned long long SctpOutSCTPPacks = 0ULL;
+ static unsigned long long SctpInSCTPPacks = 0ULL;
+ static unsigned long long SctpT1InitExpireds = 0ULL;
+ static unsigned long long SctpT1CookieExpireds = 0ULL;
+ static unsigned long long SctpT2ShutdownExpireds = 0ULL;
+ static unsigned long long SctpT3RtxExpireds = 0ULL;
+ static unsigned long long SctpT4RtoExpireds = 0ULL;
+ static unsigned long long SctpT5ShutdownGuardExpireds = 0ULL;
+ static unsigned long long SctpDelaySackExpireds = 0ULL;
+ static unsigned long long SctpAutocloseExpireds = 0ULL;
+ static unsigned long long SctpT3Retransmits = 0ULL;
+ static unsigned long long SctpPmtudRetransmits = 0ULL;
+ static unsigned long long SctpFastRetransmits = 0ULL;
+ static unsigned long long SctpInPktSoftirq = 0ULL;
+ static unsigned long long SctpInPktBacklog = 0ULL;
+ static unsigned long long SctpInPktDiscards = 0ULL;
+ static unsigned long long SctpInDataChunkDiscards = 0ULL;
+
+ if(unlikely(!arl_base)) {
+ do_associations = config_get_boolean_ondemand("plugin:proc:/proc/net/sctp/snmp", "established associations", CONFIG_BOOLEAN_AUTO);
+ do_transitions = config_get_boolean_ondemand("plugin:proc:/proc/net/sctp/snmp", "association transitions", CONFIG_BOOLEAN_AUTO);
+ do_fragmentation = config_get_boolean_ondemand("plugin:proc:/proc/net/sctp/snmp", "fragmentation", CONFIG_BOOLEAN_AUTO);
+ do_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/sctp/snmp", "packets", CONFIG_BOOLEAN_AUTO);
+ do_packet_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/sctp/snmp", "packet errors", CONFIG_BOOLEAN_AUTO);
+ do_chunk_types = config_get_boolean_ondemand("plugin:proc:/proc/net/sctp/snmp", "chunk types", CONFIG_BOOLEAN_AUTO);
+
+ arl_base = arl_create("sctp", NULL, 60);
+ arl_expect(arl_base, "SctpCurrEstab", &SctpCurrEstab);
+ arl_expect(arl_base, "SctpActiveEstabs", &SctpActiveEstabs);
+ arl_expect(arl_base, "SctpPassiveEstabs", &SctpPassiveEstabs);
+ arl_expect(arl_base, "SctpAborteds", &SctpAborteds);
+ arl_expect(arl_base, "SctpShutdowns", &SctpShutdowns);
+ arl_expect(arl_base, "SctpOutOfBlues", &SctpOutOfBlues);
+ arl_expect(arl_base, "SctpChecksumErrors", &SctpChecksumErrors);
+ arl_expect(arl_base, "SctpOutCtrlChunks", &SctpOutCtrlChunks);
+ arl_expect(arl_base, "SctpOutOrderChunks", &SctpOutOrderChunks);
+ arl_expect(arl_base, "SctpOutUnorderChunks", &SctpOutUnorderChunks);
+ arl_expect(arl_base, "SctpInCtrlChunks", &SctpInCtrlChunks);
+ arl_expect(arl_base, "SctpInOrderChunks", &SctpInOrderChunks);
+ arl_expect(arl_base, "SctpInUnorderChunks", &SctpInUnorderChunks);
+ arl_expect(arl_base, "SctpFragUsrMsgs", &SctpFragUsrMsgs);
+ arl_expect(arl_base, "SctpReasmUsrMsgs", &SctpReasmUsrMsgs);
+ arl_expect(arl_base, "SctpOutSCTPPacks", &SctpOutSCTPPacks);
+ arl_expect(arl_base, "SctpInSCTPPacks", &SctpInSCTPPacks);
+ arl_expect(arl_base, "SctpT1InitExpireds", &SctpT1InitExpireds);
+ arl_expect(arl_base, "SctpT1CookieExpireds", &SctpT1CookieExpireds);
+ arl_expect(arl_base, "SctpT2ShutdownExpireds", &SctpT2ShutdownExpireds);
+ arl_expect(arl_base, "SctpT3RtxExpireds", &SctpT3RtxExpireds);
+ arl_expect(arl_base, "SctpT4RtoExpireds", &SctpT4RtoExpireds);
+ arl_expect(arl_base, "SctpT5ShutdownGuardExpireds", &SctpT5ShutdownGuardExpireds);
+ arl_expect(arl_base, "SctpDelaySackExpireds", &SctpDelaySackExpireds);
+ arl_expect(arl_base, "SctpAutocloseExpireds", &SctpAutocloseExpireds);
+ arl_expect(arl_base, "SctpT3Retransmits", &SctpT3Retransmits);
+ arl_expect(arl_base, "SctpPmtudRetransmits", &SctpPmtudRetransmits);
+ arl_expect(arl_base, "SctpFastRetransmits", &SctpFastRetransmits);
+ arl_expect(arl_base, "SctpInPktSoftirq", &SctpInPktSoftirq);
+ arl_expect(arl_base, "SctpInPktBacklog", &SctpInPktBacklog);
+ arl_expect(arl_base, "SctpInPktDiscards", &SctpInPktDiscards);
+ arl_expect(arl_base, "SctpInDataChunkDiscards", &SctpInDataChunkDiscards);
+ }
+
+ if(unlikely(!ff)) {
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/sctp/snmp");
+ ff = procfile_open(config_get("plugin:proc:/proc/net/sctp/snmp", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
+ if(unlikely(!ff))
+ return 1;
+ }
+
+ ff = procfile_readall(ff);
+ if(unlikely(!ff))
+ return 0; // we return 0, so that we will retry to open it next time
+
+ size_t lines = procfile_lines(ff), l;
+
+ arl_begin(arl_base);
+
+ for(l = 0; l < lines ;l++) {
+ size_t words = procfile_linewords(ff, l);
+ if(unlikely(words < 2)) {
+ if(unlikely(words)) error("Cannot read /proc/net/sctp/snmp line %zu. Expected 2 params, read %zu.", l, words);
+ continue;
+ }
+
+ if(unlikely(arl_check(arl_base,
+ procfile_lineword(ff, l, 0),
+ procfile_lineword(ff, l, 1)))) break;
+ }
+
+ // --------------------------------------------------------------------
+
+ if(do_associations == CONFIG_BOOLEAN_YES || (do_associations == CONFIG_BOOLEAN_AUTO && SctpCurrEstab)) {
+ do_associations = CONFIG_BOOLEAN_YES;
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_established = NULL;
+
+ if(unlikely(!st)) {
+ st = rrdset_create_localhost(
+ "sctp"
+ , "established"
+ , NULL
+ , "associations"
+ , NULL
+ , "SCTP current total number of established associations"
+ , "associations"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SCTP_SNMP_NAME
+ , NETDATA_CHART_PRIO_SCTP
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_established = rrddim_add(st, "SctpCurrEstab", "established", 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_established, SctpCurrEstab);
+ rrdset_done(st);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(do_transitions == CONFIG_BOOLEAN_YES || (do_transitions == CONFIG_BOOLEAN_AUTO && (SctpActiveEstabs || SctpPassiveEstabs || SctpAborteds || SctpShutdowns))) {
+ do_transitions = CONFIG_BOOLEAN_YES;
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_active = NULL,
+ *rd_passive = NULL,
+ *rd_aborted = NULL,
+ *rd_shutdown = NULL;
+
+ if(unlikely(!st)) {
+ st = rrdset_create_localhost(
+ "sctp"
+ , "transitions"
+ , NULL
+ , "transitions"
+ , NULL
+ , "SCTP Association Transitions"
+ , "transitions/s"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SCTP_SNMP_NAME
+ , NETDATA_CHART_PRIO_SCTP + 10
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_active = rrddim_add(st, "SctpActiveEstabs", "active", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_passive = rrddim_add(st, "SctpPassiveEstabs", "passive", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_aborted = rrddim_add(st, "SctpAborteds", "aborted", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_shutdown = rrddim_add(st, "SctpShutdowns", "shutdown", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_active, SctpActiveEstabs);
+ rrddim_set_by_pointer(st, rd_passive, SctpPassiveEstabs);
+ rrddim_set_by_pointer(st, rd_aborted, SctpAborteds);
+ rrddim_set_by_pointer(st, rd_shutdown, SctpShutdowns);
+ rrdset_done(st);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(do_packets == CONFIG_BOOLEAN_YES || (do_packets == CONFIG_BOOLEAN_AUTO && (SctpInSCTPPacks || SctpOutSCTPPacks))) {
+ do_packets = CONFIG_BOOLEAN_YES;
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_received = NULL,
+ *rd_sent = NULL;
+
+ if(unlikely(!st)) {
+ st = rrdset_create_localhost(
+ "sctp"
+ , "packets"
+ , NULL
+ , "packets"
+ , NULL
+ , "SCTP Packets"
+ , "packets/s"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SCTP_SNMP_NAME
+ , NETDATA_CHART_PRIO_SCTP + 20
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_received = rrddim_add(st, "SctpInSCTPPacks", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_sent = rrddim_add(st, "SctpOutSCTPPacks", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_received, SctpInSCTPPacks);
+ rrddim_set_by_pointer(st, rd_sent, SctpOutSCTPPacks);
+ rrdset_done(st);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(do_packet_errors == CONFIG_BOOLEAN_YES || (do_packet_errors == CONFIG_BOOLEAN_AUTO && (SctpOutOfBlues || SctpChecksumErrors))) {
+ do_packet_errors = CONFIG_BOOLEAN_YES;
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_invalid = NULL,
+ *rd_csum = NULL;
+
+ if(unlikely(!st)) {
+ st = rrdset_create_localhost(
+ "sctp"
+ , "packet_errors"
+ , NULL
+ , "packets"
+ , NULL
+ , "SCTP Packet Errors"
+ , "packets/s"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SCTP_SNMP_NAME
+ , NETDATA_CHART_PRIO_SCTP + 30
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_invalid = rrddim_add(st, "SctpOutOfBlues", "invalid", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_csum = rrddim_add(st, "SctpChecksumErrors", "checksum", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_invalid, SctpOutOfBlues);
+ rrddim_set_by_pointer(st, rd_csum, SctpChecksumErrors);
+ rrdset_done(st);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(do_fragmentation == CONFIG_BOOLEAN_YES || (do_fragmentation == CONFIG_BOOLEAN_AUTO && (SctpFragUsrMsgs || SctpReasmUsrMsgs))) {
+ do_fragmentation = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_fragmented = NULL,
+ *rd_reassembled = NULL;
+
+ if(unlikely(!st)) {
+ st = rrdset_create_localhost(
+ "sctp"
+ , "fragmentation"
+ , NULL
+ , "fragmentation"
+ , NULL
+ , "SCTP Fragmentation"
+ , "packets/s"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SCTP_SNMP_NAME
+ , NETDATA_CHART_PRIO_SCTP + 40
+ , update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_reassembled = rrddim_add(st, "SctpReasmUsrMsgs", "reassembled", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_fragmented = rrddim_add(st, "SctpFragUsrMsgs", "fragmented", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_reassembled, SctpReasmUsrMsgs);
+ rrddim_set_by_pointer(st, rd_fragmented, SctpFragUsrMsgs);
+ rrdset_done(st);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(do_chunk_types == CONFIG_BOOLEAN_YES || (do_chunk_types == CONFIG_BOOLEAN_AUTO
+ && (SctpInCtrlChunks || SctpInOrderChunks || SctpInUnorderChunks || SctpOutCtrlChunks || SctpOutOrderChunks || SctpOutUnorderChunks))) {
+ do_chunk_types = CONFIG_BOOLEAN_YES;
+ static RRDSET *st = NULL;
+ static RRDDIM
+ *rd_InCtrl = NULL,
+ *rd_InOrder = NULL,
+ *rd_InUnorder = NULL,
+ *rd_OutCtrl = NULL,
+ *rd_OutOrder = NULL,
+ *rd_OutUnorder = NULL;
+
+ if(unlikely(!st)) {
+ st = rrdset_create_localhost(
+ "sctp"
+ , "chunks"
+ , NULL
+ , "chunks"
+ , NULL
+ , "SCTP Chunk Types"
+ , "chunks/s"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SCTP_SNMP_NAME
+ , NETDATA_CHART_PRIO_SCTP + 50
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_InCtrl = rrddim_add(st, "SctpInCtrlChunks", "InCtrl", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_InOrder = rrddim_add(st, "SctpInOrderChunks", "InOrder", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_InUnorder = rrddim_add(st, "SctpInUnorderChunks", "InUnorder", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_OutCtrl = rrddim_add(st, "SctpOutCtrlChunks", "OutCtrl", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_OutOrder = rrddim_add(st, "SctpOutOrderChunks", "OutOrder", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_OutUnorder = rrddim_add(st, "SctpOutUnorderChunks", "OutUnorder", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_InCtrl, SctpInCtrlChunks);
+ rrddim_set_by_pointer(st, rd_InOrder, SctpInOrderChunks);
+ rrddim_set_by_pointer(st, rd_InUnorder, SctpInUnorderChunks);
+ rrddim_set_by_pointer(st, rd_OutCtrl, SctpOutCtrlChunks);
+ rrddim_set_by_pointer(st, rd_OutOrder, SctpOutOrderChunks);
+ rrddim_set_by_pointer(st, rd_OutUnorder, SctpOutUnorderChunks);
+ rrdset_done(st);
+ }
+
+ return 0;
+}
+
diff --git a/src/proc_net_snmp.c b/collectors/proc.plugin/proc_net_snmp.c
index 43c010c14..ffd368f6e 100644
--- a/src/proc_net_snmp.c
+++ b/collectors/proc.plugin/proc_net_snmp.c
@@ -1,6 +1,9 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
-#define RRD_TYPE_NET_SNMP "ipv4"
+#include "plugin_proc.h"
+#define PLUGIN_PROC_MODULE_NET_SNMP_NAME "/proc/net/snmp"
+
+#define RRD_TYPE_NET_SNMP "ipv4"
static struct proc_net_snmp {
// kernel_uint_t ip_Forwarding;
@@ -102,23 +105,22 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
*arl_udplite = NULL;
static RRDVAR *tcp_max_connections_var = NULL;
- static ssize_t last_max_connections = 0;
if(unlikely(!arl_ip)) {
- do_ip_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 packets", 1);
- do_ip_fragsout = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments sent", 1);
- do_ip_fragsin = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments assembly", 1);
- do_ip_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 errors", 1);
- do_tcp_sockets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP connections", 1);
- do_tcp_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP packets", 1);
- do_tcp_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP errors", 1);
- do_tcp_opens = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP opens", 1);
- do_tcp_handshake = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP handshake issues", 1);
- do_udp_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP packets", 1);
- do_udp_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP errors", 1);
- do_icmp_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 ICMP packets", 1);
- do_icmpmsg = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 ICMP messages", 1);
- do_udplite_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDPLite packets", 1);
+ do_ip_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 packets", CONFIG_BOOLEAN_AUTO);
+ do_ip_fragsout = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 fragments sent", CONFIG_BOOLEAN_AUTO);
+ do_ip_fragsin = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 fragments assembly", CONFIG_BOOLEAN_AUTO);
+ do_ip_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 errors", CONFIG_BOOLEAN_AUTO);
+ do_tcp_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 TCP connections", CONFIG_BOOLEAN_AUTO);
+ do_tcp_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 TCP packets", CONFIG_BOOLEAN_AUTO);
+ do_tcp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 TCP errors", CONFIG_BOOLEAN_AUTO);
+ do_tcp_opens = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 TCP opens", CONFIG_BOOLEAN_AUTO);
+ do_tcp_handshake = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 TCP handshake issues", CONFIG_BOOLEAN_AUTO);
+ do_udp_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 UDP packets", CONFIG_BOOLEAN_AUTO);
+ do_udp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 UDP errors", CONFIG_BOOLEAN_AUTO);
+ do_icmp_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 ICMP packets", CONFIG_BOOLEAN_AUTO);
+ do_icmpmsg = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 ICMP messages", CONFIG_BOOLEAN_AUTO);
+ do_udplite_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp", "ipv4 UDPLite packets", CONFIG_BOOLEAN_AUTO);
hash_ip = simple_hash("Ip");
hash_tcp = simple_hash("Tcp");
@@ -181,7 +183,7 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// arl_expect(arl_tcp, "RtoAlgorithm", &snmp_root.tcp_RtoAlgorithm);
// arl_expect(arl_tcp, "RtoMin", &snmp_root.tcp_RtoMin);
// arl_expect(arl_tcp, "RtoMax", &snmp_root.tcp_RtoMax);
- arl_expect(arl_tcp, "MaxConn", &snmp_root.tcp_MaxConn);
+ arl_expect_custom(arl_tcp, "MaxConn", arl_callback_ssize_t, &snmp_root.tcp_MaxConn);
arl_expect(arl_tcp, "ActiveOpens", &snmp_root.tcp_ActiveOpens);
arl_expect(arl_tcp, "PassiveOpens", &snmp_root.tcp_PassiveOpens);
arl_expect(arl_tcp, "AttemptFails", &snmp_root.tcp_AttemptFails);
@@ -256,7 +258,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_packets) {
+ if(do_ip_packets == CONFIG_BOOLEAN_YES || (do_ip_packets == CONFIG_BOOLEAN_AUTO && (snmp_root.ip_OutRequests || snmp_root.ip_InReceives || snmp_root.ip_ForwDatagrams || snmp_root.ip_InDelivers))) {
+ do_ip_packets = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_InReceives = NULL,
*rd_OutRequests = NULL,
@@ -272,9 +276,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 Packets"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 2450
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_PACKETS
, update_every
, RRDSET_TYPE_LINE
);
@@ -295,7 +299,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_fragsout) {
+ if(do_ip_fragsout == CONFIG_BOOLEAN_YES || (do_ip_fragsout == CONFIG_BOOLEAN_AUTO && (snmp_root.ip_FragOKs || snmp_root.ip_FragFails || snmp_root.ip_FragCreates))) {
+ do_ip_fragsout = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_FragOKs = NULL,
*rd_FragFails = NULL,
@@ -310,9 +316,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 Fragments Sent"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 3020
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_FRAGMENTS
, update_every
, RRDSET_TYPE_LINE
);
@@ -332,7 +338,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_fragsin) {
+ if(do_ip_fragsin == CONFIG_BOOLEAN_YES || (do_ip_fragsin == CONFIG_BOOLEAN_AUTO && (snmp_root.ip_ReasmOKs || snmp_root.ip_ReasmFails || snmp_root.ip_ReasmReqds))) {
+ do_ip_fragsin = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_ReasmOKs = NULL,
*rd_ReasmFails = NULL,
@@ -347,9 +355,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 Fragments Reassembly"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 3030
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_FRAGMENTS + 1
, update_every
, RRDSET_TYPE_LINE
);
@@ -369,7 +377,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_errors) {
+ if(do_ip_errors == CONFIG_BOOLEAN_YES || (do_ip_errors == CONFIG_BOOLEAN_AUTO && (snmp_root.ip_InDiscards || snmp_root.ip_OutDiscards || snmp_root.ip_InHdrErrors || snmp_root.ip_InAddrErrors || snmp_root.ip_InUnknownProtos || snmp_root.ip_OutNoRoutes))) {
+ do_ip_errors = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_InDiscards = NULL,
*rd_OutDiscards = NULL,
@@ -387,9 +397,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 Errors"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 2470
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_ERRORS
, update_every
, RRDSET_TYPE_LINE
);
@@ -437,7 +447,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_packets) {
+ if(do_icmp_packets == CONFIG_BOOLEAN_YES || (do_icmp_packets == CONFIG_BOOLEAN_AUTO && (snmp_root.icmp_InMsgs || snmp_root.icmp_OutMsgs || snmp_root.icmp_InErrors || snmp_root.icmp_OutErrors || snmp_root.icmp_InCsumErrors))) {
+ do_icmp_packets = CONFIG_BOOLEAN_YES;
+
{
static RRDSET *st_packets = NULL;
static RRDDIM *rd_InMsgs = NULL,
@@ -452,9 +464,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 ICMP Packets"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 2602
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_ICMP
, update_every
, RRDSET_TYPE_LINE
);
@@ -485,9 +497,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 ICMP Errors"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 2603
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_ICMP + 1
, update_every
, RRDSET_TYPE_LINE
);
@@ -515,8 +527,8 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
}
words = procfile_linewords(ff, l);
- if(words < 3) {
- error("Cannot read /proc/net/snmp IcmpMsg line. Expected 3+ params, read %zu.", words);
+ if(words < 2) {
+ error("Cannot read /proc/net/snmp IcmpMsg line. Expected 2+ params, read %zu.", words);
continue;
}
@@ -528,7 +540,30 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmpmsg) {
+ if(do_icmpmsg == CONFIG_BOOLEAN_YES || (do_icmpmsg == CONFIG_BOOLEAN_AUTO && (
+ snmp_root.icmpmsg_InEchoReps
+ || snmp_root.icmpmsg_OutEchoReps
+ || snmp_root.icmpmsg_InDestUnreachs
+ || snmp_root.icmpmsg_OutDestUnreachs
+ || snmp_root.icmpmsg_InRedirects
+ || snmp_root.icmpmsg_OutRedirects
+ || snmp_root.icmpmsg_InEchos
+ || snmp_root.icmpmsg_OutEchos
+ || snmp_root.icmpmsg_InRouterAdvert
+ || snmp_root.icmpmsg_OutRouterAdvert
+ || snmp_root.icmpmsg_InRouterSelect
+ || snmp_root.icmpmsg_OutRouterSelect
+ || snmp_root.icmpmsg_InTimeExcds
+ || snmp_root.icmpmsg_OutTimeExcds
+ || snmp_root.icmpmsg_InParmProbs
+ || snmp_root.icmpmsg_OutParmProbs
+ || snmp_root.icmpmsg_InTimestamps
+ || snmp_root.icmpmsg_OutTimestamps
+ || snmp_root.icmpmsg_InTimestampReps
+ || snmp_root.icmpmsg_OutTimestampReps
+ ))) {
+ do_icmpmsg = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_InEchoReps = NULL,
*rd_OutEchoReps = NULL,
@@ -560,9 +595,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 ICMP Messages"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 2604
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_ICMP + 2
, update_every
, RRDSET_TYPE_LINE
);
@@ -636,15 +671,15 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(snmp_root.tcp_MaxConn != last_max_connections) {
- last_max_connections = snmp_root.tcp_MaxConn;
- rrdvar_custom_host_variable_set(localhost, tcp_max_connections_var, last_max_connections);
- }
+ // this is smart enough to update it, only when it is changed
+ rrdvar_custom_host_variable_set(localhost, tcp_max_connections_var, snmp_root.tcp_MaxConn);
// --------------------------------------------------------------------
// see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
- if(do_tcp_sockets) {
+ if(do_tcp_sockets == CONFIG_BOOLEAN_YES || (do_tcp_sockets == CONFIG_BOOLEAN_AUTO && snmp_root.tcp_CurrEstab)) {
+ do_tcp_sockets = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_CurrEstab = NULL;
@@ -657,9 +692,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 TCP Connections"
, "active connections"
- , "proc"
- , "net/snmp"
- , 2501
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_TCP
, update_every
, RRDSET_TYPE_LINE
);
@@ -674,7 +709,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcp_packets) {
+ if(do_tcp_packets == CONFIG_BOOLEAN_YES || (do_tcp_packets == CONFIG_BOOLEAN_AUTO && (snmp_root.tcp_InSegs || snmp_root.tcp_OutSegs))) {
+ do_tcp_packets = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_InSegs = NULL,
*rd_OutSegs = NULL;
@@ -688,9 +725,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 TCP Packets"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 2510
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_TCP + 4
, update_every
, RRDSET_TYPE_LINE
);
@@ -707,7 +744,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcp_errors) {
+ if(do_tcp_errors == CONFIG_BOOLEAN_YES || (do_tcp_errors == CONFIG_BOOLEAN_AUTO && (snmp_root.tcp_InErrs || snmp_root.tcp_InCsumErrors || snmp_root.tcp_RetransSegs))) {
+ do_tcp_errors = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_InErrs = NULL,
*rd_InCsumErrors = NULL,
@@ -722,9 +761,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 TCP Errors"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 2525
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_TCP + 20
, update_every
, RRDSET_TYPE_LINE
);
@@ -744,7 +783,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcp_opens) {
+ if(do_tcp_opens == CONFIG_BOOLEAN_YES || (do_tcp_opens == CONFIG_BOOLEAN_AUTO && (snmp_root.tcp_ActiveOpens || snmp_root.tcp_PassiveOpens))) {
+ do_tcp_opens = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_ActiveOpens = NULL,
*rd_PassiveOpens = NULL;
@@ -758,9 +799,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 TCP Opens"
, "connections/s"
- , "proc"
- , "net/snmp"
- , 2502
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_TCP + 5
, update_every
, RRDSET_TYPE_LINE
);
@@ -778,7 +819,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcp_handshake) {
+ if(do_tcp_handshake == CONFIG_BOOLEAN_YES || (do_tcp_handshake == CONFIG_BOOLEAN_AUTO && (snmp_root.tcp_EstabResets || snmp_root.tcp_OutRsts || snmp_root.tcp_AttemptFails))) {
+ do_tcp_handshake = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_EstabResets = NULL,
*rd_OutRsts = NULL,
@@ -794,25 +837,25 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 TCP Handshake Issues"
, "events/s"
- , "proc"
- , "net/snmp"
- , 2530
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_TCP + 30
, update_every
, RRDSET_TYPE_LINE
);
rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rd_EstabResets = rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_OutRsts = rrddim_add(st, "OutRsts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_AttemptFails = rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_TCPSynRetrans = rrddim_add(st, "TCPSynRetrans", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_EstabResets = rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_OutRsts = rrddim_add(st, "OutRsts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_AttemptFails = rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_TCPSynRetrans = rrddim_add(st, "TCPSynRetrans", "SynRetrans", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set_by_pointer(st, rd_EstabResets, (collected_number)snmp_root.tcp_EstabResets);
- rrddim_set_by_pointer(st, rd_OutRsts, (collected_number)snmp_root.tcp_OutRsts);
- rrddim_set_by_pointer(st, rd_AttemptFails, (collected_number)snmp_root.tcp_AttemptFails);
- rrddim_set_by_pointer(st, rd_TCPSynRetrans, tcpext_TCPSynRetrans);
+ rrddim_set_by_pointer(st, rd_EstabResets, (collected_number)snmp_root.tcp_EstabResets);
+ rrddim_set_by_pointer(st, rd_OutRsts, (collected_number)snmp_root.tcp_OutRsts);
+ rrddim_set_by_pointer(st, rd_AttemptFails, (collected_number)snmp_root.tcp_AttemptFails);
+ rrddim_set_by_pointer(st, rd_TCPSynRetrans, tcpext_TCPSynRetrans);
rrdset_done(st);
}
}
@@ -839,7 +882,9 @@ 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) {
+ if(do_udp_packets == CONFIG_BOOLEAN_YES || (do_udp_packets == CONFIG_BOOLEAN_AUTO && (snmp_root.udp_InDatagrams || snmp_root.udp_OutDatagrams))) {
+ do_udp_packets = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_InDatagrams = NULL,
*rd_OutDatagrams = NULL;
@@ -853,9 +898,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 UDP Packets"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 2602
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_UDP
, update_every
, RRDSET_TYPE_LINE
);
@@ -872,7 +917,16 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_udp_errors) {
+ if(do_udp_errors == CONFIG_BOOLEAN_YES || (do_udp_errors == CONFIG_BOOLEAN_AUTO && (
+ snmp_root.udp_InErrors
+ || snmp_root.udp_NoPorts
+ || snmp_root.udp_RcvbufErrors
+ || snmp_root.udp_SndbufErrors
+ || snmp_root.udp_InCsumErrors
+ || snmp_root.udp_IgnoredMulti
+ ))) {
+ do_udp_errors = CONFIG_BOOLEAN_YES;
+
static RRDSET *st = NULL;
static RRDDIM *rd_RcvbufErrors = NULL,
*rd_SndbufErrors = NULL,
@@ -890,9 +944,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 UDP Errors"
, "events/s"
- , "proc"
- , "net/snmp"
- , 2701
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_UDP + 10
, update_every
, RRDSET_TYPE_LINE
);
@@ -938,7 +992,18 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_udplite_packets) {
+ if(do_udplite_packets == CONFIG_BOOLEAN_YES || (do_udplite_packets == CONFIG_BOOLEAN_AUTO && (
+ snmp_root.udplite_InDatagrams
+ || snmp_root.udplite_OutDatagrams
+ || snmp_root.udplite_NoPorts
+ || snmp_root.udplite_InErrors
+ || snmp_root.udplite_InCsumErrors
+ || snmp_root.udplite_RcvbufErrors
+ || snmp_root.udplite_SndbufErrors
+ || snmp_root.udplite_IgnoredMulti
+ ))) {
+ do_udplite_packets = CONFIG_BOOLEAN_YES;
+
{
static RRDSET *st = NULL;
static RRDDIM *rd_InDatagrams = NULL,
@@ -953,9 +1018,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 UDPLite Packets"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 2603
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_UDPLITE
, update_every
, RRDSET_TYPE_LINE
);
@@ -988,9 +1053,9 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
, NULL
, "IPv4 UDPLite Errors"
, "packets/s"
- , "proc"
- , "net/snmp"
- , 2604
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP_NAME
+ , NETDATA_CHART_PRIO_IPV4_UDPLITE + 10
, update_every
, RRDSET_TYPE_LINE);
diff --git a/src/proc_net_snmp6.c b/collectors/proc.plugin/proc_net_snmp6.c
index bd71b391a..f0084aa26 100644
--- a/src/proc_net_snmp6.c
+++ b/collectors/proc.plugin/proc_net_snmp6.c
@@ -1,6 +1,9 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
#define RRD_TYPE_NET_SNMP6 "ipv6"
+#define PLUGIN_PROC_MODULE_NET_SNMP6_NAME "/proc/net/snmp6"
int do_proc_net_snmp6(int update_every, usec_t dt) {
(void)dt;
@@ -289,9 +292,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 Bandwidth"
, "kilobits/s"
- , "proc"
- , "net/snmp6"
- , 502
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_IPV6
, update_every
, RRDSET_TYPE_AREA
);
@@ -325,9 +328,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 Packets"
, "packets/s"
- , "proc"
- , "net/snmp6"
- , 3000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_PACKETS
, update_every
, RRDSET_TYPE_LINE
);
@@ -364,9 +367,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 Fragments Sent"
, "packets/s"
- , "proc"
- , "net/snmp6"
- , 3011
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_FRAGSOUT
, update_every
, RRDSET_TYPE_LINE
);
@@ -410,9 +413,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 Fragments Reassembly"
, "packets/s"
- , "proc"
- , "net/snmp6"
- , 3012
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_FRAGSIN
, update_every
, RRDSET_TYPE_LINE);
rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
@@ -465,9 +468,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 Errors"
, "packets/s"
- , "proc"
- , "net/snmp6"
- , 3002
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ERRORS
, update_every
, RRDSET_TYPE_LINE
);
@@ -514,9 +517,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 UDP Packets"
, "packets/s"
- , "proc"
- , "net/snmp6"
- , 3601
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_UDP_PACKETS
, update_every
, RRDSET_TYPE_LINE
);
@@ -560,9 +563,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 UDP Errors"
, "events/s"
- , "proc"
- , "net/snmp6"
- , 3701
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_UDP_ERRORS
, update_every
, RRDSET_TYPE_LINE
);
@@ -603,9 +606,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 UDPlite Packets"
, "packets/s"
- , "proc"
- , "net/snmp6"
- , 3602
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_UDPLITE_PACKETS
, update_every
, RRDSET_TYPE_LINE
);
@@ -648,9 +651,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 UDP Lite Errors"
, "events/s"
- , "proc"
- , "net/snmp6"
- , 3701
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_UDPLITE_ERRORS
, update_every
, RRDSET_TYPE_LINE
);
@@ -689,9 +692,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 Multicast Bandwidth"
, "kilobits/s"
- , "proc"
- , "net/snmp6"
- , 9000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_MCAST
, update_every
, RRDSET_TYPE_AREA
);
@@ -724,9 +727,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 Broadcast Bandwidth"
, "kilobits/s"
- , "proc"
- , "net/snmp6"
- , 8000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_BCAST
, update_every
, RRDSET_TYPE_AREA
);
@@ -759,9 +762,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 Multicast Packets"
, "packets/s"
- , "proc"
- , "net/snmp6"
- , 9500
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_MCAST_PACKETS
, update_every
, RRDSET_TYPE_LINE
);
@@ -794,9 +797,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 ICMP Messages"
, "messages/s"
- , "proc"
- , "net/snmp6"
- , 10000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ICMP
, update_every
, RRDSET_TYPE_LINE
);
@@ -828,9 +831,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 ICMP Redirects"
, "redirects/s"
- , "proc"
- , "net/snmp6"
- , 10050
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ICMP_REDIR
, update_every
, RRDSET_TYPE_LINE
);
@@ -884,9 +887,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 ICMP Errors"
, "errors/s"
- , "proc"
- , "net/snmp6"
- , 10100
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ICMP_ERRORS
, update_every
, RRDSET_TYPE_LINE
);
@@ -944,9 +947,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 ICMP Echo"
, "messages/s"
- , "proc"
- , "net/snmp6"
- , 10200
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ICMP_ECHOS
, update_every
, RRDSET_TYPE_LINE
);
@@ -994,9 +997,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 ICMP Group Membership"
, "messages/s"
- , "proc"
- , "net/snmp6"
- , 10300
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ICMP_GROUPMEMB
, update_every
, RRDSET_TYPE_LINE);
@@ -1043,9 +1046,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 Router Messages"
, "messages/s"
- , "proc"
- , "net/snmp6"
- , 10400
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ICMP_ROUTER
, update_every
, RRDSET_TYPE_LINE
);
@@ -1089,9 +1092,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 Neighbor Messages"
, "messages/s"
- , "proc"
- , "net/snmp6"
- , 10500
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ICMP_NEIGHBOR
, update_every
, RRDSET_TYPE_LINE
);
@@ -1127,9 +1130,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 ICMP MLDv2 Reports"
, "reports/s"
- , "proc"
- , "net/snmp6"
- , 10600
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ICMP_LDV2
, update_every
, RRDSET_TYPE_LINE
);
@@ -1181,9 +1184,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 ICMP Types"
, "messages/s"
- , "proc"
- , "net/snmp6"
- , 10700
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ICMP_TYPES
, update_every
, RRDSET_TYPE_LINE
);
@@ -1239,9 +1242,9 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, NULL
, "IPv6 ECT Packets"
, "packets/s"
- , "proc"
- , "net/snmp6"
- , 10800
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SNMP6_NAME
+ , NETDATA_CHART_PRIO_IPV6_ECT
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/proc_net_sockstat.c b/collectors/proc.plugin/proc_net_sockstat.c
index db3070660..0c3b6e196 100644
--- a/src/proc_net_sockstat.c
+++ b/collectors/proc.plugin/proc_net_sockstat.c
@@ -1,4 +1,8 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME "/proc/net/sockstat"
static struct proc_net_sockstat {
kernel_uint_t sockets_used;
@@ -56,9 +60,9 @@ static int read_tcp_mem(void) {
// fprintf(stderr, "TCP MEM low = %llu, pressure = %llu, high = %llu\n", low, pressure, high);
- rrdvar_custom_host_variable_set(localhost, tcp_mem_low_threshold, low * sysconf(_SC_PAGESIZE) / 1024);
- rrdvar_custom_host_variable_set(localhost, tcp_mem_pressure_threshold, pressure * sysconf(_SC_PAGESIZE) / 1024);
- rrdvar_custom_host_variable_set(localhost, tcp_mem_high_threshold, high * sysconf(_SC_PAGESIZE) / 1024);
+ rrdvar_custom_host_variable_set(localhost, tcp_mem_low_threshold, low * sysconf(_SC_PAGESIZE) / 1024.0);
+ rrdvar_custom_host_variable_set(localhost, tcp_mem_pressure_threshold, pressure * sysconf(_SC_PAGESIZE) / 1024.0);
+ rrdvar_custom_host_variable_set(localhost, tcp_mem_high_threshold, high * sysconf(_SC_PAGESIZE) / 1024.0);
return 0;
}
@@ -229,9 +233,9 @@ int do_proc_net_sockstat(int update_every, usec_t dt) {
, NULL
, "IPv4 Sockets Used"
, "sockets"
- , "proc"
- , "net/sockstat"
- , 2400
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
+ , NETDATA_CHART_PRIO_IPV4_SOCKETS
, update_every
, RRDSET_TYPE_LINE
);
@@ -264,9 +268,9 @@ int do_proc_net_sockstat(int update_every, usec_t dt) {
, NULL
, "IPv4 TCP Sockets"
, "sockets"
- , "proc"
- , "net/sockstat"
- , 2500
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
+ , NETDATA_CHART_PRIO_IPV4_TCP_SOCKETS
, update_every
, RRDSET_TYPE_LINE
);
@@ -302,9 +306,9 @@ int do_proc_net_sockstat(int update_every, usec_t dt) {
, NULL
, "IPv4 TCP Sockets Memory"
, "KB"
- , "proc"
- , "net/sockstat"
- , 4000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
+ , NETDATA_CHART_PRIO_IPV4_TCP_MEM
, update_every
, RRDSET_TYPE_AREA
);
@@ -334,9 +338,9 @@ int do_proc_net_sockstat(int update_every, usec_t dt) {
, NULL
, "IPv4 UDP Sockets"
, "sockets"
- , "proc"
- , "net/sockstat"
- , 2600
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
+ , NETDATA_CHART_PRIO_IPV4_UDP
, update_every
, RRDSET_TYPE_LINE
);
@@ -366,9 +370,9 @@ int do_proc_net_sockstat(int update_every, usec_t dt) {
, NULL
, "IPv4 UDP Sockets Memory"
, "KB"
- , "proc"
- , "net/sockstat"
- , 2603
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
+ , NETDATA_CHART_PRIO_IPV4_UDP_MEM
, update_every
, RRDSET_TYPE_AREA
);
@@ -398,9 +402,9 @@ int do_proc_net_sockstat(int update_every, usec_t dt) {
, NULL
, "IPv4 UDPLITE Sockets"
, "sockets"
- , "proc"
- , "net/sockstat"
- , 2602
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
+ , NETDATA_CHART_PRIO_IPV4_UDPLITE
, update_every
, RRDSET_TYPE_LINE
);
@@ -430,9 +434,9 @@ int do_proc_net_sockstat(int update_every, usec_t dt) {
, NULL
, "IPv4 RAW Sockets"
, "sockets"
- , "proc"
- , "net/sockstat"
- , 3010
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
+ , NETDATA_CHART_PRIO_IPV4_RAW
, update_every
, RRDSET_TYPE_LINE
);
@@ -462,9 +466,9 @@ int do_proc_net_sockstat(int update_every, usec_t dt) {
, NULL
, "IPv4 FRAG Sockets"
, "fragments"
- , "proc"
- , "net/sockstat"
- , 3010
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
+ , NETDATA_CHART_PRIO_IPV4_FRAGMENTS
, update_every
, RRDSET_TYPE_LINE
);
@@ -494,9 +498,9 @@ int do_proc_net_sockstat(int update_every, usec_t dt) {
, NULL
, "IPv4 FRAG Sockets Memory"
, "KB"
- , "proc"
- , "net/sockstat"
- , 3020
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
+ , NETDATA_CHART_PRIO_IPV4_FRAGMENTS_MEM
, update_every
, RRDSET_TYPE_AREA
);
diff --git a/src/proc_net_sockstat6.c b/collectors/proc.plugin/proc_net_sockstat6.c
index 97175ccf7..687b9bdeb 100644
--- a/src/proc_net_sockstat6.c
+++ b/collectors/proc.plugin/proc_net_sockstat6.c
@@ -1,4 +1,8 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME "/proc/net/sockstat6"
static struct proc_net_sockstat6 {
kernel_uint_t tcp6_inuse;
@@ -122,9 +126,9 @@ int do_proc_net_sockstat6(int update_every, usec_t dt) {
, NULL
, "IPv6 TCP Sockets"
, "sockets"
- , "proc"
- , "net/sockstat6"
- , 3599
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME
+ , NETDATA_CHART_PRIO_IPV6_TCP
, update_every
, RRDSET_TYPE_LINE
);
@@ -154,9 +158,9 @@ int do_proc_net_sockstat6(int update_every, usec_t dt) {
, NULL
, "IPv6 UDP Sockets"
, "sockets"
- , "proc"
- , "net/sockstat6"
- , 3600
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME
+ , NETDATA_CHART_PRIO_IPV6_UDP
, update_every
, RRDSET_TYPE_LINE
);
@@ -186,9 +190,9 @@ int do_proc_net_sockstat6(int update_every, usec_t dt) {
, NULL
, "IPv6 UDPLITE Sockets"
, "sockets"
- , "proc"
- , "net/sockstat6"
- , 3601
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME
+ , NETDATA_CHART_PRIO_IPV6_UDPLITE
, update_every
, RRDSET_TYPE_LINE
);
@@ -218,9 +222,9 @@ int do_proc_net_sockstat6(int update_every, usec_t dt) {
, NULL
, "IPv6 RAW Sockets"
, "sockets"
- , "proc"
- , "net/sockstat6"
- , 3700
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME
+ , NETDATA_CHART_PRIO_IPV6_RAW
, update_every
, RRDSET_TYPE_LINE
);
@@ -250,9 +254,9 @@ int do_proc_net_sockstat6(int update_every, usec_t dt) {
, NULL
, "IPv6 FRAG Sockets"
, "fragments"
- , "proc"
- , "net/sockstat6"
- , 3010
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME
+ , NETDATA_CHART_PRIO_IPV6_FRAGMENTS
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/proc_net_softnet_stat.c b/collectors/proc.plugin/proc_net_softnet_stat.c
index f3c117e16..7ec783e77 100644
--- a/src/proc_net_softnet_stat.c
+++ b/collectors/proc.plugin/proc_net_softnet_stat.c
@@ -1,4 +1,8 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_NET_SOFTNET_NAME "/proc/net/softnet_stat"
static inline char *softnet_column_name(size_t column) {
switch(column) {
@@ -87,9 +91,9 @@ int do_proc_net_softnet_stat(int update_every, usec_t dt) {
, "system.softnet_stat"
, "System softnet_stat"
, "events/s"
- , "proc"
- , "net/softnet_stat"
- , 955
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOFTNET_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_SOFTNET_STAT
, update_every
, RRDSET_TYPE_LINE
);
@@ -123,9 +127,9 @@ int do_proc_net_softnet_stat(int update_every, usec_t dt) {
, "cpu.softnet_stat"
, title
, "events/s"
- , "proc"
- , "net/softnet_stat"
- , 4101 + l
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_NET_SOFTNET_NAME
+ , NETDATA_CHART_PRIO_SOFTNET_PER_CORE + l
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/proc_net_stat_conntrack.c b/collectors/proc.plugin/proc_net_stat_conntrack.c
index 363fbc199..f5257c0a0 100644
--- a/src/proc_net_stat_conntrack.c
+++ b/collectors/proc.plugin/proc_net_stat_conntrack.c
@@ -1,7 +1,10 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
#define RRD_TYPE_NET_STAT_CONNTRACK "conntrack"
+#define PLUGIN_PROC_MODULE_CONNTRACK_NAME "/proc/net/stat/nf_conntrack"
int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
static procfile *ff = NULL;
@@ -140,9 +143,9 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
, NULL
, "Connection Tracker Connections"
, "active connections"
- , "proc"
- , "net/stat/nf_conntrack"
- , 3000
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_CONNTRACK_NAME
+ , NETDATA_CHART_PRIO_NETFILTER_SOCKETS
, update_every
, RRDSET_TYPE_LINE
);
@@ -173,9 +176,9 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
, NULL
, "Connection Tracker New Connections"
, "connections/s"
- , "proc"
- , "net/stat/nf_conntrack"
- , 3001
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_CONNTRACK_NAME
+ , NETDATA_CHART_PRIO_NETFILTER_NEW
, update_every
, RRDSET_TYPE_LINE
);
@@ -210,9 +213,9 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
, NULL
, "Connection Tracker Changes"
, "changes/s"
- , "proc"
- , "net/stat/nf_conntrack"
- , 3002
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_CONNTRACK_NAME
+ , NETDATA_CHART_PRIO_NETFILTER_CHANGES
, update_every
, RRDSET_TYPE_LINE
);
@@ -247,9 +250,9 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
, NULL
, "Connection Tracker Expectations"
, "expectations/s"
- , "proc"
- , "net/stat/nf_conntrack"
- , 3003
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_CONNTRACK_NAME
+ , NETDATA_CHART_PRIO_NETFILTER_EXPECT
, update_every
, RRDSET_TYPE_LINE
);
@@ -284,9 +287,9 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
, NULL
, "Connection Tracker Searches"
, "searches/s"
- , "proc"
- , "net/stat/nf_conntrack"
- , 3010
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_CONNTRACK_NAME
+ , NETDATA_CHART_PRIO_NETFILTER_SEARCH
, update_every
, RRDSET_TYPE_LINE
);
@@ -322,9 +325,9 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
, NULL
, "Connection Tracker Errors"
, "events/s"
- , "proc"
- , "net/stat/nf_conntrack"
- , 3005
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_CONNTRACK_NAME
+ , NETDATA_CHART_PRIO_NETFILTER_ERRORS
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/proc_net_stat_synproxy.c b/collectors/proc.plugin/proc_net_stat_synproxy.c
index 0d6f6ee03..f0c1f47c1 100644
--- a/src/proc_net_stat_synproxy.c
+++ b/collectors/proc.plugin/proc_net_stat_synproxy.c
@@ -1,4 +1,8 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_SYNPROXY_NAME "/proc/net/stat/synproxy"
#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
#define RRD_TYPE_NET_STAT_SYNPROXY "synproxy"
@@ -68,9 +72,9 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
, NULL
, "SYNPROXY Entries Used"
, "entries"
- , "proc"
- , "net/stat/synproxy"
- , 3304
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_SYNPROXY_NAME
+ , NETDATA_CHART_PRIO_SYNPROXY_ENTRIES
, update_every
, RRDSET_TYPE_LINE
);
@@ -98,9 +102,9 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
, NULL
, "SYNPROXY SYN Packets received"
, "SYN/s"
- , "proc"
- , "net/stat/synproxy"
- , 3301
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_SYNPROXY_NAME
+ , NETDATA_CHART_PRIO_SYNPROXY_SYN_RECEIVED
, update_every
, RRDSET_TYPE_LINE
);
@@ -128,9 +132,9 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
, NULL
, "SYNPROXY Connections Reopened"
, "connections/s"
- , "proc"
- , "net/stat/synproxy"
- , 3303
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_SYNPROXY_NAME
+ , NETDATA_CHART_PRIO_SYNPROXY_CONN_OPEN
, update_every
, RRDSET_TYPE_LINE
);
@@ -158,9 +162,9 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
, NULL
, "SYNPROXY TCP Cookies"
, "cookies/s"
- , "proc"
- , "net/stat/synproxy"
- , 3302
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_SYNPROXY_NAME
+ , NETDATA_CHART_PRIO_SYNPROXY_COOKIES
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/proc_self_mountinfo.c b/collectors/proc.plugin/proc_self_mountinfo.c
index 4ccdddff1..3f17ccce2 100644
--- a/src/proc_self_mountinfo.c
+++ b/collectors/proc.plugin/proc_self_mountinfo.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
// ----------------------------------------------------------------------------
// taken from gnulib/mountlist.c
diff --git a/src/proc_self_mountinfo.h b/collectors/proc.plugin/proc_self_mountinfo.h
index a8d337539..15d63c786 100644
--- a/src/proc_self_mountinfo.h
+++ b/collectors/proc.plugin/proc_self_mountinfo.h
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#ifndef NETDATA_PROC_SELF_MOUNTINFO_H
#define NETDATA_PROC_SELF_MOUNTINFO_H 1
diff --git a/src/proc_softirqs.c b/collectors/proc.plugin/proc_softirqs.c
index cd7440b00..d68c69bb7 100644
--- a/src/proc_softirqs.c
+++ b/collectors/proc.plugin/proc_softirqs.c
@@ -1,4 +1,8 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_SOFTIRQS_NAME "/proc/softirqs"
#define MAX_INTERRUPT_NAME 50
@@ -51,15 +55,16 @@ static inline struct interrupt *get_interrupts_array(size_t lines, int cpus) {
int do_proc_softirqs(int update_every, usec_t dt) {
(void)dt;
static procfile *ff = NULL;
- static int cpus = -1, do_per_core = -1;
+ static int cpus = -1, do_per_core = CONFIG_BOOLEAN_INVALID;
struct interrupt *irrs = NULL;
- if(unlikely(do_per_core == -1)) do_per_core = config_get_boolean("plugin:proc:/proc/softirqs", "interrupts per core", 1);
+ if(unlikely(do_per_core == CONFIG_BOOLEAN_INVALID))
+ do_per_core = config_get_boolean_ondemand("plugin:proc:/proc/softirqs", "interrupts per core", CONFIG_BOOLEAN_AUTO);
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/softirqs");
- ff = procfile_open(config_get("plugin:proc:/proc/softirqs", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(config_get("plugin:proc:/proc/softirqs", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -105,10 +110,6 @@ int do_proc_softirqs(int update_every, usec_t dt) {
irr->id = procfile_lineword(ff, l, 0);
if(unlikely(!irr->id || !irr->id[0])) continue;
- size_t idlen = strlen(irr->id);
- if(unlikely(idlen && irr->id[idlen - 1] == ':'))
- irr->id[idlen - 1] = '\0';
-
int c;
for(c = 0; c < cpus ;c++) {
if(likely((c + 1) < (int)words))
@@ -136,9 +137,9 @@ int do_proc_softirqs(int update_every, usec_t dt) {
, NULL
, "System softirqs"
, "softirqs/s"
- , "proc"
- , "softirqs"
- , 950
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_SOFTIRQS_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_SOFTIRQS
, update_every
, RRDSET_TYPE_STACKED
);
@@ -148,34 +149,30 @@ int do_proc_softirqs(int update_every, usec_t dt) {
for(l = 0; l < lines ;l++) {
struct interrupt *irr = irrindex(irrs, l, cpus);
- if(unlikely(!irr->used)) continue;
-
- // some interrupt may have changed without changing the total number of lines
- // if the same number of interrupts have been added and removed between two
- // calls of this function.
- if(unlikely(!irr->rd || strncmp(irr->name, irr->rd->name, MAX_INTERRUPT_NAME) != 0)) {
- irr->rd = rrddim_find(st_system_softirqs, irr->id);
-
- if(unlikely(!irr->rd))
+ if(irr->used && irr->total) {
+ // some interrupt may have changed without changing the total number of lines
+ // if the same number of interrupts have been added and removed between two
+ // calls of this function.
+ if(unlikely(!irr->rd || strncmp(irr->name, irr->rd->name, MAX_INTERRUPT_NAME) != 0)) {
irr->rd = rrddim_add(st_system_softirqs, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- else
rrddim_set_name(st_system_softirqs, irr->rd, irr->name);
- // also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop
- if(likely(do_per_core)) {
- int c;
- for (c = 0; c < cpus ;c++) irr->cpu[c].rd = NULL;
+ // also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop
+ if(likely(do_per_core != CONFIG_BOOLEAN_NO)) {
+ int c;
+ for(c = 0; c < cpus; c++) irr->cpu[c].rd = NULL;
+ }
}
- }
- rrddim_set_by_pointer(st_system_softirqs, irr->rd, irr->total);
+ rrddim_set_by_pointer(st_system_softirqs, irr->rd, irr->total);
+ }
}
rrdset_done(st_system_softirqs);
// --------------------------------------------------------------------
- if(do_per_core) {
+ if(do_per_core != CONFIG_BOOLEAN_NO) {
static RRDSET **core_st = NULL;
static int old_cpus = 0;
@@ -214,9 +211,9 @@ int do_proc_softirqs(int update_every, usec_t dt) {
, "cpu.softirqs"
, title
, "softirqs/s"
- , "proc"
- , "softirqs"
- , 3000 + c
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_SOFTIRQS_NAME
+ , NETDATA_CHART_PRIO_SOFTIRQS_PER_CORE + c
, update_every
, RRDSET_TYPE_STACKED
);
@@ -227,18 +224,14 @@ int do_proc_softirqs(int update_every, usec_t dt) {
for(l = 0; l < lines ;l++) {
struct interrupt *irr = irrindex(irrs, l, cpus);
- if(unlikely(!irr->used)) continue;
-
- if(unlikely(!irr->cpu[c].rd)) {
- irr->cpu[c].rd = rrddim_find(core_st[c], irr->id);
-
- if(unlikely(!irr->cpu[c].rd))
+ if(irr->used && (do_per_core == CONFIG_BOOLEAN_YES || irr->cpu[c].value)) {
+ if(unlikely(!irr->cpu[c].rd)) {
irr->cpu[c].rd = rrddim_add(core_st[c], irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- else
rrddim_set_name(core_st[c], irr->cpu[c].rd, irr->name);
- }
+ }
- rrddim_set_by_pointer(core_st[c], irr->cpu[c].rd, irr->cpu[c].value);
+ rrddim_set_by_pointer(core_st[c], irr->cpu[c].rd, irr->cpu[c].value);
+ }
}
rrdset_done(core_st[c]);
diff --git a/src/proc_spl_kstat_zfs.c b/collectors/proc.plugin/proc_spl_kstat_zfs.c
index 9d489d8e4..a96b236cb 100644
--- a/src/proc_spl_kstat_zfs.c
+++ b/collectors/proc.plugin/proc_spl_kstat_zfs.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
#include "zfs_common.h"
#define ZFS_PROC_ARCSTATS "/proc/spl/kstat/zfs/arcstats"
@@ -146,8 +148,8 @@ int do_proc_spl_kstat_zfs_arcstats(int update_every, usec_t dt) {
if(unlikely(arcstats.l2exist == -1))
arcstats.l2exist = 0;
- generate_charts_arcstats("proc", update_every);
- generate_charts_arc_summary("proc", update_every);
+ generate_charts_arcstats(PLUGIN_PROC_NAME, ZFS_PROC_ARCSTATS, update_every);
+ generate_charts_arc_summary(PLUGIN_PROC_NAME, ZFS_PROC_ARCSTATS, update_every);
return 0;
}
diff --git a/src/proc_stat.c b/collectors/proc.plugin/proc_stat.c
index d1aefb73e..fb77df647 100644
--- a/src/proc_stat.c
+++ b/collectors/proc.plugin/proc_stat.c
@@ -1,7 +1,11 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_STAT_NAME "/proc/stat"
struct per_core_single_number_file {
- char found:1;
+ unsigned char found:1;
const char *filename;
int fd;
collected_number value;
@@ -121,6 +125,8 @@ int do_proc_stat(int update_every, usec_t dt) {
static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1, do_core_throttle_count = -1, do_package_throttle_count = -1, do_scaling_cur_freq = -1;
static uint32_t hash_intr, hash_ctxt, hash_processes, hash_procs_running, hash_procs_blocked;
static char *core_throttle_count_filename = NULL, *package_throttle_count_filename = NULL, *scaling_cur_freq_filename = NULL;
+ static RRDVAR *cpus_var = NULL;
+ size_t cores_found = (size_t)processors;
if(unlikely(do_cpu == -1)) {
do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", CONFIG_BOOLEAN_YES);
@@ -196,6 +202,7 @@ int do_proc_stat(int update_every, usec_t dt) {
}
size_t core = (row_key[3] == '\0') ? 0 : str2ul(&row_key[3]) + 1;
+ if(core > 0) cores_found = core;
if(likely((core == 0 && do_cpu) || (core > 0 && do_cpu_cores))) {
char *id;
@@ -236,17 +243,17 @@ int do_proc_stat(int update_every, usec_t dt) {
type = "system";
context = "system.cpu";
family = id;
- priority = 100;
+ priority = NETDATA_CHART_PRIO_SYSTEM_CPU;
}
else {
title = "Core utilization";
type = "cpu";
context = "cpu.cpu";
family = "utilization";
- priority = 1000;
+ priority = NETDATA_CHART_PRIO_CPU_PER_CORE;
- // FIXME: check for /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
- // FIXME: check for /sys/devices/system/cpu/cpu*/cpufreq/stats/time_in_state
+ // TODO: check for /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
+ // TODO: check for /sys/devices/system/cpu/cpu*/cpufreq/stats/time_in_state
char filename[FILENAME_MAX + 1];
struct stat stbuf;
@@ -287,9 +294,9 @@ int do_proc_stat(int update_every, usec_t dt) {
, context
, title
, "percentage"
- , "proc"
- , "stat"
- , priority
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_STAT_NAME
+ , priority + core
, update_every
, RRDSET_TYPE_STACKED
);
@@ -308,6 +315,9 @@ int do_proc_stat(int update_every, usec_t dt) {
cpu_chart->rd_iowait = rrddim_add(cpu_chart->st, "iowait", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
cpu_chart->rd_idle = rrddim_add(cpu_chart->st, "idle", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
rrddim_hide(cpu_chart->st, "idle");
+
+ if(unlikely(core == 0 && cpus_var == NULL))
+ cpus_var = rrdvar_custom_host_variable_create(localhost, "active_processors");
}
else rrdset_next(cpu_chart->st);
@@ -339,9 +349,9 @@ int do_proc_stat(int update_every, usec_t dt) {
, NULL
, "CPU Interrupts"
, "interrupts/s"
- , "proc"
- , "stat"
- , 900
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_STAT_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_INTR
, update_every
, RRDSET_TYPE_LINE
);
@@ -371,9 +381,9 @@ int do_proc_stat(int update_every, usec_t dt) {
, NULL
, "CPU Context Switches"
, "context switches/s"
- , "proc"
- , "stat"
- , 800
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_STAT_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_CTXT
, update_every
, RRDSET_TYPE_LINE
);
@@ -412,9 +422,9 @@ int do_proc_stat(int update_every, usec_t dt) {
, NULL
, "Started Processes"
, "processes/s"
- , "proc"
- , "stat"
- , 700
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_STAT_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_FORKS
, update_every
, RRDSET_TYPE_LINE
);
@@ -444,9 +454,9 @@ int do_proc_stat(int update_every, usec_t dt) {
, NULL
, "System Processes"
, "processes"
- , "proc"
- , "stat"
- , 600
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_STAT_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_PROCESSES
, update_every
, RRDSET_TYPE_LINE
);
@@ -478,9 +488,9 @@ int do_proc_stat(int update_every, usec_t dt) {
, "cpu.core_throttling"
, "Core Thermal Throttling Events"
, "events/s"
- , "proc"
- , "stat"
- , 5001
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_STAT_NAME
+ , NETDATA_CHART_PRIO_CORE_THROTTLING
, update_every
, RRDSET_TYPE_LINE
);
@@ -508,9 +518,9 @@ int do_proc_stat(int update_every, usec_t dt) {
, "cpu.package_throttling"
, "Package Thermal Throttling Events"
, "events/s"
- , "proc"
- , "stat"
- , 5002
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_STAT_NAME
+ , NETDATA_CHART_PRIO_PACKAGE_THROTTLING
, update_every
, RRDSET_TYPE_LINE
);
@@ -538,8 +548,8 @@ int do_proc_stat(int update_every, usec_t dt) {
, "cpu.scaling_cur_freq"
, "Per CPU Core, Current CPU Scaling Frequency"
, "MHz"
- , "proc"
- , "stat"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_STAT_NAME
, 5003
, update_every
, RRDSET_TYPE_LINE
@@ -553,5 +563,8 @@ int do_proc_stat(int update_every, usec_t dt) {
}
}
+ if(cpus_var)
+ rrdvar_custom_host_variable_set(localhost, cpus_var, cores_found);
+
return 0;
}
diff --git a/src/proc_sys_kernel_random_entropy_avail.c b/collectors/proc.plugin/proc_sys_kernel_random_entropy_avail.c
index ca4d7657c..20d2116ce 100644
--- a/src/proc_sys_kernel_random_entropy_avail.c
+++ b/collectors/proc.plugin/proc_sys_kernel_random_entropy_avail.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
int do_proc_sys_kernel_random_entropy_avail(int update_every, usec_t dt) {
(void)dt;
@@ -29,9 +31,9 @@ int do_proc_sys_kernel_random_entropy_avail(int update_every, usec_t dt) {
, NULL
, "Available Entropy"
, "entropy"
- , "proc"
- , "sys/kernel/random/entropy_avail"
- , 1000
+ , PLUGIN_PROC_NAME
+ , "/proc/sys/kernel/random/entropy_avail"
+ , NETDATA_CHART_PRIO_SYSTEM_ENTROPY
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/proc_uptime.c b/collectors/proc.plugin/proc_uptime.c
index 259de4760..142ae2d0c 100644
--- a/src/proc_uptime.c
+++ b/collectors/proc.plugin/proc_uptime.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
static inline collected_number uptime_from_boottime(void) {
#ifdef CLOCK_BOOTTIME_IS_AVAILABLE
@@ -83,9 +85,9 @@ int do_proc_uptime(int update_every, usec_t dt) {
, NULL
, "System Uptime"
, "seconds"
- , "proc"
- , "uptime"
- , 1000
+ , PLUGIN_PROC_NAME
+ , "/proc/uptime"
+ , NETDATA_CHART_PRIO_SYSTEM_UPTIME
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/proc_vmstat.c b/collectors/proc.plugin/proc_vmstat.c
index 52e88d888..f7c93c20a 100644
--- a/src/proc_vmstat.c
+++ b/collectors/proc.plugin/proc_vmstat.c
@@ -1,4 +1,8 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_VMSTAT_NAME "/proc/vmstat"
int do_proc_vmstat(int update_every, usec_t dt) {
(void)dt;
@@ -102,9 +106,9 @@ int do_proc_vmstat(int update_every, usec_t dt) {
, NULL
, "Swap I/O"
, "kilobytes/s"
- , "proc"
- , "vmstat"
- , 250
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_VMSTAT_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_SWAPIO
, update_every
, RRDSET_TYPE_AREA
);
@@ -134,9 +138,9 @@ int do_proc_vmstat(int update_every, usec_t dt) {
, NULL
, "Memory Paged from/to disk"
, "kilobytes/s"
- , "proc"
- , "vmstat"
- , 151
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_VMSTAT_NAME
+ , NETDATA_CHART_PRIO_SYSTEM_PGPGIO
, update_every
, RRDSET_TYPE_AREA
);
@@ -166,8 +170,8 @@ int do_proc_vmstat(int update_every, usec_t dt) {
, NULL
, "Memory Page Faults"
, "page faults/s"
- , "proc"
- , "vmstat"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_VMSTAT_NAME
, NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS
, update_every
, RRDSET_TYPE_LINE
@@ -211,8 +215,8 @@ int do_proc_vmstat(int update_every, usec_t dt) {
, NULL
, "NUMA events"
, "events/s"
- , "proc"
- , "vmstat"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_VMSTAT_NAME
, NETDATA_CHART_PRIO_MEM_NUMA
, update_every
, RRDSET_TYPE_LINE
diff --git a/src/sys_devices_system_edac_mc.c b/collectors/proc.plugin/sys_devices_system_edac_mc.c
index caa16192e..03cbfff83 100644
--- a/src/sys_devices_system_edac_mc.c
+++ b/collectors/proc.plugin/sys_devices_system_edac_mc.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
struct mc {
char *name;
@@ -140,9 +142,9 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
, NULL
, "ECC Memory Correctable Errors"
, "errors"
- , "proc"
+ , PLUGIN_PROC_NAME
, "/sys/devices/system/edac/mc"
- , NETDATA_CHART_PRIO_MEM_HW + 50
+ , NETDATA_CHART_PRIO_MEM_HW_ECC_CE
, update_every
, RRDSET_TYPE_LINE
);
@@ -178,9 +180,9 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
, NULL
, "ECC Memory Uncorrectable Errors"
, "errors"
- , "proc"
+ , PLUGIN_PROC_NAME
, "/sys/devices/system/edac/mc"
- , NETDATA_CHART_PRIO_MEM_HW + 60
+ , NETDATA_CHART_PRIO_MEM_HW_ECC_UE
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/sys_devices_system_node.c b/collectors/proc.plugin/sys_devices_system_node.c
index d04c8dc30..6e6d0acca 100644
--- a/src/sys_devices_system_node.c
+++ b/collectors/proc.plugin/sys_devices_system_node.c
@@ -1,4 +1,6 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
struct node {
char *name;
@@ -105,9 +107,9 @@ int do_proc_sys_devices_system_node(int update_every, usec_t dt) {
, NULL
, "NUMA events"
, "events/s"
- , "proc"
+ , PLUGIN_PROC_NAME
, "/sys/devices/system/node"
- , NETDATA_CHART_PRIO_MEM_NUMA + 10
+ , NETDATA_CHART_PRIO_MEM_NUMA_NODES
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/sys_fs_btrfs.c b/collectors/proc.plugin/sys_fs_btrfs.c
index a8dfb5c91..ed980cea5 100644
--- a/src/sys_fs_btrfs.c
+++ b/collectors/proc.plugin/sys_fs_btrfs.c
@@ -1,4 +1,8 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_BTRFS_NAME "/sys/fs/btrfs"
typedef struct btrfs_disk {
char *name;
@@ -171,12 +175,16 @@ static inline int find_btrfs_disks(BTRFS_NODE *node, const char *path) {
snprintfz(filename, FILENAME_MAX, "%s/%s/size", path, de->d_name);
d->size_filename = strdupz(filename);
- // for disks
- snprintfz(filename, FILENAME_MAX, "%s/%s/queue/hw_sector_size", path, de->d_name);
+ // for bcache
+ snprintfz(filename, FILENAME_MAX, "%s/%s/bcache/../queue/hw_sector_size", path, de->d_name);
struct stat sb;
- if(stat(filename, &sb) == -1)
- // for partitions
- snprintfz(filename, FILENAME_MAX, "%s/%s/../queue/hw_sector_size", path, de->d_name);
+ if(stat(filename, &sb) == -1) {
+ // for disks
+ snprintfz(filename, FILENAME_MAX, "%s/%s/queue/hw_sector_size", path, de->d_name);
+ if(stat(filename, &sb) == -1)
+ // for partitions
+ snprintfz(filename, FILENAME_MAX, "%s/%s/../queue/hw_sector_size", path, de->d_name);
+ }
d->hw_sector_size_filename = strdupz(filename);
@@ -538,7 +546,7 @@ int do_sys_fs_btrfs(int update_every, usec_t dt) {
snprintf(id, RRD_ID_LENGTH_MAX, "disk_%s", node->id);
snprintf(name, RRD_ID_LENGTH_MAX, "disk_%s", node->label);
- snprintf(title, 200, "BTRFS Disk Allocation for %s", node->label);
+ snprintf(title, 200, "BTRFS Physical Disk Allocation for %s", node->label);
netdata_fix_chart_id(id);
netdata_fix_chart_name(name);
@@ -551,20 +559,20 @@ int do_sys_fs_btrfs(int update_every, usec_t dt) {
, "btrfs.disk"
, title
, "MB"
- , "proc"
- , "sys/fs/btrfs"
- , 2300
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_BTRFS_NAME
+ , NETDATA_CHART_PRIO_BTRFS_DISK
, update_every
, RRDSET_TYPE_STACKED
);
- node->rd_allocation_disks_unallocated = rrddim_add(node->st_allocation_disks, "unallocated", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- node->rd_allocation_disks_data_used = rrddim_add(node->st_allocation_disks, "data_used", "data used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- node->rd_allocation_disks_data_free = rrddim_add(node->st_allocation_disks, "data_free", "data free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- node->rd_allocation_disks_metadata_used = rrddim_add(node->st_allocation_disks, "meta_used", "meta used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ node->rd_allocation_disks_unallocated = rrddim_add(node->st_allocation_disks, "unallocated", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ node->rd_allocation_disks_data_free = rrddim_add(node->st_allocation_disks, "data_free", "data free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ node->rd_allocation_disks_data_used = rrddim_add(node->st_allocation_disks, "data_used", "data used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
node->rd_allocation_disks_metadata_free = rrddim_add(node->st_allocation_disks, "meta_free", "meta free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- node->rd_allocation_disks_system_used = rrddim_add(node->st_allocation_disks, "sys_used", "sys used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- node->rd_allocation_disks_system_free = rrddim_add(node->st_allocation_disks, "sys_free", "sys free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ node->rd_allocation_disks_metadata_used = rrddim_add(node->st_allocation_disks, "meta_used", "meta used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ node->rd_allocation_disks_system_free = rrddim_add(node->st_allocation_disks, "sys_free", "sys free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ node->rd_allocation_disks_system_used = rrddim_add(node->st_allocation_disks, "sys_used", "sys used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(node->st_allocation_disks);
@@ -607,9 +615,9 @@ int do_sys_fs_btrfs(int update_every, usec_t dt) {
, "btrfs.data"
, title
, "MB"
- , "proc"
- , "sys/fs/btrfs"
- , 2301
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_BTRFS_NAME
+ , NETDATA_CHART_PRIO_BTRFS_DATA
, update_every
, RRDSET_TYPE_STACKED
);
@@ -648,9 +656,9 @@ int do_sys_fs_btrfs(int update_every, usec_t dt) {
, "btrfs.metadata"
, title
, "MB"
- , "proc"
- , "sys/fs/btrfs"
- , 2302
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_BTRFS_NAME
+ , NETDATA_CHART_PRIO_BTRFS_METADATA
, update_every
, RRDSET_TYPE_STACKED
);
@@ -691,9 +699,9 @@ int do_sys_fs_btrfs(int update_every, usec_t dt) {
, "btrfs.system"
, title
, "MB"
- , "proc"
- , "sys/fs/btrfs"
- , 2303
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_BTRFS_NAME
+ , NETDATA_CHART_PRIO_BTRFS_SYSTEM
, update_every
, RRDSET_TYPE_STACKED
);
diff --git a/src/sys_kernel_mm_ksm.c b/collectors/proc.plugin/sys_kernel_mm_ksm.c
index 7ca1366b4..0f5c79c49 100644
--- a/src/sys_kernel_mm_ksm.c
+++ b/collectors/proc.plugin/sys_kernel_mm_ksm.c
@@ -1,4 +1,8 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_proc.h"
+
+#define PLUGIN_PROC_MODULE_KSM_NAME "/sys/kernel/mm/ksm"
typedef struct ksm_name_value {
char filename[FILENAME_MAX + 1];
@@ -102,8 +106,8 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
, NULL
, "Kernel Same Page Merging"
, "MB"
- , "proc"
- , "/sys/kernel/mm/ksm"
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_KSM_NAME
, NETDATA_CHART_PRIO_MEM_KSM
, update_every
, RRDSET_TYPE_AREA
@@ -142,9 +146,9 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
, NULL
, "Kernel Same Page Merging Savings"
, "MB"
- , "proc"
- , "/sys/kernel/mm/ksm"
- , NETDATA_CHART_PRIO_MEM_KSM + 1
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_KSM_NAME
+ , NETDATA_CHART_PRIO_MEM_KSM_SAVINGS
, update_every
, RRDSET_TYPE_AREA
);
@@ -176,9 +180,9 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
, NULL
, "Kernel Same Page Merging Effectiveness"
, "percentage"
- , "proc"
- , "/sys/kernel/mm/ksm"
- , NETDATA_CHART_PRIO_MEM_KSM + 2
+ , PLUGIN_PROC_NAME
+ , PLUGIN_PROC_MODULE_KSM_NAME
+ , NETDATA_CHART_PRIO_MEM_KSM_RATIOS
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/zfs_common.c b/collectors/proc.plugin/zfs_common.c
index 05935dd0f..1aaceb908 100644
--- a/src/zfs_common.c
+++ b/collectors/proc.plugin/zfs_common.c
@@ -1,9 +1,10 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "zfs_common.h"
struct arcstats arcstats = { 0 };
-void generate_charts_arcstats(const char *plugin, int update_every) {
+void generate_charts_arcstats(const char *plugin, const char *module, int update_every) {
// ARC reads
unsigned long long aread = arcstats.hits + arcstats.misses;
@@ -47,8 +48,8 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
, "ZFS ARC Size"
, "MB"
, plugin
- , "zfs"
- , 2500
+ , module
+ , NETDATA_CHART_PRIO_ZFS_ARC_SIZE
, update_every
, RRDSET_TYPE_AREA
);
@@ -85,8 +86,8 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
, "ZFS L2 ARC Size"
, "MB"
, plugin
- , "zfs"
- , 2500
+ , module
+ , NETDATA_CHART_PRIO_ZFS_L2_SIZE
, update_every
, RRDSET_TYPE_AREA
);
@@ -122,8 +123,8 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
, "ZFS Reads"
, "reads/s"
, plugin
- , "zfs"
- , 2510
+ , module
+ , NETDATA_CHART_PRIO_ZFS_READS
, update_every
, RRDSET_TYPE_AREA
);
@@ -167,8 +168,8 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
, "ZFS ARC L2 Read/Write Rate"
, "kilobytes/s"
, plugin
- , "zfs"
- , 2700
+ , module
+ , NETDATA_CHART_PRIO_ZFS_IO
, update_every
, RRDSET_TYPE_AREA
);
@@ -201,8 +202,8 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
, "ZFS ARC Hits"
, "percentage"
, plugin
- , "zfs"
- , 2520
+ , module
+ , NETDATA_CHART_PRIO_ZFS_HITS
, update_every
, RRDSET_TYPE_STACKED
);
@@ -235,8 +236,8 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
, "ZFS Demand Hits"
, "percentage"
, plugin
- , "zfs"
- , 2530
+ , module
+ , NETDATA_CHART_PRIO_ZFS_DHITS
, update_every
, RRDSET_TYPE_STACKED
);
@@ -269,8 +270,8 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
, "ZFS Prefetch Hits"
, "percentage"
, plugin
- , "zfs"
- , 2540
+ , module
+ , NETDATA_CHART_PRIO_ZFS_PHITS
, update_every
, RRDSET_TYPE_STACKED
);
@@ -303,8 +304,8 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
, "ZFS Metadata Hits"
, "percentage"
, plugin
- , "zfs"
- , 2550
+ , module
+ , NETDATA_CHART_PRIO_ZFS_MHITS
, update_every
, RRDSET_TYPE_STACKED
);
@@ -337,8 +338,8 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
, "ZFS L2 Hits"
, "percentage"
, plugin
- , "zfs"
- , 2560
+ , module
+ , NETDATA_CHART_PRIO_ZFS_L2HITS
, update_every
, RRDSET_TYPE_STACKED
);
@@ -373,8 +374,8 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
, "ZFS List Hits"
, "hits/s"
, plugin
- , "zfs"
- , 2600
+ , module
+ , NETDATA_CHART_PRIO_ZFS_LIST_HITS
, update_every
, RRDSET_TYPE_AREA
);
@@ -395,7 +396,7 @@ void generate_charts_arcstats(const char *plugin, int update_every) {
}
}
-void generate_charts_arc_summary(const char *plugin, int update_every) {
+void generate_charts_arc_summary(const char *plugin, const char *module, int update_every) {
unsigned long long arc_accesses_total = arcstats.hits + arcstats.misses;
unsigned long long real_hits = arcstats.mfu_hits + arcstats.mru_hits;
unsigned long long real_misses = arc_accesses_total - real_hits;
@@ -432,8 +433,8 @@ void generate_charts_arc_summary(const char *plugin, int update_every) {
, "ZFS ARC Size Breakdown"
, "percentage"
, plugin
- , "zfs"
- , 2520
+ , module
+ , NETDATA_CHART_PRIO_ZFS_ARC_SIZE_BREAKDOWN
, update_every
, RRDSET_TYPE_STACKED
);
@@ -471,8 +472,8 @@ void generate_charts_arc_summary(const char *plugin, int update_every) {
, "ZFS Memory Operations"
, "operations/s"
, plugin
- , "zfs"
- , 2523
+ , module
+ , NETDATA_CHART_PRIO_ZFS_MEMORY_OPS
, update_every
, RRDSET_TYPE_LINE
);
@@ -517,8 +518,8 @@ void generate_charts_arc_summary(const char *plugin, int update_every) {
, "ZFS Important Operations"
, "operations/s"
, plugin
- , "zfs"
- , 2522
+ , module
+ , NETDATA_CHART_PRIO_ZFS_IMPORTANT_OPS
, update_every
, RRDSET_TYPE_LINE
);
@@ -555,8 +556,8 @@ void generate_charts_arc_summary(const char *plugin, int update_every) {
, "ZFS Actual Cache Hits"
, "percentage"
, plugin
- , "zfs"
- , 2519
+ , module
+ , NETDATA_CHART_PRIO_ZFS_ACTUAL_HITS
, update_every
, RRDSET_TYPE_STACKED
);
@@ -589,8 +590,8 @@ void generate_charts_arc_summary(const char *plugin, int update_every) {
, "ZFS Data Demand Efficiency"
, "percentage"
, plugin
- , "zfs"
- , 2531
+ , module
+ , NETDATA_CHART_PRIO_ZFS_DEMAND_DATA_HITS
, update_every
, RRDSET_TYPE_STACKED
);
@@ -623,8 +624,8 @@ void generate_charts_arc_summary(const char *plugin, int update_every) {
, "ZFS Data Prefetch Efficiency"
, "percentage"
, plugin
- , "zfs"
- , 2532
+ , module
+ , NETDATA_CHART_PRIO_ZFS_PREFETCH_DATA_HITS
, update_every
, RRDSET_TYPE_STACKED
);
@@ -657,8 +658,8 @@ void generate_charts_arc_summary(const char *plugin, int update_every) {
, "ZFS ARC Hash Elements"
, "elements"
, plugin
- , "zfs"
- , 2800
+ , module
+ , NETDATA_CHART_PRIO_ZFS_HASH_ELEMENTS
, update_every
, RRDSET_TYPE_LINE
);
@@ -691,8 +692,8 @@ void generate_charts_arc_summary(const char *plugin, int update_every) {
, "ZFS ARC Hash Chains"
, "chains"
, plugin
- , "zfs"
- , 2810
+ , module
+ , NETDATA_CHART_PRIO_ZFS_HASH_CHAINS
, update_every
, RRDSET_TYPE_LINE
);
diff --git a/src/zfs_common.h b/collectors/proc.plugin/zfs_common.h
index 4494e70ca..fab54f59a 100644
--- a/src/zfs_common.h
+++ b/collectors/proc.plugin/zfs_common.h
@@ -1,5 +1,9 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#ifndef NETDATA_ZFS_COMMON_H
-#define NETDATA_ZFS_COMMON_H
+#define NETDATA_ZFS_COMMON_H 1
+
+#include "../../daemon/common.h"
#define ZFS_FAMILY_SIZE "size"
#define ZFS_FAMILY_EFFICIENCY "efficiency"
@@ -105,7 +109,7 @@ struct arcstats {
int l2exist;
};
-void generate_charts_arcstats(const char *plugin, int update_every);
-void generate_charts_arc_summary(const char *plugin, int update_every);
+void generate_charts_arcstats(const char *plugin, const char *module, int update_every);
+void generate_charts_arc_summary(const char *plugin, const char *module, int update_every);
#endif //NETDATA_ZFS_COMMON_H
diff --git a/python.d/Makefile.am b/collectors/python.d.plugin/Makefile.am
index a5fcc7394..5f214e436 100644
--- a/python.d/Makefile.am
+++ b/collectors/python.d.plugin/Makefile.am
@@ -1,73 +1,110 @@
-MAINTAINERCLEANFILES= $(srcdir)/Makefile.in
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
CLEANFILES = \
- python-modules-installer.sh \
+ python.d.plugin \
$(NULL)
include $(top_srcdir)/build/subst.inc
-
SUFFIXES = .in
+dist_libconfig_DATA = \
+ python.d.conf \
+ $(NULL)
+
+dist_plugins_SCRIPTS = \
+ python.d.plugin \
+ $(NULL)
+
+dist_noinst_DATA = \
+ python.d.plugin.in \
+ README.md \
+ $(NULL)
+
dist_python_SCRIPTS = \
- python-modules-installer.sh \
$(NULL)
dist_python_DATA = \
- README.md \
- apache.chart.py \
- beanstalk.chart.py \
- bind_rndc.chart.py \
- ceph.chart.py \
- chrony.chart.py \
- couchdb.chart.py \
- cpufreq.chart.py \
- cpuidle.chart.py \
- dns_query_time.chart.py \
- dnsdist.chart.py \
- dovecot.chart.py \
- elasticsearch.chart.py \
- example.chart.py \
- exim.chart.py \
- fail2ban.chart.py \
- freeradius.chart.py \
- go_expvar.chart.py \
- haproxy.chart.py \
- hddtemp.chart.py \
- httpcheck.chart.py \
- icecast.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_plus.chart.py \
- nsd.chart.py \
- ntpd.chart.py \
- ovpn_status_log.chart.py \
- phpfpm.chart.py \
- portcheck.chart.py \
- postfix.chart.py \
- postgres.chart.py \
- powerdns.chart.py \
- rabbitmq.chart.py \
- redis.chart.py \
- retroshare.chart.py \
- samba.chart.py \
- sensors.chart.py \
- springboot.chart.py \
- squid.chart.py \
- smartd_log.chart.py \
- tomcat.chart.py \
- traefik.chart.py \
- varnish.chart.py \
- web_log.chart.py \
$(NULL)
+userpythonconfigdir=$(configdir)/python.d
+dist_userpythonconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
+pythonconfigdir=$(libconfigdir)/python.d
+dist_pythonconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
+include adaptec_raid/Makefile.inc
+include apache/Makefile.inc
+include beanstalk/Makefile.inc
+include bind_rndc/Makefile.inc
+include boinc/Makefile.inc
+include ceph/Makefile.inc
+include chrony/Makefile.inc
+include couchdb/Makefile.inc
+include cpufreq/Makefile.inc
+include cpuidle/Makefile.inc
+include dnsdist/Makefile.inc
+include dns_query_time/Makefile.inc
+include dockerd/Makefile.inc
+include dovecot/Makefile.inc
+include elasticsearch/Makefile.inc
+include example/Makefile.inc
+include exim/Makefile.inc
+include fail2ban/Makefile.inc
+include freeradius/Makefile.inc
+include go_expvar/Makefile.inc
+include haproxy/Makefile.inc
+include hddtemp/Makefile.inc
+include httpcheck/Makefile.inc
+include icecast/Makefile.inc
+include ipfs/Makefile.inc
+include isc_dhcpd/Makefile.inc
+include linux_power_supply/Makefile.inc
+include litespeed/Makefile.inc
+include logind/Makefile.inc
+include mdstat/Makefile.inc
+include megacli/Makefile.inc
+include memcached/Makefile.inc
+include mongodb/Makefile.inc
+include monit/Makefile.inc
+include mysql/Makefile.inc
+include nginx/Makefile.inc
+include nginx_plus/Makefile.inc
+include nsd/Makefile.inc
+include ntpd/Makefile.inc
+include ovpn_status_log/Makefile.inc
+include phpfpm/Makefile.inc
+include portcheck/Makefile.inc
+include postfix/Makefile.inc
+include postgres/Makefile.inc
+include powerdns/Makefile.inc
+include proxysql/Makefile.inc
+include puppet/Makefile.inc
+include rabbitmq/Makefile.inc
+include redis/Makefile.inc
+include rethinkdbs/Makefile.inc
+include retroshare/Makefile.inc
+include samba/Makefile.inc
+include sensors/Makefile.inc
+include smartd_log/Makefile.inc
+include spigotmc/Makefile.inc
+include springboot/Makefile.inc
+include squid/Makefile.inc
+include tomcat/Makefile.inc
+include traefik/Makefile.inc
+include unbound/Makefile.inc
+include uwsgi/Makefile.inc
+include varnish/Makefile.inc
+include w1sensor/Makefile.inc
+include web_log/Makefile.inc
+
pythonmodulesdir=$(pythondir)/python_modules
dist_pythonmodules_DATA = \
python_modules/__init__.py \
- python_modules/base.py \
$(NULL)
basesdir=$(pythonmodulesdir)/bases
@@ -95,6 +132,9 @@ dist_third_party_DATA = \
python_modules/third_party/__init__.py \
python_modules/third_party/ordereddict.py \
python_modules/third_party/lm_sensors.py \
+ python_modules/third_party/mcrcon.py \
+ python_modules/third_party/boinc_client.py \
+ python_modules/third_party/monotonic.py \
$(NULL)
pythonyaml2dir=$(pythonmodulesdir)/pyyaml2
diff --git a/collectors/python.d.plugin/Makefile.in b/collectors/python.d.plugin/Makefile.in
new file mode 100644
index 000000000..ca2743d58
--- /dev/null
+++ b/collectors/python.d.plugin/Makefile.in
@@ -0,0 +1,1987 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(top_srcdir)/build/subst.inc \
+ $(srcdir)/adaptec_raid/Makefile.inc \
+ $(srcdir)/apache/Makefile.inc $(srcdir)/beanstalk/Makefile.inc \
+ $(srcdir)/bind_rndc/Makefile.inc $(srcdir)/boinc/Makefile.inc \
+ $(srcdir)/ceph/Makefile.inc $(srcdir)/chrony/Makefile.inc \
+ $(srcdir)/couchdb/Makefile.inc $(srcdir)/cpufreq/Makefile.inc \
+ $(srcdir)/cpuidle/Makefile.inc $(srcdir)/dnsdist/Makefile.inc \
+ $(srcdir)/dns_query_time/Makefile.inc \
+ $(srcdir)/dockerd/Makefile.inc $(srcdir)/dovecot/Makefile.inc \
+ $(srcdir)/elasticsearch/Makefile.inc \
+ $(srcdir)/example/Makefile.inc $(srcdir)/exim/Makefile.inc \
+ $(srcdir)/fail2ban/Makefile.inc \
+ $(srcdir)/freeradius/Makefile.inc \
+ $(srcdir)/go_expvar/Makefile.inc \
+ $(srcdir)/haproxy/Makefile.inc $(srcdir)/hddtemp/Makefile.inc \
+ $(srcdir)/httpcheck/Makefile.inc \
+ $(srcdir)/icecast/Makefile.inc $(srcdir)/ipfs/Makefile.inc \
+ $(srcdir)/isc_dhcpd/Makefile.inc \
+ $(srcdir)/linux_power_supply/Makefile.inc \
+ $(srcdir)/litespeed/Makefile.inc $(srcdir)/logind/Makefile.inc \
+ $(srcdir)/mdstat/Makefile.inc $(srcdir)/megacli/Makefile.inc \
+ $(srcdir)/memcached/Makefile.inc \
+ $(srcdir)/mongodb/Makefile.inc $(srcdir)/monit/Makefile.inc \
+ $(srcdir)/mysql/Makefile.inc $(srcdir)/nginx/Makefile.inc \
+ $(srcdir)/nginx_plus/Makefile.inc $(srcdir)/nsd/Makefile.inc \
+ $(srcdir)/ntpd/Makefile.inc \
+ $(srcdir)/ovpn_status_log/Makefile.inc \
+ $(srcdir)/phpfpm/Makefile.inc $(srcdir)/portcheck/Makefile.inc \
+ $(srcdir)/postfix/Makefile.inc $(srcdir)/postgres/Makefile.inc \
+ $(srcdir)/powerdns/Makefile.inc \
+ $(srcdir)/proxysql/Makefile.inc $(srcdir)/puppet/Makefile.inc \
+ $(srcdir)/rabbitmq/Makefile.inc $(srcdir)/redis/Makefile.inc \
+ $(srcdir)/rethinkdbs/Makefile.inc \
+ $(srcdir)/retroshare/Makefile.inc $(srcdir)/samba/Makefile.inc \
+ $(srcdir)/sensors/Makefile.inc \
+ $(srcdir)/smartd_log/Makefile.inc \
+ $(srcdir)/spigotmc/Makefile.inc \
+ $(srcdir)/springboot/Makefile.inc $(srcdir)/squid/Makefile.inc \
+ $(srcdir)/tomcat/Makefile.inc $(srcdir)/traefik/Makefile.inc \
+ $(srcdir)/unbound/Makefile.inc $(srcdir)/uwsgi/Makefile.inc \
+ $(srcdir)/varnish/Makefile.inc $(srcdir)/w1sensor/Makefile.inc \
+ $(srcdir)/web_log/Makefile.inc $(srcdir)/Makefile.in \
+ $(srcdir)/Makefile.am $(dist_plugins_SCRIPTS) \
+ $(dist_python_SCRIPTS) $(dist_bases_DATA) \
+ $(dist_bases_framework_services_DATA) $(dist_libconfig_DATA) \
+ $(dist_noinst_DATA) $(dist_python_DATA) \
+ $(dist_python_urllib3_DATA) \
+ $(dist_python_urllib3_backports_DATA) \
+ $(dist_python_urllib3_contrib_DATA) \
+ $(dist_python_urllib3_packages_DATA) \
+ $(dist_python_urllib3_securetransport_DATA) \
+ $(dist_python_urllib3_ssl_match_hostname_DATA) \
+ $(dist_python_urllib3_util_DATA) $(dist_pythonconfig_DATA) \
+ $(dist_pythonmodules_DATA) $(dist_pythonyaml2_DATA) \
+ $(dist_pythonyaml3_DATA) $(dist_third_party_DATA) \
+ $(dist_userpythonconfig_DATA)
+subdir = collectors/python.d.plugin
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(pythondir)" \
+ "$(DESTDIR)$(basesdir)" \
+ "$(DESTDIR)$(bases_framework_servicesdir)" \
+ "$(DESTDIR)$(libconfigdir)" "$(DESTDIR)$(pythondir)" \
+ "$(DESTDIR)$(python_urllib3dir)" \
+ "$(DESTDIR)$(python_urllib3_backportsdir)" \
+ "$(DESTDIR)$(python_urllib3_contribdir)" \
+ "$(DESTDIR)$(python_urllib3_packagesdir)" \
+ "$(DESTDIR)$(python_urllib3_securetransportdir)" \
+ "$(DESTDIR)$(python_urllib3_ssl_match_hostnamedir)" \
+ "$(DESTDIR)$(python_urllib3_utildir)" \
+ "$(DESTDIR)$(pythonconfigdir)" "$(DESTDIR)$(pythonmodulesdir)" \
+ "$(DESTDIR)$(pythonyaml2dir)" "$(DESTDIR)$(pythonyaml3dir)" \
+ "$(DESTDIR)$(third_partydir)" \
+ "$(DESTDIR)$(userpythonconfigdir)"
+SCRIPTS = $(dist_plugins_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_bases_DATA) $(dist_bases_framework_services_DATA) \
+ $(dist_libconfig_DATA) $(dist_noinst_DATA) $(dist_python_DATA) \
+ $(dist_python_urllib3_DATA) \
+ $(dist_python_urllib3_backports_DATA) \
+ $(dist_python_urllib3_contrib_DATA) \
+ $(dist_python_urllib3_packages_DATA) \
+ $(dist_python_urllib3_securetransport_DATA) \
+ $(dist_python_urllib3_ssl_match_hostname_DATA) \
+ $(dist_python_urllib3_util_DATA) $(dist_pythonconfig_DATA) \
+ $(dist_pythonmodules_DATA) $(dist_pythonyaml2_DATA) \
+ $(dist_pythonyaml3_DATA) $(dist_third_party_DATA) \
+ $(dist_userpythonconfig_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+CLEANFILES = \
+ python.d.plugin \
+ $(NULL)
+
+SUFFIXES = .in
+dist_libconfig_DATA = \
+ python.d.conf \
+ $(NULL)
+
+dist_plugins_SCRIPTS = \
+ python.d.plugin \
+ $(NULL)
+
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA = python.d.plugin.in README.md $(NULL) \
+ adaptec_raid/README.md adaptec_raid/Makefile.inc \
+ apache/README.md apache/Makefile.inc beanstalk/README.md \
+ beanstalk/Makefile.inc bind_rndc/README.md \
+ bind_rndc/Makefile.inc boinc/README.md boinc/Makefile.inc \
+ ceph/README.md ceph/Makefile.inc chrony/README.md \
+ chrony/Makefile.inc couchdb/README.md couchdb/Makefile.inc \
+ cpufreq/README.md cpufreq/Makefile.inc cpuidle/README.md \
+ cpuidle/Makefile.inc dnsdist/README.md dnsdist/Makefile.inc \
+ dns_query_time/README.md dns_query_time/Makefile.inc \
+ dockerd/README.md dockerd/Makefile.inc dovecot/README.md \
+ dovecot/Makefile.inc elasticsearch/README.md \
+ elasticsearch/Makefile.inc example/README.md \
+ example/Makefile.inc exim/README.md exim/Makefile.inc \
+ fail2ban/README.md fail2ban/Makefile.inc freeradius/README.md \
+ freeradius/Makefile.inc go_expvar/README.md \
+ go_expvar/Makefile.inc haproxy/README.md haproxy/Makefile.inc \
+ hddtemp/README.md hddtemp/Makefile.inc httpcheck/README.md \
+ httpcheck/Makefile.inc icecast/README.md icecast/Makefile.inc \
+ ipfs/README.md ipfs/Makefile.inc isc_dhcpd/README.md \
+ isc_dhcpd/Makefile.inc linux_power_supply/README.md \
+ linux_power_supply/Makefile.inc litespeed/README.md \
+ litespeed/Makefile.inc logind/README.md logind/Makefile.inc \
+ mdstat/README.md mdstat/Makefile.inc megacli/README.md \
+ megacli/Makefile.inc memcached/README.md \
+ memcached/Makefile.inc mongodb/README.md mongodb/Makefile.inc \
+ monit/README.md monit/Makefile.inc mysql/README.md \
+ mysql/Makefile.inc nginx/README.md nginx/Makefile.inc \
+ nginx_plus/README.md nginx_plus/Makefile.inc nsd/README.md \
+ nsd/Makefile.inc ntpd/README.md ntpd/Makefile.inc \
+ ovpn_status_log/README.md ovpn_status_log/Makefile.inc \
+ phpfpm/README.md phpfpm/Makefile.inc portcheck/README.md \
+ portcheck/Makefile.inc postfix/README.md postfix/Makefile.inc \
+ postgres/README.md postgres/Makefile.inc powerdns/README.md \
+ powerdns/Makefile.inc proxysql/README.md proxysql/Makefile.inc \
+ puppet/README.md puppet/Makefile.inc rabbitmq/README.md \
+ rabbitmq/Makefile.inc redis/README.md redis/Makefile.inc \
+ rethinkdbs/README.md rethinkdbs/Makefile.inc \
+ retroshare/README.md retroshare/Makefile.inc samba/README.md \
+ samba/Makefile.inc sensors/README.md sensors/Makefile.inc \
+ smartd_log/README.md smartd_log/Makefile.inc \
+ spigotmc/README.md spigotmc/Makefile.inc springboot/README.md \
+ springboot/Makefile.inc squid/README.md squid/Makefile.inc \
+ tomcat/README.md tomcat/Makefile.inc traefik/README.md \
+ traefik/Makefile.inc unbound/README.md unbound/Makefile.inc \
+ uwsgi/README.md uwsgi/Makefile.inc varnish/README.md \
+ varnish/Makefile.inc w1sensor/README.md w1sensor/Makefile.inc \
+ web_log/README.md web_log/Makefile.inc
+dist_python_SCRIPTS = \
+ $(NULL)
+
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+
+# install these files
+dist_python_DATA = $(NULL) adaptec_raid/adaptec_raid.chart.py \
+ apache/apache.chart.py beanstalk/beanstalk.chart.py \
+ bind_rndc/bind_rndc.chart.py boinc/boinc.chart.py \
+ ceph/ceph.chart.py chrony/chrony.chart.py \
+ couchdb/couchdb.chart.py cpufreq/cpufreq.chart.py \
+ cpuidle/cpuidle.chart.py dnsdist/dnsdist.chart.py \
+ dns_query_time/dns_query_time.chart.py \
+ dockerd/dockerd.chart.py dovecot/dovecot.chart.py \
+ elasticsearch/elasticsearch.chart.py example/example.chart.py \
+ exim/exim.chart.py fail2ban/fail2ban.chart.py \
+ freeradius/freeradius.chart.py go_expvar/go_expvar.chart.py \
+ haproxy/haproxy.chart.py hddtemp/hddtemp.chart.py \
+ httpcheck/httpcheck.chart.py icecast/icecast.chart.py \
+ ipfs/ipfs.chart.py isc_dhcpd/isc_dhcpd.chart.py \
+ linux_power_supply/linux_power_supply.chart.py \
+ litespeed/litespeed.chart.py logind/logind.chart.py \
+ mdstat/mdstat.chart.py megacli/megacli.chart.py \
+ memcached/memcached.chart.py mongodb/mongodb.chart.py \
+ monit/monit.chart.py mysql/mysql.chart.py nginx/nginx.chart.py \
+ nginx_plus/nginx_plus.chart.py nsd/nsd.chart.py \
+ ntpd/ntpd.chart.py ovpn_status_log/ovpn_status_log.chart.py \
+ phpfpm/phpfpm.chart.py portcheck/portcheck.chart.py \
+ postfix/postfix.chart.py postgres/postgres.chart.py \
+ powerdns/powerdns.chart.py proxysql/proxysql.chart.py \
+ puppet/puppet.chart.py rabbitmq/rabbitmq.chart.py \
+ redis/redis.chart.py rethinkdbs/rethinkdbs.chart.py \
+ retroshare/retroshare.chart.py samba/samba.chart.py \
+ sensors/sensors.chart.py smartd_log/smartd_log.chart.py \
+ spigotmc/spigotmc.chart.py springboot/springboot.chart.py \
+ squid/squid.chart.py tomcat/tomcat.chart.py \
+ traefik/traefik.chart.py unbound/unbound.chart.py \
+ uwsgi/uwsgi.chart.py varnish/varnish.chart.py \
+ w1sensor/w1sensor.chart.py web_log/web_log.chart.py
+userpythonconfigdir = $(configdir)/python.d
+dist_userpythonconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
+pythonconfigdir = $(libconfigdir)/python.d
+dist_pythonconfig_DATA = $(top_srcdir)/installer/.keep $(NULL) \
+ adaptec_raid/adaptec_raid.conf apache/apache.conf \
+ beanstalk/beanstalk.conf bind_rndc/bind_rndc.conf \
+ boinc/boinc.conf ceph/ceph.conf chrony/chrony.conf \
+ couchdb/couchdb.conf cpufreq/cpufreq.conf cpuidle/cpuidle.conf \
+ dnsdist/dnsdist.conf dns_query_time/dns_query_time.conf \
+ dockerd/dockerd.conf dovecot/dovecot.conf \
+ elasticsearch/elasticsearch.conf example/example.conf \
+ exim/exim.conf fail2ban/fail2ban.conf \
+ freeradius/freeradius.conf go_expvar/go_expvar.conf \
+ haproxy/haproxy.conf hddtemp/hddtemp.conf \
+ httpcheck/httpcheck.conf icecast/icecast.conf ipfs/ipfs.conf \
+ isc_dhcpd/isc_dhcpd.conf \
+ linux_power_supply/linux_power_supply.conf \
+ litespeed/litespeed.conf logind/logind.conf mdstat/mdstat.conf \
+ megacli/megacli.conf memcached/memcached.conf \
+ mongodb/mongodb.conf monit/monit.conf mysql/mysql.conf \
+ nginx/nginx.conf nginx_plus/nginx_plus.conf nsd/nsd.conf \
+ ntpd/ntpd.conf ovpn_status_log/ovpn_status_log.conf \
+ phpfpm/phpfpm.conf portcheck/portcheck.conf \
+ postfix/postfix.conf postgres/postgres.conf \
+ powerdns/powerdns.conf proxysql/proxysql.conf \
+ puppet/puppet.conf rabbitmq/rabbitmq.conf redis/redis.conf \
+ rethinkdbs/rethinkdbs.conf retroshare/retroshare.conf \
+ samba/samba.conf sensors/sensors.conf \
+ smartd_log/smartd_log.conf spigotmc/spigotmc.conf \
+ springboot/springboot.conf squid/squid.conf tomcat/tomcat.conf \
+ traefik/traefik.conf unbound/unbound.conf uwsgi/uwsgi.conf \
+ varnish/varnish.conf w1sensor/w1sensor.conf \
+ web_log/web_log.conf
+pythonmodulesdir = $(pythondir)/python_modules
+dist_pythonmodules_DATA = \
+ python_modules/__init__.py \
+ $(NULL)
+
+basesdir = $(pythonmodulesdir)/bases
+dist_bases_DATA = \
+ python_modules/bases/__init__.py \
+ python_modules/bases/charts.py \
+ python_modules/bases/collection.py \
+ python_modules/bases/loaders.py \
+ python_modules/bases/loggers.py \
+ $(NULL)
+
+bases_framework_servicesdir = $(basesdir)/FrameworkServices
+dist_bases_framework_services_DATA = \
+ python_modules/bases/FrameworkServices/__init__.py \
+ python_modules/bases/FrameworkServices/ExecutableService.py \
+ python_modules/bases/FrameworkServices/LogService.py \
+ python_modules/bases/FrameworkServices/MySQLService.py \
+ python_modules/bases/FrameworkServices/SimpleService.py \
+ python_modules/bases/FrameworkServices/SocketService.py \
+ python_modules/bases/FrameworkServices/UrlService.py \
+ $(NULL)
+
+third_partydir = $(pythonmodulesdir)/third_party
+dist_third_party_DATA = \
+ python_modules/third_party/__init__.py \
+ python_modules/third_party/ordereddict.py \
+ python_modules/third_party/lm_sensors.py \
+ python_modules/third_party/mcrcon.py \
+ python_modules/third_party/boinc_client.py \
+ python_modules/third_party/monotonic.py \
+ $(NULL)
+
+pythonyaml2dir = $(pythonmodulesdir)/pyyaml2
+dist_pythonyaml2_DATA = \
+ python_modules/pyyaml2/__init__.py \
+ python_modules/pyyaml2/composer.py \
+ python_modules/pyyaml2/constructor.py \
+ python_modules/pyyaml2/cyaml.py \
+ python_modules/pyyaml2/dumper.py \
+ python_modules/pyyaml2/emitter.py \
+ python_modules/pyyaml2/error.py \
+ python_modules/pyyaml2/events.py \
+ python_modules/pyyaml2/loader.py \
+ python_modules/pyyaml2/nodes.py \
+ python_modules/pyyaml2/parser.py \
+ python_modules/pyyaml2/reader.py \
+ python_modules/pyyaml2/representer.py \
+ python_modules/pyyaml2/resolver.py \
+ python_modules/pyyaml2/scanner.py \
+ python_modules/pyyaml2/serializer.py \
+ python_modules/pyyaml2/tokens.py \
+ $(NULL)
+
+pythonyaml3dir = $(pythonmodulesdir)/pyyaml3
+dist_pythonyaml3_DATA = \
+ python_modules/pyyaml3/__init__.py \
+ python_modules/pyyaml3/composer.py \
+ python_modules/pyyaml3/constructor.py \
+ python_modules/pyyaml3/cyaml.py \
+ python_modules/pyyaml3/dumper.py \
+ python_modules/pyyaml3/emitter.py \
+ python_modules/pyyaml3/error.py \
+ python_modules/pyyaml3/events.py \
+ python_modules/pyyaml3/loader.py \
+ python_modules/pyyaml3/nodes.py \
+ python_modules/pyyaml3/parser.py \
+ python_modules/pyyaml3/reader.py \
+ python_modules/pyyaml3/representer.py \
+ python_modules/pyyaml3/resolver.py \
+ python_modules/pyyaml3/scanner.py \
+ python_modules/pyyaml3/serializer.py \
+ python_modules/pyyaml3/tokens.py \
+ $(NULL)
+
+python_urllib3dir = $(pythonmodulesdir)/urllib3
+dist_python_urllib3_DATA = \
+ python_modules/urllib3/__init__.py \
+ python_modules/urllib3/_collections.py \
+ python_modules/urllib3/connection.py \
+ python_modules/urllib3/connectionpool.py \
+ python_modules/urllib3/exceptions.py \
+ python_modules/urllib3/fields.py \
+ python_modules/urllib3/filepost.py \
+ python_modules/urllib3/response.py \
+ python_modules/urllib3/poolmanager.py \
+ python_modules/urllib3/request.py \
+ $(NULL)
+
+python_urllib3_utildir = $(python_urllib3dir)/util
+dist_python_urllib3_util_DATA = \
+ python_modules/urllib3/util/__init__.py \
+ python_modules/urllib3/util/connection.py \
+ python_modules/urllib3/util/request.py \
+ python_modules/urllib3/util/response.py \
+ python_modules/urllib3/util/retry.py \
+ python_modules/urllib3/util/selectors.py \
+ python_modules/urllib3/util/ssl_.py \
+ python_modules/urllib3/util/timeout.py \
+ python_modules/urllib3/util/url.py \
+ python_modules/urllib3/util/wait.py \
+ $(NULL)
+
+python_urllib3_packagesdir = $(python_urllib3dir)/packages
+dist_python_urllib3_packages_DATA = \
+ python_modules/urllib3/packages/__init__.py \
+ python_modules/urllib3/packages/ordered_dict.py \
+ python_modules/urllib3/packages/six.py \
+ $(NULL)
+
+python_urllib3_backportsdir = $(python_urllib3_packagesdir)/backports
+dist_python_urllib3_backports_DATA = \
+ python_modules/urllib3/packages/backports/__init__.py \
+ python_modules/urllib3/packages/backports/makefile.py \
+ $(NULL)
+
+python_urllib3_ssl_match_hostnamedir = $(python_urllib3_packagesdir)/ssl_match_hostname
+dist_python_urllib3_ssl_match_hostname_DATA = \
+ python_modules/urllib3/packages/ssl_match_hostname/__init__.py \
+ python_modules/urllib3/packages/ssl_match_hostname/_implementation.py \
+ $(NULL)
+
+python_urllib3_contribdir = $(python_urllib3dir)/contrib
+dist_python_urllib3_contrib_DATA = \
+ python_modules/urllib3/contrib/__init__.py \
+ python_modules/urllib3/contrib/appengine.py \
+ python_modules/urllib3/contrib/ntlmpool.py \
+ python_modules/urllib3/contrib/pyopenssl.py \
+ python_modules/urllib3/contrib/securetransport.py \
+ python_modules/urllib3/contrib/socks.py \
+ $(NULL)
+
+python_urllib3_securetransportdir = $(python_urllib3_contribdir)/_securetransport
+dist_python_urllib3_securetransport_DATA = \
+ python_modules/urllib3/contrib/_securetransport/__init__.py \
+ python_modules/urllib3/contrib/_securetransport/bindings.py \
+ python_modules/urllib3/contrib/_securetransport/low_level.py \
+ $(NULL)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .in
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/build/subst.inc $(srcdir)/adaptec_raid/Makefile.inc $(srcdir)/apache/Makefile.inc $(srcdir)/beanstalk/Makefile.inc $(srcdir)/bind_rndc/Makefile.inc $(srcdir)/boinc/Makefile.inc $(srcdir)/ceph/Makefile.inc $(srcdir)/chrony/Makefile.inc $(srcdir)/couchdb/Makefile.inc $(srcdir)/cpufreq/Makefile.inc $(srcdir)/cpuidle/Makefile.inc $(srcdir)/dnsdist/Makefile.inc $(srcdir)/dns_query_time/Makefile.inc $(srcdir)/dockerd/Makefile.inc $(srcdir)/dovecot/Makefile.inc $(srcdir)/elasticsearch/Makefile.inc $(srcdir)/example/Makefile.inc $(srcdir)/exim/Makefile.inc $(srcdir)/fail2ban/Makefile.inc $(srcdir)/freeradius/Makefile.inc $(srcdir)/go_expvar/Makefile.inc $(srcdir)/haproxy/Makefile.inc $(srcdir)/hddtemp/Makefile.inc $(srcdir)/httpcheck/Makefile.inc $(srcdir)/icecast/Makefile.inc $(srcdir)/ipfs/Makefile.inc $(srcdir)/isc_dhcpd/Makefile.inc $(srcdir)/linux_power_supply/Makefile.inc $(srcdir)/litespeed/Makefile.inc $(srcdir)/logind/Makefile.inc $(srcdir)/mdstat/Makefile.inc $(srcdir)/megacli/Makefile.inc $(srcdir)/memcached/Makefile.inc $(srcdir)/mongodb/Makefile.inc $(srcdir)/monit/Makefile.inc $(srcdir)/mysql/Makefile.inc $(srcdir)/nginx/Makefile.inc $(srcdir)/nginx_plus/Makefile.inc $(srcdir)/nsd/Makefile.inc $(srcdir)/ntpd/Makefile.inc $(srcdir)/ovpn_status_log/Makefile.inc $(srcdir)/phpfpm/Makefile.inc $(srcdir)/portcheck/Makefile.inc $(srcdir)/postfix/Makefile.inc $(srcdir)/postgres/Makefile.inc $(srcdir)/powerdns/Makefile.inc $(srcdir)/proxysql/Makefile.inc $(srcdir)/puppet/Makefile.inc $(srcdir)/rabbitmq/Makefile.inc $(srcdir)/redis/Makefile.inc $(srcdir)/rethinkdbs/Makefile.inc $(srcdir)/retroshare/Makefile.inc $(srcdir)/samba/Makefile.inc $(srcdir)/sensors/Makefile.inc $(srcdir)/smartd_log/Makefile.inc $(srcdir)/spigotmc/Makefile.inc $(srcdir)/springboot/Makefile.inc $(srcdir)/squid/Makefile.inc $(srcdir)/tomcat/Makefile.inc $(srcdir)/traefik/Makefile.inc $(srcdir)/unbound/Makefile.inc $(srcdir)/uwsgi/Makefile.inc $(srcdir)/varnish/Makefile.inc $(srcdir)/w1sensor/Makefile.inc $(srcdir)/web_log/Makefile.inc $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/python.d.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/python.d.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(top_srcdir)/build/subst.inc $(srcdir)/adaptec_raid/Makefile.inc $(srcdir)/apache/Makefile.inc $(srcdir)/beanstalk/Makefile.inc $(srcdir)/bind_rndc/Makefile.inc $(srcdir)/boinc/Makefile.inc $(srcdir)/ceph/Makefile.inc $(srcdir)/chrony/Makefile.inc $(srcdir)/couchdb/Makefile.inc $(srcdir)/cpufreq/Makefile.inc $(srcdir)/cpuidle/Makefile.inc $(srcdir)/dnsdist/Makefile.inc $(srcdir)/dns_query_time/Makefile.inc $(srcdir)/dockerd/Makefile.inc $(srcdir)/dovecot/Makefile.inc $(srcdir)/elasticsearch/Makefile.inc $(srcdir)/example/Makefile.inc $(srcdir)/exim/Makefile.inc $(srcdir)/fail2ban/Makefile.inc $(srcdir)/freeradius/Makefile.inc $(srcdir)/go_expvar/Makefile.inc $(srcdir)/haproxy/Makefile.inc $(srcdir)/hddtemp/Makefile.inc $(srcdir)/httpcheck/Makefile.inc $(srcdir)/icecast/Makefile.inc $(srcdir)/ipfs/Makefile.inc $(srcdir)/isc_dhcpd/Makefile.inc $(srcdir)/linux_power_supply/Makefile.inc $(srcdir)/litespeed/Makefile.inc $(srcdir)/logind/Makefile.inc $(srcdir)/mdstat/Makefile.inc $(srcdir)/megacli/Makefile.inc $(srcdir)/memcached/Makefile.inc $(srcdir)/mongodb/Makefile.inc $(srcdir)/monit/Makefile.inc $(srcdir)/mysql/Makefile.inc $(srcdir)/nginx/Makefile.inc $(srcdir)/nginx_plus/Makefile.inc $(srcdir)/nsd/Makefile.inc $(srcdir)/ntpd/Makefile.inc $(srcdir)/ovpn_status_log/Makefile.inc $(srcdir)/phpfpm/Makefile.inc $(srcdir)/portcheck/Makefile.inc $(srcdir)/postfix/Makefile.inc $(srcdir)/postgres/Makefile.inc $(srcdir)/powerdns/Makefile.inc $(srcdir)/proxysql/Makefile.inc $(srcdir)/puppet/Makefile.inc $(srcdir)/rabbitmq/Makefile.inc $(srcdir)/redis/Makefile.inc $(srcdir)/rethinkdbs/Makefile.inc $(srcdir)/retroshare/Makefile.inc $(srcdir)/samba/Makefile.inc $(srcdir)/sensors/Makefile.inc $(srcdir)/smartd_log/Makefile.inc $(srcdir)/spigotmc/Makefile.inc $(srcdir)/springboot/Makefile.inc $(srcdir)/squid/Makefile.inc $(srcdir)/tomcat/Makefile.inc $(srcdir)/traefik/Makefile.inc $(srcdir)/unbound/Makefile.inc $(srcdir)/uwsgi/Makefile.inc $(srcdir)/varnish/Makefile.inc $(srcdir)/w1sensor/Makefile.inc $(srcdir)/web_log/Makefile.inc:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-dist_pluginsSCRIPTS: $(dist_plugins_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @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; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pluginsdir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pluginsdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dist_pluginsSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_plugins_SCRIPTS)'; test -n "$(pluginsdir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(pluginsdir)'; $(am__uninstall_files_from_dir)
+install-dist_pythonSCRIPTS: $(dist_python_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @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; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pythondir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pythondir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dist_pythonSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_python_SCRIPTS)'; test -n "$(pythondir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(pythondir)'; $(am__uninstall_files_from_dir)
+install-dist_basesDATA: $(dist_bases_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_bases_DATA)'; test -n "$(basesdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(basesdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(basesdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(basesdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(basesdir)" || exit $$?; \
+ done
+
+uninstall-dist_basesDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_bases_DATA)'; test -n "$(basesdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(basesdir)'; $(am__uninstall_files_from_dir)
+install-dist_bases_framework_servicesDATA: $(dist_bases_framework_services_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_bases_framework_services_DATA)'; test -n "$(bases_framework_servicesdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bases_framework_servicesdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bases_framework_servicesdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(bases_framework_servicesdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(bases_framework_servicesdir)" || exit $$?; \
+ done
+
+uninstall-dist_bases_framework_servicesDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_bases_framework_services_DATA)'; test -n "$(bases_framework_servicesdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(bases_framework_servicesdir)'; $(am__uninstall_files_from_dir)
+install-dist_libconfigDATA: $(dist_libconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_libconfig_DATA)'; test -n "$(libconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(libconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(libconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_libconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_libconfig_DATA)'; test -n "$(libconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(libconfigdir)'; $(am__uninstall_files_from_dir)
+install-dist_pythonDATA: $(dist_python_DATA)
+ @$(NORMAL_INSTALL)
+ @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"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pythondir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pythondir)" || exit $$?; \
+ done
+
+uninstall-dist_pythonDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_python_DATA)'; test -n "$(pythondir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pythondir)'; $(am__uninstall_files_from_dir)
+install-dist_python_urllib3DATA: $(dist_python_urllib3_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_python_urllib3_DATA)'; test -n "$(python_urllib3dir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(python_urllib3dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(python_urllib3dir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(python_urllib3dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(python_urllib3dir)" || exit $$?; \
+ done
+
+uninstall-dist_python_urllib3DATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_python_urllib3_DATA)'; test -n "$(python_urllib3dir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(python_urllib3dir)'; $(am__uninstall_files_from_dir)
+install-dist_python_urllib3_backportsDATA: $(dist_python_urllib3_backports_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_python_urllib3_backports_DATA)'; test -n "$(python_urllib3_backportsdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(python_urllib3_backportsdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(python_urllib3_backportsdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(python_urllib3_backportsdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(python_urllib3_backportsdir)" || exit $$?; \
+ done
+
+uninstall-dist_python_urllib3_backportsDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_python_urllib3_backports_DATA)'; test -n "$(python_urllib3_backportsdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(python_urllib3_backportsdir)'; $(am__uninstall_files_from_dir)
+install-dist_python_urllib3_contribDATA: $(dist_python_urllib3_contrib_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_python_urllib3_contrib_DATA)'; test -n "$(python_urllib3_contribdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(python_urllib3_contribdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(python_urllib3_contribdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(python_urllib3_contribdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(python_urllib3_contribdir)" || exit $$?; \
+ done
+
+uninstall-dist_python_urllib3_contribDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_python_urllib3_contrib_DATA)'; test -n "$(python_urllib3_contribdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(python_urllib3_contribdir)'; $(am__uninstall_files_from_dir)
+install-dist_python_urllib3_packagesDATA: $(dist_python_urllib3_packages_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_python_urllib3_packages_DATA)'; test -n "$(python_urllib3_packagesdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(python_urllib3_packagesdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(python_urllib3_packagesdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(python_urllib3_packagesdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(python_urllib3_packagesdir)" || exit $$?; \
+ done
+
+uninstall-dist_python_urllib3_packagesDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_python_urllib3_packages_DATA)'; test -n "$(python_urllib3_packagesdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(python_urllib3_packagesdir)'; $(am__uninstall_files_from_dir)
+install-dist_python_urllib3_securetransportDATA: $(dist_python_urllib3_securetransport_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_python_urllib3_securetransport_DATA)'; test -n "$(python_urllib3_securetransportdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(python_urllib3_securetransportdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(python_urllib3_securetransportdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(python_urllib3_securetransportdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(python_urllib3_securetransportdir)" || exit $$?; \
+ done
+
+uninstall-dist_python_urllib3_securetransportDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_python_urllib3_securetransport_DATA)'; test -n "$(python_urllib3_securetransportdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(python_urllib3_securetransportdir)'; $(am__uninstall_files_from_dir)
+install-dist_python_urllib3_ssl_match_hostnameDATA: $(dist_python_urllib3_ssl_match_hostname_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_python_urllib3_ssl_match_hostname_DATA)'; test -n "$(python_urllib3_ssl_match_hostnamedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(python_urllib3_ssl_match_hostnamedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(python_urllib3_ssl_match_hostnamedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(python_urllib3_ssl_match_hostnamedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(python_urllib3_ssl_match_hostnamedir)" || exit $$?; \
+ done
+
+uninstall-dist_python_urllib3_ssl_match_hostnameDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_python_urllib3_ssl_match_hostname_DATA)'; test -n "$(python_urllib3_ssl_match_hostnamedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(python_urllib3_ssl_match_hostnamedir)'; $(am__uninstall_files_from_dir)
+install-dist_python_urllib3_utilDATA: $(dist_python_urllib3_util_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_python_urllib3_util_DATA)'; test -n "$(python_urllib3_utildir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(python_urllib3_utildir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(python_urllib3_utildir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(python_urllib3_utildir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(python_urllib3_utildir)" || exit $$?; \
+ done
+
+uninstall-dist_python_urllib3_utilDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_python_urllib3_util_DATA)'; test -n "$(python_urllib3_utildir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(python_urllib3_utildir)'; $(am__uninstall_files_from_dir)
+install-dist_pythonconfigDATA: $(dist_pythonconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @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"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pythonconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pythonconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_pythonconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @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)
+install-dist_pythonmodulesDATA: $(dist_pythonmodules_DATA)
+ @$(NORMAL_INSTALL)
+ @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"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pythonmodulesdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pythonmodulesdir)" || exit $$?; \
+ done
+
+uninstall-dist_pythonmodulesDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pythonmodules_DATA)'; test -n "$(pythonmodulesdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pythonmodulesdir)'; $(am__uninstall_files_from_dir)
+install-dist_pythonyaml2DATA: $(dist_pythonyaml2_DATA)
+ @$(NORMAL_INSTALL)
+ @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"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pythonyaml2dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pythonyaml2dir)" || exit $$?; \
+ done
+
+uninstall-dist_pythonyaml2DATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pythonyaml2_DATA)'; test -n "$(pythonyaml2dir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pythonyaml2dir)'; $(am__uninstall_files_from_dir)
+install-dist_pythonyaml3DATA: $(dist_pythonyaml3_DATA)
+ @$(NORMAL_INSTALL)
+ @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"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pythonyaml3dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pythonyaml3dir)" || exit $$?; \
+ done
+
+uninstall-dist_pythonyaml3DATA:
+ @$(NORMAL_UNINSTALL)
+ @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)
+install-dist_third_partyDATA: $(dist_third_party_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_third_party_DATA)'; test -n "$(third_partydir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(third_partydir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(third_partydir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(third_partydir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(third_partydir)" || exit $$?; \
+ done
+
+uninstall-dist_third_partyDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_third_party_DATA)'; test -n "$(third_partydir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(third_partydir)'; $(am__uninstall_files_from_dir)
+install-dist_userpythonconfigDATA: $(dist_userpythonconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_userpythonconfig_DATA)'; test -n "$(userpythonconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(userpythonconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(userpythonconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(userpythonconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(userpythonconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_userpythonconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_userpythonconfig_DATA)'; test -n "$(userpythonconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(userpythonconfigdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(basesdir)" "$(DESTDIR)$(bases_framework_servicesdir)" "$(DESTDIR)$(libconfigdir)" "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(python_urllib3dir)" "$(DESTDIR)$(python_urllib3_backportsdir)" "$(DESTDIR)$(python_urllib3_contribdir)" "$(DESTDIR)$(python_urllib3_packagesdir)" "$(DESTDIR)$(python_urllib3_securetransportdir)" "$(DESTDIR)$(python_urllib3_ssl_match_hostnamedir)" "$(DESTDIR)$(python_urllib3_utildir)" "$(DESTDIR)$(pythonconfigdir)" "$(DESTDIR)$(pythonmodulesdir)" "$(DESTDIR)$(pythonyaml2dir)" "$(DESTDIR)$(pythonyaml3dir)" "$(DESTDIR)$(third_partydir)" "$(DESTDIR)$(userpythonconfigdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_basesDATA \
+ install-dist_bases_framework_servicesDATA \
+ install-dist_libconfigDATA install-dist_pluginsSCRIPTS \
+ install-dist_pythonDATA install-dist_pythonSCRIPTS \
+ install-dist_python_urllib3DATA \
+ install-dist_python_urllib3_backportsDATA \
+ install-dist_python_urllib3_contribDATA \
+ install-dist_python_urllib3_packagesDATA \
+ install-dist_python_urllib3_securetransportDATA \
+ install-dist_python_urllib3_ssl_match_hostnameDATA \
+ install-dist_python_urllib3_utilDATA \
+ install-dist_pythonconfigDATA install-dist_pythonmodulesDATA \
+ install-dist_pythonyaml2DATA install-dist_pythonyaml3DATA \
+ install-dist_third_partyDATA install-dist_userpythonconfigDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_basesDATA \
+ uninstall-dist_bases_framework_servicesDATA \
+ uninstall-dist_libconfigDATA uninstall-dist_pluginsSCRIPTS \
+ uninstall-dist_pythonDATA uninstall-dist_pythonSCRIPTS \
+ uninstall-dist_python_urllib3DATA \
+ uninstall-dist_python_urllib3_backportsDATA \
+ uninstall-dist_python_urllib3_contribDATA \
+ uninstall-dist_python_urllib3_packagesDATA \
+ uninstall-dist_python_urllib3_securetransportDATA \
+ uninstall-dist_python_urllib3_ssl_match_hostnameDATA \
+ uninstall-dist_python_urllib3_utilDATA \
+ uninstall-dist_pythonconfigDATA \
+ uninstall-dist_pythonmodulesDATA \
+ uninstall-dist_pythonyaml2DATA uninstall-dist_pythonyaml3DATA \
+ uninstall-dist_third_partyDATA \
+ uninstall-dist_userpythonconfigDATA
+
+.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_basesDATA \
+ install-dist_bases_framework_servicesDATA \
+ install-dist_libconfigDATA install-dist_pluginsSCRIPTS \
+ install-dist_pythonDATA install-dist_pythonSCRIPTS \
+ install-dist_python_urllib3DATA \
+ install-dist_python_urllib3_backportsDATA \
+ install-dist_python_urllib3_contribDATA \
+ install-dist_python_urllib3_packagesDATA \
+ install-dist_python_urllib3_securetransportDATA \
+ install-dist_python_urllib3_ssl_match_hostnameDATA \
+ install-dist_python_urllib3_utilDATA \
+ install-dist_pythonconfigDATA install-dist_pythonmodulesDATA \
+ install-dist_pythonyaml2DATA install-dist_pythonyaml3DATA \
+ install-dist_third_partyDATA install-dist_userpythonconfigDATA \
+ 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_basesDATA \
+ uninstall-dist_bases_framework_servicesDATA \
+ uninstall-dist_libconfigDATA uninstall-dist_pluginsSCRIPTS \
+ uninstall-dist_pythonDATA uninstall-dist_pythonSCRIPTS \
+ uninstall-dist_python_urllib3DATA \
+ uninstall-dist_python_urllib3_backportsDATA \
+ uninstall-dist_python_urllib3_contribDATA \
+ uninstall-dist_python_urllib3_packagesDATA \
+ uninstall-dist_python_urllib3_securetransportDATA \
+ uninstall-dist_python_urllib3_ssl_match_hostnameDATA \
+ uninstall-dist_python_urllib3_utilDATA \
+ uninstall-dist_pythonconfigDATA \
+ uninstall-dist_pythonmodulesDATA \
+ uninstall-dist_pythonyaml2DATA uninstall-dist_pythonyaml3DATA \
+ uninstall-dist_third_partyDATA \
+ uninstall-dist_userpythonconfigDATA
+
+.in:
+ if sed \
+ -e 's#[@]localstatedir_POST@#$(localstatedir)#g' \
+ -e 's#[@]sbindir_POST@#$(sbindir)#g' \
+ -e 's#[@]sysconfdir_POST@#$(sysconfdir)#g' \
+ -e 's#[@]pythondir_POST@#$(pythondir)#g' \
+ -e 's#[@]configdir_POST@#$(configdir)#g' \
+ -e 's#[@]libconfigdir_POST@#$(libconfigdir)#g' \
+ -e 's#[@]cachedir_POST@#$(cachedir)#g' \
+ $< > $@.tmp; then \
+ mv "$@.tmp" "$@"; \
+ else \
+ rm -f "$@.tmp"; \
+ false; \
+ 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.
+.NOEXPORT:
diff --git a/collectors/python.d.plugin/README.md b/collectors/python.d.plugin/README.md
new file mode 100644
index 000000000..df24cd18f
--- /dev/null
+++ b/collectors/python.d.plugin/README.md
@@ -0,0 +1,198 @@
+# python.d.plugin
+
+`python.d.plugin` is a netdata external plugin. It is an **orchestrator** for data collection modules written in `python`.
+
+1. It runs as an independent process `ps fax` shows it
+2. It is started and stopped automatically by netdata
+3. It communicates with netdata via a unidirectional pipe (sending data to the netdata daemon)
+4. Supports any number of data collection **modules**
+5. Allows each **module** to have one or more data collection **jobs**
+6. Each **job** is collecting one or more metrics from a single data source
+
+
+## Disclaimer
+
+Every module should be compatible with python2 and python3.
+All third party libraries should be installed system-wide or in `python_modules` directory.
+Module configurations are written in YAML and **pyYAML is required**.
+
+Every configuration file must have one of two formats:
+
+- Configuration for only one job:
+
+```yaml
+update_every : 2 # update frequency
+retries : 1 # how many failures in update() is tolerated
+priority : 20000 # where it is shown on dashboard
+
+other_var1 : bla # variables passed to module
+other_var2 : alb
+```
+
+- Configuration for many jobs (ex. mysql):
+
+```yaml
+# module defaults:
+update_every : 2
+retries : 1
+priority : 20000
+
+local: # job name
+ update_every : 5 # job update frequency
+ other_var1 : some_val # module specific variable
+
+other_job:
+ priority : 5 # job position on dashboard
+ retries : 20 # job retries
+ other_var2 : val # module specific variable
+```
+
+`update_every`, `retries`, and `priority` are always optional.
+
+---
+
+## How to write a new module
+
+Writing new python module is simple. You just need to remember to include 5 major things:
+- **ORDER** global list
+- **CHART** global dictionary
+- **Service** class
+- **_get_data** method
+- all code needs to be compatible with Python 2 (**≥ 2.7**) *and* 3 (**≥ 3.1**)
+
+If you plan to submit the module in a PR, make sure and go through the [PR checklist for new modules](https://github.com/netdata/netdata/wiki/New-Module-PR-Checklist) beforehand to make sure you have updated all the files you need to.
+
+### Global variables `ORDER` and `CHART`
+
+`ORDER` list should contain the order of chart ids. Example:
+```py
+ORDER = ['first_chart', 'second_chart', 'third_chart']
+```
+
+`CHART` dictionary is a little bit trickier. It should contain the chart definition in following format:
+```py
+CHART = {
+ id: {
+ 'options': [name, title, units, family, context, charttype],
+ 'lines': [
+ [unique_dimension_name, name, algorithm, multiplier, divisor]
+ ]}
+```
+
+All names are better explained in the [External Plugins](../) section.
+Parameters like `priority` and `update_every` are handled by `python.d.plugin`.
+
+### `Service` class
+
+Every module needs to implement its own `Service` class. This class should inherit from one of the framework classes:
+
+- `SimpleService`
+- `UrlService`
+- `SocketService`
+- `LogService`
+- `ExecutableService`
+
+Also it needs to invoke the parent class constructor in a specific way as well as assign global variables to class variables.
+
+Simple example:
+```py
+from base import UrlService
+class Service(UrlService):
+ def __init__(self, configuration=None, name=None):
+ UrlService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+```
+
+### `_get_data` collector/parser
+
+This method should grab raw data from `_get_raw_data`, parse it, and return a dictionary where keys are unique dimension names or `None` if no data is collected.
+
+Example:
+```py
+def _get_data(self):
+ try:
+ raw = self._get_raw_data().split(" ")
+ return {'active': int(raw[2])}
+ except (ValueError, AttributeError):
+ return None
+```
+
+More about framework classes
+============================
+
+Every framework class has some user-configurable variables which are specific to this particular class. Those variables should have default values initialized in the child class constructor.
+
+If module needs some additional user-configurable variable, it can be accessed from the `self.configuration` list and assigned in constructor or custom `check` method. Example:
+```py
+def __init__(self, configuration=None, name=None):
+ UrlService.__init__(self, configuration=configuration, name=name)
+ try:
+ self.baseurl = str(self.configuration['baseurl'])
+ except (KeyError, TypeError):
+ self.baseurl = "http://localhost:5001"
+```
+
+Classes implement `_get_raw_data` which should be used to grab raw data. This method usually returns a list of strings.
+
+### `SimpleService`
+
+_This is last resort class, if a new module cannot be written by using other framework class this one can be used._
+
+_Example: `mysql`, `sensors`_
+
+It is the lowest-level class which implements most of module logic, like:
+- threading
+- handling run times
+- chart formatting
+- logging
+- chart creation and updating
+
+### `LogService`
+
+_Examples: `apache_cache`, `nginx_log`_
+
+_Variable from config file_: `log_path`.
+
+Object created from this class reads new lines from file specified in `log_path` variable. It will check if file exists and is readable. Also `_get_raw_data` returns list of strings where each string is one line from file specified in `log_path`.
+
+### `ExecutableService`
+
+_Examples: `exim`, `postfix`_
+
+_Variable from config file_: `command`.
+
+This allows to execute a shell command in a secure way. It will check for invalid characters in `command` variable and won't proceed if there is one of:
+- '&'
+- '|'
+- ';'
+- '>'
+- '<'
+
+For additional security it uses python `subprocess.Popen` (without `shell=True` option) to execute command. Command can be specified with absolute or relative name. When using relative name, it will try to find `command` in `PATH` environment variable as well as in `/sbin` and `/usr/sbin`.
+
+`_get_raw_data` returns list of decoded lines returned by `command`.
+
+### UrlService
+
+_Examples: `apache`, `nginx`, `tomcat`_
+
+_Variables from config file_: `url`, `user`, `pass`.
+
+If data is grabbed by accessing service via HTTP protocol, this class can be used. It can handle HTTP Basic Auth when specified with `user` and `pass` credentials.
+
+`_get_raw_data` returns list of utf-8 decoded strings (lines).
+
+### SocketService
+
+_Examples: `dovecot`, `redis`_
+
+_Variables from config file_: `unix_socket`, `host`, `port`, `request`.
+
+Object will try execute `request` using either `unix_socket` or TCP/IP socket with combination of `host` and `port`. This can access unix sockets with SOCK_STREAM or SOCK_DGRAM protocols and TCP/IP sockets in version 4 and 6 with SOCK_STREAM setting.
+
+Sockets are accessed in non-blocking mode with 15 second timeout.
+
+After every execution of `_get_raw_data` socket is closed, to prevent this module needs to set `_keep_alive` variable to `True` and implement custom `_check_raw_data` method.
+
+`_check_raw_data` should take raw data and return `True` if all data is received otherwise it should return `False`. Also it should do it in fast and efficient way. \ No newline at end of file
diff --git a/collectors/python.d.plugin/adaptec_raid/Makefile.inc b/collectors/python.d.plugin/adaptec_raid/Makefile.inc
new file mode 100644
index 000000000..716cdb235
--- /dev/null
+++ b/collectors/python.d.plugin/adaptec_raid/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += adaptec_raid/adaptec_raid.chart.py
+dist_pythonconfig_DATA += adaptec_raid/adaptec_raid.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += adaptec_raid/README.md adaptec_raid/Makefile.inc
+
diff --git a/collectors/python.d.plugin/adaptec_raid/README.md b/collectors/python.d.plugin/adaptec_raid/README.md
new file mode 100644
index 000000000..499dc9190
--- /dev/null
+++ b/collectors/python.d.plugin/adaptec_raid/README.md
@@ -0,0 +1,46 @@
+# adaptec raid
+
+Module collects logical and physical devices health metrics.
+
+**Requirements:**
+* `arcconf` program
+* `sudo` program
+* `netdata` user needs to be able to sudo the `arcconf` program without password
+
+To grab stats it executes:
+ * `sudo -n arcconf GETCONFIG 1 LD`
+ * `sudo -n arcconf GETCONFIG 1 PD`
+
+
+It produces:
+
+1. **Logical Device Status**
+
+2. **Physical Device State**
+
+3. **Physical Device S.M.A.R.T warnings**
+
+4. **Physical Device Temperature**
+
+### prerequisite
+This module uses `arcconf` which can only be executed by root. It uses
+`sudo` and assumes that it is configured such that the `netdata` user can
+execute `arcconf` as root without password.
+
+Add to `sudoers`:
+
+ netdata ALL=(root) NOPASSWD: /path/to/arcconf
+
+### configuration
+
+ **adaptec_raid** is disabled by default. Should be explicitly enabled in `python.d.conf`.
+
+```yaml
+adaptec_raid: yes
+```
+
+#### Screenshot:
+
+![image](https://user-images.githubusercontent.com/22274335/47278133-6d306680-d601-11e8-87c2-cc9c0f42d686.png)
+
+---
diff --git a/collectors/python.d.plugin/adaptec_raid/adaptec_raid.chart.py b/collectors/python.d.plugin/adaptec_raid/adaptec_raid.chart.py
new file mode 100644
index 000000000..1fb1e4336
--- /dev/null
+++ b/collectors/python.d.plugin/adaptec_raid/adaptec_raid.chart.py
@@ -0,0 +1,247 @@
+# -*- coding: utf-8 -*-
+# Description: adaptec_raid netdata python.d module
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+
+import re
+
+from copy import deepcopy
+
+from bases.FrameworkServices.ExecutableService import ExecutableService
+from bases.collection import find_binary
+
+
+disabled_by_default = True
+
+update_every = 5
+
+ORDER = [
+ 'ld_status',
+ 'pd_state',
+ 'pd_smart_warnings',
+ 'pd_temperature',
+]
+
+CHARTS = {
+ 'ld_status': {
+ 'options': [None, 'Status Is Not OK', 'bool', 'logical devices', 'adapter_raid.ld_status', 'line'],
+ 'lines': []
+ },
+ 'pd_state': {
+ 'options': [None, 'State Is Not OK', 'bool', 'physical devices', 'adapter_raid.pd_state', 'line'],
+ 'lines': []
+ },
+ 'pd_smart_warnings': {
+ 'options': [None, 'S.M.A.R.T warnings', 'count', 'physical devices',
+ 'adapter_raid.smart_warnings', 'line'],
+ 'lines': []
+ },
+ 'pd_temperature': {
+ 'options': [None, 'Temperature', 'celsius', 'physical devices', 'adapter_raid.temperature', 'line'],
+ 'lines': []
+ },
+}
+
+SUDO = 'sudo'
+ARCCONF = 'arcconf'
+
+BAD_LD_STATUS = (
+ 'Degraded',
+ 'Failed',
+)
+
+GOOD_PD_STATUS = (
+ 'Online',
+)
+
+RE_LD = re.compile(
+ r'Logical device number\s+([0-9]+).*?'
+ r'Status of logical device\s+: ([a-zA-Z]+)'
+)
+
+
+def find_lds(d):
+ d = ' '.join(v.strip() for v in d)
+ return [LD(*v) for v in RE_LD.findall(d)]
+
+
+def find_pds(d):
+ pds = list()
+ pd = PD()
+
+ for row in d:
+ row = row.strip()
+ if row.startswith('Device #'):
+ pd = PD()
+ pd.id = row.split('#')[-1]
+ elif not pd.id:
+ continue
+
+ if row.startswith('State'):
+ v = row.split()[-1]
+ pd.state = v
+ elif row.startswith('S.M.A.R.T. warnings'):
+ v = row.split()[-1]
+ pd.smart_warnings = v
+ elif row.startswith('Temperature'):
+ v = row.split(':')[-1].split()[0]
+ pd.temperature = v
+ elif row.startswith('NCQ status'):
+ if pd.id and pd.state and pd.smart_warnings:
+ pds.append(pd)
+ pd = PD()
+
+ return pds
+
+
+class LD:
+ def __init__(self, ld_id, status):
+ self.id = ld_id
+ self.status = status
+
+ def data(self):
+ return {
+ 'ld_{0}_status'.format(self.id): int(self.status in BAD_LD_STATUS)
+ }
+
+
+class PD:
+ def __init__(self):
+ self.id = None
+ self.state = None
+ self.smart_warnings = None
+ self.temperature = None
+
+ def data(self):
+ data = {
+ 'pd_{0}_state'.format(self.id): int(self.state not in GOOD_PD_STATUS),
+ 'pd_{0}_smart_warnings'.format(self.id): self.smart_warnings,
+ }
+ if self.temperature and self.temperature.isdigit():
+ data['pd_{0}_temperature'.format(self.id)] = self.temperature
+
+ return data
+
+
+class Arcconf:
+ def __init__(self, arcconf):
+ self.arcconf = arcconf
+
+ def ld_info(self):
+ return [self.arcconf, 'GETCONFIG', '1', 'LD']
+
+ def pd_info(self):
+ return [self.arcconf, 'GETCONFIG', '1', 'PD']
+
+
+# TODO: hardcoded sudo...
+class SudoArcconf:
+ def __init__(self, arcconf, sudo):
+ self.arcconf = Arcconf(arcconf)
+ self.sudo = sudo
+
+ def ld_info(self):
+ return [self.sudo, '-n'] + self.arcconf.ld_info()
+
+ def pd_info(self):
+ return [self.sudo, '-n'] + self.arcconf.pd_info()
+
+
+class Service(ExecutableService):
+ def __init__(self, configuration=None, name=None):
+ ExecutableService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = deepcopy(CHARTS)
+ self.use_sudo = self.configuration.get('use_sudo', True)
+ self.arcconf = None
+
+ def execute(self, command, stderr=False):
+ return self._get_raw_data(command=command, stderr=stderr)
+
+ def check(self):
+ arcconf = find_binary(ARCCONF)
+ if not arcconf:
+ self.error('can\'t locate "{0}" binary'.format(ARCCONF))
+ return False
+
+ sudo = find_binary(SUDO)
+ if self.use_sudo:
+ if not sudo:
+ self.error('can\'t locate "{0}" binary'.format(SUDO))
+ return False
+ err = self.execute([sudo, '-n', '-v'], True)
+ if err:
+ self.error(' '.join(err))
+ return False
+
+ if self.use_sudo:
+ self.arcconf = SudoArcconf(arcconf, sudo)
+ else:
+ self.arcconf = Arcconf(arcconf)
+
+ lds = self.get_lds()
+ if not lds:
+ return False
+
+ self.debug('discovered logical devices ids: {0}'.format([ld.id for ld in lds]))
+
+ pds = self.get_pds()
+ if not pds:
+ return False
+
+ self.debug('discovered physical devices ids: {0}'.format([pd.id for pd in pds]))
+
+ self.update_charts(lds, pds)
+ return True
+
+ def get_data(self):
+ data = dict()
+
+ for ld in self.get_lds():
+ data.update(ld.data())
+
+ for pd in self.get_pds():
+ data.update(pd.data())
+
+ return data
+
+ def get_lds(self):
+ raw_lds = self.execute(self.arcconf.ld_info())
+ if not raw_lds:
+ return None
+
+ lds = find_lds(raw_lds)
+ if not lds:
+ self.error('failed to parse "{0}" output'.format(' '.join(self.arcconf.ld_info())))
+ self.debug('output: {0}'.format(raw_lds))
+ return None
+ return lds
+
+ def get_pds(self):
+ raw_pds = self.execute(self.arcconf.pd_info())
+ if not raw_pds:
+ return None
+
+ pds = find_pds(raw_pds)
+ if not pds:
+ self.error('failed to parse "{0}" output'.format(' '.join(self.arcconf.pd_info())))
+ self.debug('output: {0}'.format(raw_pds))
+ return None
+ return pds
+
+ def update_charts(self, lds, pds):
+ charts = self.definitions
+ for ld in lds:
+ dim = ['ld_{0}_status'.format(ld.id), 'ld {0}'.format(ld.id)]
+ charts['ld_status']['lines'].append(dim)
+
+ for pd in pds:
+ dim = ['pd_{0}_state'.format(pd.id), 'pd {0}'.format(pd.id)]
+ charts['pd_state']['lines'].append(dim)
+
+ dim = ['pd_{0}_smart_warnings'.format(pd.id), 'pd {0}'.format(pd.id)]
+ charts['pd_smart_warnings']['lines'].append(dim)
+
+ dim = ['pd_{0}_temperature'.format(pd.id), 'pd {0}'.format(pd.id)]
+ charts['pd_temperature']['lines'].append(dim)
diff --git a/collectors/python.d.plugin/adaptec_raid/adaptec_raid.conf b/collectors/python.d.plugin/adaptec_raid/adaptec_raid.conf
new file mode 100644
index 000000000..253cbf5a9
--- /dev/null
+++ b/collectors/python.d.plugin/adaptec_raid/adaptec_raid.conf
@@ -0,0 +1,55 @@
+# netdata python.d.plugin configuration for adaptec raid
+#
+# This file is in YaML format. Generally the format is:
+#
+# name: value
+#
+
+# ----------------------------------------------------------------------
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+# ----------------------------------------------------------------------
diff --git a/collectors/python.d.plugin/apache/Makefile.inc b/collectors/python.d.plugin/apache/Makefile.inc
new file mode 100644
index 000000000..70a421550
--- /dev/null
+++ b/collectors/python.d.plugin/apache/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += apache/apache.chart.py
+dist_pythonconfig_DATA += apache/apache.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += apache/README.md apache/Makefile.inc
+
diff --git a/collectors/python.d.plugin/apache/README.md b/collectors/python.d.plugin/apache/README.md
new file mode 100644
index 000000000..c6d1d126a
--- /dev/null
+++ b/collectors/python.d.plugin/apache/README.md
@@ -0,0 +1,59 @@
+# apache
+
+This module will monitor one or more Apache servers depending on configuration.
+
+**Requirements:**
+ * apache with enabled `mod_status`
+
+It produces the following charts:
+
+1. **Requests** in requests/s
+ * requests
+
+2. **Connections**
+ * connections
+
+3. **Async Connections**
+ * keepalive
+ * closing
+ * writing
+
+4. **Bandwidth** in kilobytes/s
+ * sent
+
+5. **Workers**
+ * idle
+ * busy
+
+6. **Lifetime Avg. Requests/s** in requests/s
+ * requests_sec
+
+7. **Lifetime Avg. Bandwidth/s** in kilobytes/s
+ * size_sec
+
+8. **Lifetime Avg. Response Size** in bytes/request
+ * size_req
+
+### configuration
+
+Needs only `url` to server's `server-status?auto`
+
+Here is an example for 2 servers:
+
+```yaml
+update_every : 10
+priority : 90100
+
+local:
+ url : 'http://localhost/server-status?auto'
+ retries : 20
+
+remote:
+ url : 'http://www.apache.org/server-status?auto'
+ update_every : 5
+ retries : 4
+```
+
+Without configuration, module attempts to connect to `http://localhost/server-status?auto`
+
+---
diff --git a/python.d/apache.chart.py b/collectors/python.d.plugin/apache/apache.chart.py
index 789b3c099..d136274d0 100644
--- a/python.d/apache.chart.py
+++ b/collectors/python.d.plugin/apache/apache.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: apache netdata python.d module
# Author: Pawel Krupa (paulfantom)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.FrameworkServices.UrlService import UrlService
@@ -25,63 +26,65 @@ CHARTS = {
'options': [None, 'apache Lifetime Avg. Response Size', 'bytes/request',
'statistics', 'apache.bytesperreq', 'area'],
'lines': [
- ["size_req"]
+ ['size_req']
]},
'workers': {
'options': [None, 'apache Workers', 'workers', 'workers', 'apache.workers', 'stacked'],
'lines': [
- ["idle"],
- ["busy"],
+ ['idle'],
+ ['busy'],
]},
'reqpersec': {
'options': [None, 'apache Lifetime Avg. Requests/s', 'requests/s', 'statistics',
'apache.reqpersec', 'area'],
'lines': [
- ["requests_sec"]
+ ['requests_sec']
]},
'bytespersec': {
'options': [None, 'apache Lifetime Avg. Bandwidth/s', 'kilobits/s', 'statistics',
'apache.bytesperreq', 'area'],
'lines': [
- ["size_sec", None, 'absolute', 8, 1000]
+ ['size_sec', None, 'absolute', 8, 1000]
]},
'requests': {
'options': [None, 'apache Requests', 'requests/s', 'requests', 'apache.requests', 'line'],
'lines': [
- ["requests", None, 'incremental']
+ ['requests', None, 'incremental']
]},
'net': {
'options': [None, 'apache Bandwidth', 'kilobits/s', 'bandwidth', 'apache.net', 'area'],
'lines': [
- ["sent", None, 'incremental', 8, 1]
+ ['sent', None, 'incremental', 8, 1]
]},
'connections': {
'options': [None, 'apache Connections', 'connections', 'connections', 'apache.connections', 'line'],
'lines': [
- ["connections"]
+ ['connections']
]},
'conns_async': {
'options': [None, 'apache Async Connections', 'connections', 'connections', 'apache.conns_async', 'stacked'],
'lines': [
- ["keepalive"],
- ["closing"],
- ["writing"]
+ ['keepalive'],
+ ['closing'],
+ ['writing']
]}
}
-ASSIGNMENT = {"BytesPerReq": 'size_req',
- "IdleWorkers": 'idle',
- "IdleServers": 'idle_servers',
- "BusyWorkers": 'busy',
- "BusyServers": 'busy_servers',
- "ReqPerSec": 'requests_sec',
- "BytesPerSec": 'size_sec',
- "Total Accesses": 'requests',
- "Total kBytes": 'sent',
- "ConnsTotal": 'connections',
- "ConnsAsyncKeepAlive": 'keepalive',
- "ConnsAsyncClosing": 'closing',
- "ConnsAsyncWriting": 'writing'}
+ASSIGNMENT = {
+ 'BytesPerReq': 'size_req',
+ 'IdleWorkers': 'idle',
+ 'IdleServers': 'idle_servers',
+ 'BusyWorkers': 'busy',
+ 'BusyServers': 'busy_servers',
+ 'ReqPerSec': 'requests_sec',
+ 'BytesPerSec': 'size_sec',
+ 'Total Accesses': 'requests',
+ 'Total kBytes': 'sent',
+ 'ConnsTotal': 'connections',
+ 'ConnsAsyncKeepAlive': 'keepalive',
+ 'ConnsAsyncClosing': 'closing',
+ 'ConnsAsyncWriting': 'writing'
+}
class Service(UrlService):
@@ -102,8 +105,8 @@ class Service(UrlService):
for chart in self.definitions:
if chart == 'workers':
lines = self.definitions[chart]['lines']
- lines[0] = ["idle_servers", 'idle']
- lines[1] = ["busy_servers", 'busy']
+ lines[0] = ['idle_servers', 'idle']
+ lines[1] = ['busy_servers', 'busy']
opts = self.definitions[chart]['options']
opts[1] = opts[1].replace('apache', 'lighttpd')
opts[4] = opts[4].replace('apache', 'lighttpd')
@@ -120,7 +123,7 @@ class Service(UrlService):
data = dict()
for row in raw_data.split('\n'):
- tmp = row.split(":")
+ tmp = row.split(':')
if tmp[0] in ASSIGNMENT:
try:
data[ASSIGNMENT[tmp[0]]] = int(float(tmp[1]))
diff --git a/conf.d/python.d/apache.conf b/collectors/python.d.plugin/apache/apache.conf
index 3bbc3f786..8b606f7e0 100644
--- a/conf.d/python.d/apache.conf
+++ b/collectors/python.d.plugin/apache/apache.conf
@@ -84,4 +84,4 @@ localipv4:
localipv6:
name : 'local'
- url : 'http://::1/server-status?auto'
+ url : 'http://[::1]/server-status?auto'
diff --git a/collectors/python.d.plugin/beanstalk/Makefile.inc b/collectors/python.d.plugin/beanstalk/Makefile.inc
new file mode 100644
index 000000000..4bbb7087d
--- /dev/null
+++ b/collectors/python.d.plugin/beanstalk/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += beanstalk/beanstalk.chart.py
+dist_pythonconfig_DATA += beanstalk/beanstalk.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += beanstalk/README.md beanstalk/Makefile.inc
+
diff --git a/collectors/python.d.plugin/beanstalk/README.md b/collectors/python.d.plugin/beanstalk/README.md
new file mode 100644
index 000000000..c2d7d5787
--- /dev/null
+++ b/collectors/python.d.plugin/beanstalk/README.md
@@ -0,0 +1,103 @@
+# beanstalk
+
+Module provides server and tube-level statistics:
+
+**Requirements:**
+ * `python-beanstalkc`
+
+**Server statistics:**
+
+1. **Cpu usage** in cpu time
+ * user
+ * system
+
+2. **Jobs rate** in jobs/s
+ * total
+ * timeouts
+
+3. **Connections rate** in connections/s
+ * connections
+
+4. **Commands rate** in commands/s
+ * put
+ * peek
+ * peek-ready
+ * peek-delayed
+ * peek-buried
+ * reserve
+ * use
+ * watch
+ * ignore
+ * delete
+ * release
+ * bury
+ * kick
+ * stats
+ * stats-job
+ * stats-tube
+ * list-tubes
+ * list-tube-used
+ * list-tubes-watched
+ * pause-tube
+
+5. **Current tubes** in tubes
+ * tubes
+
+6. **Current jobs** in jobs
+ * urgent
+ * ready
+ * reserved
+ * delayed
+ * buried
+
+7. **Current connections** in connections
+ * written
+ * producers
+ * workers
+ * waiting
+
+8. **Binlog** in records/s
+ * written
+ * migrated
+
+9. **Uptime** in seconds
+ * uptime
+
+**Per tube statistics:**
+
+1. **Jobs rate** in jobs/s
+ * jobs
+
+2. **Jobs** in jobs
+ * using
+ * ready
+ * reserved
+ * delayed
+ * buried
+
+3. **Connections** in connections
+ * using
+ * waiting
+ * watching
+
+4. **Commands** in commands/s
+ * deletes
+ * pauses
+
+5. **Pause** in seconds
+ * since
+ * left
+
+
+### configuration
+
+Sample:
+
+```yaml
+host : '127.0.0.1'
+port : 11300
+```
+
+If no configuration is given, module will attempt to connect to beanstalkd on `127.0.0.1:11300` address
+
+---
diff --git a/python.d/beanstalk.chart.py b/collectors/python.d.plugin/beanstalk/beanstalk.chart.py
index 8880afdd9..1472b4e1a 100644
--- a/python.d/beanstalk.chart.py
+++ b/collectors/python.d.plugin/beanstalk/beanstalk.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: beanstalk netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
try:
import beanstalkc
@@ -8,13 +9,8 @@ try:
except ImportError:
BEANSTALKC = False
-try:
- import yaml
- YAML = True
-except ImportError:
- YAML = False
-
from bases.FrameworkServices.SimpleService import SimpleService
+from bases.loaders import safe_load
# default module values (can be overridden per job in `config`)
# update_every = 2
@@ -114,12 +110,13 @@ CHARTS = {
def tube_chart_template(name):
- order = ['{0}_jobs_rate'.format(name),
- '{0}_jobs'.format(name),
- '{0}_connections'.format(name),
- '{0}_commands'.format(name),
- '{0}_pause'.format(name)
- ]
+ order = [
+ '{0}_jobs_rate'.format(name),
+ '{0}_jobs'.format(name),
+ '{0}_connections'.format(name),
+ '{0}_commands'.format(name),
+ '{0}_pause'.format(name)
+ ]
family = 'tube {0}'.format(name)
charts = {
@@ -127,7 +124,8 @@ def tube_chart_template(name):
'options': [None, 'Job Rate', 'jobs/s', family, 'beanstalk.jobs_rate', 'area'],
'lines': [
['_'.join([name, 'total-jobs']), 'jobs', 'incremental']
- ]},
+ ]
+ },
order[1]: {
'options': [None, 'Jobs', 'jobs', family, 'beanstalk.jobs', 'stacked'],
'lines': [
@@ -136,27 +134,30 @@ def tube_chart_template(name):
['_'.join([name, 'current-jobs-reserved']), 'reserved'],
['_'.join([name, 'current-jobs-delayed']), 'delayed'],
['_'.join([name, 'current-jobs-buried']), 'buried']
- ]},
+ ]
+ },
order[2]: {
'options': [None, 'Connections', 'connections', family, 'beanstalk.connections', 'stacked'],
'lines': [
['_'.join([name, 'current-using']), 'using'],
['_'.join([name, 'current-waiting']), 'waiting'],
['_'.join([name, 'current-watching']), 'watching']
- ]},
+ ]
+ },
order[3]: {
'options': [None, 'Commands', 'commands/s', family, 'beanstalk.commands', 'stacked'],
'lines': [
['_'.join([name, 'cmd-delete']), 'deletes', 'incremental'],
['_'.join([name, 'cmd-pause-tube']), 'pauses', 'incremental']
- ]},
+ ]
+ },
order[4]: {
'options': [None, 'Pause', 'seconds', family, 'beanstalk.pause', 'stacked'],
'lines': [
['_'.join([name, 'pause']), 'since'],
['_'.join([name, 'pause-time-left']), 'left']
- ]}
-
+ ]
+ }
}
return order, charts
@@ -176,10 +177,6 @@ class Service(SimpleService):
self.error("'beanstalkc' module is needed to use beanstalk.chart.py")
return False
- if not YAML:
- self.error("'yaml' module is needed to use beanstalk.chart.py")
- return False
-
self.conn = self.connect()
return True if self.conn else False
@@ -231,7 +228,7 @@ class Service(SimpleService):
return beanstalkc.Connection(host=host,
port=port,
connect_timeout=timeout,
- parse_yaml=yaml.load)
+ parse_yaml=safe_load)
except beanstalkc.SocketError as error:
self.error('Connection to {0}:{1} failed: {2}'.format(host, port, error))
return None
diff --git a/conf.d/python.d/beanstalk.conf b/collectors/python.d.plugin/beanstalk/beanstalk.conf
index 940801877..940801877 100644
--- a/conf.d/python.d/beanstalk.conf
+++ b/collectors/python.d.plugin/beanstalk/beanstalk.conf
diff --git a/collectors/python.d.plugin/bind_rndc/Makefile.inc b/collectors/python.d.plugin/bind_rndc/Makefile.inc
new file mode 100644
index 000000000..72f391492
--- /dev/null
+++ b/collectors/python.d.plugin/bind_rndc/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += bind_rndc/bind_rndc.chart.py
+dist_pythonconfig_DATA += bind_rndc/bind_rndc.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += bind_rndc/README.md bind_rndc/Makefile.inc
+
diff --git a/collectors/python.d.plugin/bind_rndc/README.md b/collectors/python.d.plugin/bind_rndc/README.md
new file mode 100644
index 000000000..688297ab3
--- /dev/null
+++ b/collectors/python.d.plugin/bind_rndc/README.md
@@ -0,0 +1,60 @@
+# bind_rndc
+
+Module parses bind dump file to collect real-time performance metrics
+
+**Requirements:**
+ * Version of bind must be 9.6 +
+ * Netdata must have permissions to run `rndc stats`
+
+It produces:
+
+1. **Name server statistics**
+ * requests
+ * responses
+ * success
+ * auth_answer
+ * nonauth_answer
+ * nxrrset
+ * failure
+ * nxdomain
+ * recursion
+ * duplicate
+ * rejections
+
+2. **Incoming queries**
+ * RESERVED0
+ * A
+ * NS
+ * CNAME
+ * SOA
+ * PTR
+ * MX
+ * TXT
+ * X25
+ * AAAA
+ * SRV
+ * NAPTR
+ * A6
+ * DS
+ * RSIG
+ * DNSKEY
+ * SPF
+ * ANY
+ * DLV
+
+3. **Outgoing queries**
+ * Same as Incoming queries
+
+
+### configuration
+
+Sample:
+
+```yaml
+local:
+ named_stats_path : '/var/log/bind/named.stats'
+```
+
+If no configuration is given, module will attempt to read named.stats file at `/var/log/bind/named.stats`
+
+---
diff --git a/python.d/bind_rndc.chart.py b/collectors/python.d.plugin/bind_rndc/bind_rndc.chart.py
index cc96659b2..423232f65 100644
--- a/python.d/bind_rndc.chart.py
+++ b/collectors/python.d.plugin/bind_rndc/bind_rndc.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: bind rndc netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
import os
@@ -35,56 +36,50 @@ CHARTS = {
['nms_dropped_queries', 'dropped_queries', 'incremental'],
]},
'incoming_queries': {
- 'options': [None, 'Incoming Queries', 'queries', 'incoming queries',
- 'bind_rndc.incoming_queries', 'line'],
+ 'options': [None, 'Incoming Queries', 'queries', 'incoming queries', 'bind_rndc.incoming_queries', 'line'],
'lines': [
]},
'outgoing_queries': {
- 'options': [None, 'Outgoing Queries', 'queries', 'outgoing queries',
- 'bind_rndc.outgoing_queries', 'line'],
+ 'options': [None, 'Outgoing Queries', 'queries', 'outgoing queries', 'bind_rndc.outgoing_queries', 'line'],
'lines': [
]},
'named_stats_size': {
- 'options': [None, 'Named Stats File Size', 'MB', 'file size',
- 'bind_rndc.stats_size', 'line'],
+ 'options': [None, 'Named Stats File Size', 'MB', 'file size', 'bind_rndc.stats_size', 'line'],
'lines': [
['stats_size', None, 'absolute', 1, 1 << 20]
- ]}
+ ]
+ }
}
NMS = {
- 'nms_requests':
- ['IPv4 requests received',
- 'IPv6 requests received',
- 'TCP requests received',
- 'requests with EDNS(0) receive'],
- 'nms_responses':
- ['responses sent',
- 'truncated responses sent',
- 'responses with EDNS(0) sent',
- 'requests with unsupported EDNS version received'],
- 'nms_failure':
- ['other query failures',
- 'queries resulted in SERVFAIL'],
- 'nms_auth_answer':
- ['queries resulted in authoritative answer'],
- 'nms_non_auth_answer':
- ['queries resulted in non authoritative answer'],
- 'nms_nxrrset':
- ['queries resulted in nxrrset'],
- 'nms_success':
- ['queries resulted in successful answer'],
- 'nms_nxdomain':
- ['queries resulted in NXDOMAIN'],
- 'nms_recursion':
- ['queries caused recursion'],
- 'nms_duplicate':
- ['duplicate queries received'],
- 'nms_rejected_queries':
- ['auth queries rejected',
- 'recursive queries rejected'],
- 'nms_dropped_queries':
- ['queries dropped']
+ 'nms_requests': [
+ 'IPv4 requests received',
+ 'IPv6 requests received',
+ 'TCP requests received',
+ 'requests with EDNS(0) receive'
+ ],
+ 'nms_responses': [
+ 'responses sent',
+ 'truncated responses sent',
+ 'responses with EDNS(0) sent',
+ 'requests with unsupported EDNS version received'
+ ],
+ 'nms_failure': [
+ 'other query failures',
+ 'queries resulted in SERVFAIL'
+ ],
+ 'nms_auth_answer': ['queries resulted in authoritative answer'],
+ 'nms_non_auth_answer': ['queries resulted in non authoritative answer'],
+ 'nms_nxrrset': ['queries resulted in nxrrset'],
+ 'nms_success': ['queries resulted in successful answer'],
+ 'nms_nxdomain': ['queries resulted in NXDOMAIN'],
+ 'nms_recursion': ['queries caused recursion'],
+ 'nms_duplicate': ['duplicate queries received'],
+ 'nms_rejected_queries': [
+ 'auth queries rejected',
+ 'recursive queries rejected'
+ ],
+ 'nms_dropped_queries': ['queries dropped']
}
STATS = ['Name Server Statistics', 'Incoming Queries', 'Outgoing Queries']
@@ -215,7 +210,9 @@ def parse_stats(field, named_stats):
if '[' in line:
continue
v, k = line.strip().split(' ', 1)
- data[k] = int(v)
+ if k not in data:
+ data[k] = 0
+ data[k] += int(v)
continue
break
break
diff --git a/conf.d/python.d/bind_rndc.conf b/collectors/python.d.plugin/bind_rndc/bind_rndc.conf
index 71958ff98..71958ff98 100644
--- a/conf.d/python.d/bind_rndc.conf
+++ b/collectors/python.d.plugin/bind_rndc/bind_rndc.conf
diff --git a/collectors/python.d.plugin/boinc/Makefile.inc b/collectors/python.d.plugin/boinc/Makefile.inc
new file mode 100644
index 000000000..319e19cfe
--- /dev/null
+++ b/collectors/python.d.plugin/boinc/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += boinc/boinc.chart.py
+dist_pythonconfig_DATA += boinc/boinc.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += boinc/README.md boinc/Makefile.inc
+
diff --git a/collectors/python.d.plugin/boinc/README.md b/collectors/python.d.plugin/boinc/README.md
new file mode 100644
index 000000000..595bcd3c0
--- /dev/null
+++ b/collectors/python.d.plugin/boinc/README.md
@@ -0,0 +1,28 @@
+# boinc
+
+This module monitors task counts for the Berkely Open Infrastructure
+Networking Computing (BOINC) distributed computing client using the same
+RPC interface that the BOINC monitoring GUI does.
+
+It provides charts tracking the total number of tasks and active tasks,
+as well as ones tracking each of the possible states for tasks.
+
+### configuration
+
+BOINC requires use of a password to access it's RPC interface. You can
+find this password in the `gui_rpc_auth.cfg` file in your BOINC directory.
+
+By default, the module will try to auto-detect the password by looking
+in `/var/lib/boinc` for this file (this is the location most Linux
+distributions use for a system-wide BOINC installation), so things may
+just work without needing configuration for the local system.
+
+You can monitor remote systems as well:
+
+```yaml
+remote:
+ hostname: some-host
+ password: some-password
+```
+
+---
diff --git a/collectors/python.d.plugin/boinc/boinc.chart.py b/collectors/python.d.plugin/boinc/boinc.chart.py
new file mode 100644
index 000000000..d14754c4b
--- /dev/null
+++ b/collectors/python.d.plugin/boinc/boinc.chart.py
@@ -0,0 +1,162 @@
+# -*- coding: utf-8 -*-
+# Description: BOINC netdata python.d module
+# Author: Austin S. Hemmelgarn (Ferroin)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import socket
+
+from bases.FrameworkServices.SimpleService import SimpleService
+
+from third_party import boinc_client
+
+
+ORDER = ['tasks', 'states', 'sched_states', 'process_states']
+
+CHARTS = {
+ 'tasks': {
+ 'options': [None, 'Overall Tasks', 'tasks', 'boinc', 'boinc.tasks', 'line'],
+ 'lines': [
+ ['total', 'Total', 'absolute', 1, 1],
+ ['active', 'Active', 'absolute', 1, 1]
+ ]
+ },
+ 'states': {
+ 'options': [None, 'Tasks per State', 'tasks', 'boinc', 'boinc.states', 'line'],
+ 'lines': [
+ ['new', 'New', 'absolute', 1, 1],
+ ['downloading', 'Downloading', 'absolute', 1, 1],
+ ['downloaded', 'Ready to Run', 'absolute', 1, 1],
+ ['comperror', 'Compute Errors', 'absolute', 1, 1],
+ ['uploading', 'Uploading', 'absolute', 1, 1],
+ ['uploaded', 'Uploaded', 'absolute', 1, 1],
+ ['aborted', 'Aborted', 'absolute', 1, 1],
+ ['upload_failed', 'Failed Uploads', 'absolute', 1, 1]
+ ]
+ },
+ 'sched_states': {
+ 'options': [None, 'Tasks per Scheduler State', 'tasks', 'boinc', 'boinc.sched', 'line'],
+ 'lines': [
+ ['uninit_sched', 'Uninitialized', 'absolute', 1, 1],
+ ['preempted', 'Preempted', 'absolute', 1, 1],
+ ['scheduled', 'Scheduled', 'absolute', 1, 1]
+ ]
+ },
+ 'process_states': {
+ 'options': [None, 'Tasks per Process State', 'tasks', 'boinc', 'boinc.process', 'line'],
+ 'lines': [
+ ['uninit_proc', 'Uninitialized', 'absolute', 1, 1],
+ ['executing', 'Executing', 'absolute', 1, 1],
+ ['suspended', 'Suspended', 'absolute', 1, 1],
+ ['aborting', 'Aborted', 'absolute', 1, 1],
+ ['quit', 'Quit', 'absolute', 1, 1],
+ ['copy_pending', 'Copy Pending', 'absolute', 1, 1]
+ ]
+ }
+}
+
+# A simple template used for pre-loading the return dictionary to make
+# the _get_data() method simpler.
+_DATA_TEMPLATE = {
+ 'total': 0,
+ 'active': 0,
+ 'new': 0,
+ 'downloading': 0,
+ 'downloaded': 0,
+ 'comperror': 0,
+ 'uploading': 0,
+ 'uploaded': 0,
+ 'aborted': 0,
+ 'upload_failed': 0,
+ 'uninit_sched': 0,
+ 'preempted': 0,
+ 'scheduled': 0,
+ 'uninit_proc': 0,
+ 'executing': 0,
+ 'suspended': 0,
+ 'aborting': 0,
+ 'quit': 0,
+ 'copy_pending': 0
+}
+
+# Map task states to dimensions
+_TASK_MAP = {
+ boinc_client.ResultState.NEW: 'new',
+ boinc_client.ResultState.FILES_DOWNLOADING: 'downloading',
+ boinc_client.ResultState.FILES_DOWNLOADED: 'downloaded',
+ boinc_client.ResultState.COMPUTE_ERROR: 'comperror',
+ boinc_client.ResultState.FILES_UPLOADING: 'uploading',
+ boinc_client.ResultState.FILES_UPLOADED: 'uploaded',
+ boinc_client.ResultState.ABORTED: 'aborted',
+ boinc_client.ResultState.UPLOAD_FAILED: 'upload_failed'
+}
+
+# Map scheduler states to dimensions
+_SCHED_MAP = {
+ boinc_client.CpuSched.UNINITIALIZED: 'uninit_sched',
+ boinc_client.CpuSched.PREEMPTED: 'preempted',
+ boinc_client.CpuSched.SCHEDULED: 'scheduled',
+}
+
+# Maps process states to dimensions
+_PROC_MAP = {
+ boinc_client.Process.UNINITIALIZED: 'uninit_proc',
+ boinc_client.Process.EXECUTING: 'executing',
+ boinc_client.Process.SUSPENDED: 'suspended',
+ boinc_client.Process.ABORT_PENDING: 'aborted',
+ boinc_client.Process.QUIT_PENDING: 'quit',
+ boinc_client.Process.COPY_PENDING: 'copy_pending'
+}
+
+
+class Service(SimpleService):
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+ self.host = self.configuration.get('host', 'localhost')
+ self.port = self.configuration.get('port', 0)
+ self.password = self.configuration.get('password', '')
+ self.client = boinc_client.BoincClient(host=self.host, port=self.port, passwd=self.password)
+ self.alive = False
+
+ def check(self):
+ return self.connect()
+
+ def connect(self):
+ self.client.connect()
+ self.alive = self.client.connected and self.client.authorized
+ return self.alive
+
+ def reconnect(self):
+ # The client class itself actually disconnects existing
+ # connections when it is told to connect, so we don't need to
+ # explicitly disconnect when we're just trying to reconnect.
+ return self.connect()
+
+ def is_alive(self):
+ if not self.alive:
+ return self.reconnect()
+ return True
+
+ def _get_data(self):
+ if not self.is_alive():
+ return None
+ data = dict(_DATA_TEMPLATE)
+ results = []
+ try:
+ results = self.client.get_tasks()
+ except socket.error:
+ self.error('Connection is dead')
+ self.alive = False
+ return None
+ for task in results:
+ data['total'] += 1
+ data[_TASK_MAP[task.state]] += 1
+ try:
+ if task.active_task:
+ data['active'] += 1
+ data[_SCHED_MAP[task.scheduler_state]] += 1
+ data[_PROC_MAP[task.active_task_state]] += 1
+ except AttributeError:
+ pass
+ return data
diff --git a/collectors/python.d.plugin/boinc/boinc.conf b/collectors/python.d.plugin/boinc/boinc.conf
new file mode 100644
index 000000000..e59d2509d
--- /dev/null
+++ b/collectors/python.d.plugin/boinc/boinc.conf
@@ -0,0 +1,68 @@
+# netdata python.d.plugin configuration for boinc
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# Additionally to the above, boinc also supports the following:
+#
+# hostname: localhost # The host running the BOINC client
+# port: 31416 # The remote GUI RPC port for BOINC
+# password: '' # The remote GUI RPC password
diff --git a/collectors/python.d.plugin/ceph/Makefile.inc b/collectors/python.d.plugin/ceph/Makefile.inc
new file mode 100644
index 000000000..15b039ef6
--- /dev/null
+++ b/collectors/python.d.plugin/ceph/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += ceph/ceph.chart.py
+dist_pythonconfig_DATA += ceph/ceph.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += ceph/README.md ceph/Makefile.inc
+
diff --git a/collectors/python.d.plugin/ceph/README.md b/collectors/python.d.plugin/ceph/README.md
new file mode 100644
index 000000000..29dfe5d1d
--- /dev/null
+++ b/collectors/python.d.plugin/ceph/README.md
@@ -0,0 +1,32 @@
+# ceph
+
+This module monitors the ceph cluster usage and consuption data of a server.
+
+It produces:
+
+* Cluster statistics (usage, available, latency, objects, read/write rate)
+* OSD usage
+* OSD latency
+* Pool usage
+* Pool read/write operations
+* Pool read/write rate
+* number of objects per pool
+
+**Requirements:**
+
+- `rados` python module
+- Granting read permissions to ceph group from keyring file
+```shell
+# chmod 640 /etc/ceph/ceph.client.admin.keyring
+```
+
+### Configuration
+
+Sample:
+```yaml
+local:
+ config_file: '/etc/ceph/ceph.conf'
+ keyring_file: '/etc/ceph/ceph.client.admin.keyring'
+```
+
+---
diff --git a/python.d/ceph.chart.py b/collectors/python.d.plugin/ceph/ceph.chart.py
index fb78397d0..31c764d0f 100644
--- a/python.d/ceph.chart.py
+++ b/collectors/python.d.plugin/ceph/ceph.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: ceph netdata python.d module
# Author: Luis Eduardo (lets00)
+# SPDX-License-Identifier: GPL-3.0-or-later
try:
import rados
@@ -8,6 +9,7 @@ try:
except ImportError:
CEPH = False
+import os
import json
from bases.FrameworkServices.SimpleService import SimpleService
@@ -16,17 +18,29 @@ update_every = 10
priority = 60000
retries = 60
-ORDER = ['general_usage', 'general_objects', 'general_bytes', 'general_operations',
- 'general_latency', 'pool_usage', 'pool_objects', 'pool_read_bytes',
- 'pool_write_bytes', 'pool_read_operations', 'pool_write_operations', 'osd_usage',
- 'osd_apply_latency', 'osd_commit_latency']
+ORDER = [
+ 'general_usage',
+ 'general_objects',
+ 'general_bytes',
+ 'general_operations',
+ 'general_latency',
+ 'pool_usage',
+ 'pool_objects',
+ 'pool_read_bytes',
+ 'pool_write_bytes',
+ 'pool_read_operations',
+ 'pool_write_operations',
+ 'osd_usage',
+ 'osd_apply_latency',
+ 'osd_commit_latency'
+]
CHARTS = {
'general_usage': {
'options': [None, 'Ceph General Space', 'KB', 'general', 'ceph.general_usage', 'stacked'],
'lines': [
- ['general_available', 'avail', 'absolute', 1, 1024],
- ['general_usage', 'used', 'absolute', 1, 1024]
+ ['general_available', 'avail', 'absolute'],
+ ['general_usage', 'used', 'absolute']
]
},
'general_objects': {
@@ -118,6 +132,20 @@ class Service(SimpleService):
if not (self.config_file and self.keyring_file):
self.error('config_file and/or keyring_file is not defined')
return False
+
+ # Verify files and permissions
+ if not (os.access(self.config_file, os.F_OK)):
+ self.error('{0} does not exist'.format(self.config_file))
+ return False
+ if not (os.access(self.keyring_file, os.F_OK)):
+ self.error('{0} does not exist'.format(self.keyring_file))
+ return False
+ if not (os.access(self.config_file, os.R_OK)):
+ self.error('Ceph plugin does not read {0}, define read permission.'.format(self.config_file))
+ return False
+ if not (os.access(self.keyring_file, os.R_OK)):
+ self.error('Ceph plugin does not read {0}, define read permission.'.format(self.keyring_file))
+ return False
try:
self.cluster = rados.Rados(conffile=self.config_file,
conf=dict(keyring=self.keyring_file))
@@ -148,11 +176,11 @@ class Service(SimpleService):
pool['name'],
'absolute', 1, 1024])
self.definitions['pool_read_operations']['lines'].append(['read_operations_{0}'.format(pool['name']),
- pool['name'],
- 'absolute'])
+ pool['name'],
+ 'absolute'])
self.definitions['pool_write_operations']['lines'].append(['write_operations_{0}'.format(pool['name']),
- pool['name'],
- 'absolute'])
+ pool['name'],
+ 'absolute'])
# OSD lines
for osd in sorted(self._get_osd_df()['nodes']):
@@ -214,16 +242,17 @@ class Service(SimpleService):
apply_latency += perf['perf_stats']['apply_latency_ms']
commit_latency += perf['perf_stats']['commit_latency_ms']
- return {'general_usage': int(status['kb_used']),
- 'general_available': int(status['kb_avail']),
- 'general_objects': int(status['num_objects']),
- 'general_read_bytes': read_bytes_sec,
- 'general_write_bytes': write_bytes_sec,
- 'general_read_operations': read_op_per_sec,
- 'general_write_operations': write_op_per_sec,
- 'general_apply_latency': apply_latency,
- 'general_commit_latency': commit_latency
- }
+ return {
+ 'general_usage': int(status['kb_used']),
+ 'general_available': int(status['kb_avail']),
+ 'general_objects': int(status['num_objects']),
+ 'general_read_bytes': read_bytes_sec,
+ 'general_write_bytes': write_bytes_sec,
+ 'general_read_operations': read_op_per_sec,
+ 'general_write_operations': write_op_per_sec,
+ 'general_apply_latency': apply_latency,
+ 'general_commit_latency': commit_latency
+ }
@staticmethod
def _get_pool_usage(pool):
@@ -247,11 +276,12 @@ class Service(SimpleService):
Get read/write kb and operations in a pool
:return: A pool dict with both read/write bytes and operations.
"""
- return {'read_{0}'.format(pool['pool_name']): int(pool['client_io_rate'].get('read_bytes_sec', 0)),
- 'write_{0}'.format(pool['pool_name']): int(pool['client_io_rate'].get('write_bytes_sec', 0)),
- 'read_operations_{0}'.format(pool['pool_name']): int(pool['client_io_rate'].get('read_op_per_sec', 0)),
- 'write_operations_{0}'.format(pool['pool_name']): int(pool['client_io_rate'].get('write_op_per_sec', 0))
- }
+ return {
+ 'read_{0}'.format(pool['pool_name']): int(pool['client_io_rate'].get('read_bytes_sec', 0)),
+ 'write_{0}'.format(pool['pool_name']): int(pool['client_io_rate'].get('write_bytes_sec', 0)),
+ 'read_operations_{0}'.format(pool['pool_name']): int(pool['client_io_rate'].get('read_op_per_sec', 0)),
+ 'write_operations_{0}'.format(pool['pool_name']): int(pool['client_io_rate'].get('write_op_per_sec', 0))
+ }
@staticmethod
def _get_osd_usage(osd):
@@ -267,8 +297,10 @@ class Service(SimpleService):
Get ceph osd apply and commit latency
:return: A osd dict with osd name's key with both apply and commit latency values
"""
- return {'apply_latency_osd.{0}'.format(osd['id']): osd['perf_stats']['apply_latency_ms'],
- 'commit_latency_osd.{0}'.format(osd['id']): osd['perf_stats']['commit_latency_ms']}
+ return {
+ 'apply_latency_osd.{0}'.format(osd['id']): osd['perf_stats']['apply_latency_ms'],
+ 'commit_latency_osd.{0}'.format(osd['id']): osd['perf_stats']['commit_latency_ms']
+ }
def _get_df(self):
"""
diff --git a/conf.d/python.d/ceph.conf b/collectors/python.d.plugin/ceph/ceph.conf
index 78ac1e251..78ac1e251 100644
--- a/conf.d/python.d/ceph.conf
+++ b/collectors/python.d.plugin/ceph/ceph.conf
diff --git a/collectors/python.d.plugin/chrony/Makefile.inc b/collectors/python.d.plugin/chrony/Makefile.inc
new file mode 100644
index 000000000..18a805b12
--- /dev/null
+++ b/collectors/python.d.plugin/chrony/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += chrony/chrony.chart.py
+dist_pythonconfig_DATA += chrony/chrony.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += chrony/README.md chrony/Makefile.inc
+
diff --git a/collectors/python.d.plugin/chrony/README.md b/collectors/python.d.plugin/chrony/README.md
new file mode 100644
index 000000000..30636fe77
--- /dev/null
+++ b/collectors/python.d.plugin/chrony/README.md
@@ -0,0 +1,31 @@
+# chrony
+
+This module monitors the precision and statistics of a local chronyd server.
+
+It produces:
+
+* frequency
+* last offset
+* RMS offset
+* residual freq
+* root delay
+* root dispersion
+* skew
+* system time
+
+**Requirements:**
+Verify that user netdata can execute `chronyc tracking`. If necessary, update `/etc/chrony.conf`, `cmdallow`.
+
+### Configuration
+
+Sample:
+```yaml
+# data collection frequency:
+update_every: 1
+
+# chrony query command:
+local:
+ command: 'chronyc -n tracking'
+```
+
+---
diff --git a/python.d/chrony.chart.py b/collectors/python.d.plugin/chrony/chrony.chart.py
index 8f331fa50..fd01d4e85 100644
--- a/python.d/chrony.chart.py
+++ b/collectors/python.d.plugin/chrony/chrony.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: chrony netdata python.d module
# Author: Dominik Schloesser (domschl)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.FrameworkServices.ExecutableService import ExecutableService
@@ -13,66 +14,70 @@ retries = 10
ORDER = ['system', 'offsets', 'stratum', 'root', 'frequency', 'residualfreq', 'skew']
CHARTS = {
- # id: {
- # 'options': [name, title, units, family, context, charttype],
- # 'lines': [
- # [unique_dimension_name, name, algorithm, multiplier, divisor]
- # ]}
'system': {
- 'options': [None, "Chrony System Time Deltas", "microseconds", 'system', 'chrony.system', 'area'],
+ 'options': [None, 'Chrony System Time Deltas', 'microseconds', 'system', 'chrony.system', 'area'],
'lines': [
- ['timediff', 'system time', 'absolute', 1, 1000]
- ]},
+ ['timediff', 'system time', 'absolute', 1, 1000]
+ ]
+ },
'offsets': {
- 'options': [None, "Chrony System Time Offsets", "microseconds", 'system', 'chrony.offsets', 'area'],
+ 'options': [None, 'Chrony System Time Offsets', 'microseconds', 'system', 'chrony.offsets', 'area'],
'lines': [
['lastoffset', 'last offset', 'absolute', 1, 1000],
- ['rmsoffset', 'RMS offset', 'absolute', 1, 1000]
- ]},
+ ['rmsoffset', 'RMS offset', 'absolute', 1, 1000]
+ ]
+ },
'stratum': {
- 'options': [None, "Chrony Stratum", "stratum", 'root', 'chrony.stratum', 'line'],
+ 'options': [None, 'Chrony Stratum', 'stratum', 'root', 'chrony.stratum', 'line'],
'lines': [
['stratum', None, 'absolute', 1, 1]
- ]},
+ ]
+ },
'root': {
- 'options': [None, "Chrony Root Delays", "milliseconds", 'root', 'chrony.root', 'line'],
+ 'options': [None, 'Chrony Root Delays', 'milliseconds', 'root', 'chrony.root', 'line'],
'lines': [
- ['rootdelay', 'delay', 'absolute', 1, 1000000],
+ ['rootdelay', 'delay', 'absolute', 1, 1000000],
['rootdispersion', 'dispersion', 'absolute', 1, 1000000]
- ]},
+ ]
+ },
'frequency': {
- 'options': [None, "Chrony Frequency", "ppm", 'frequencies', 'chrony.frequency', 'area'],
+ 'options': [None, 'Chrony Frequency', 'ppm', 'frequencies', 'chrony.frequency', 'area'],
'lines': [
['frequency', None, 'absolute', 1, 1000]
- ]},
+ ]
+ },
'residualfreq': {
- 'options': [None, "Chrony Residual frequency", "ppm", 'frequencies', 'chrony.residualfreq', 'area'],
+ 'options': [None, 'Chrony Residual frequency', 'ppm', 'frequencies', 'chrony.residualfreq', 'area'],
'lines': [
['residualfreq', 'residual frequency', 'absolute', 1, 1000]
- ]},
+ ]
+ },
'skew': {
- 'options': [None, "Chrony Skew, error bound on frequency", "ppm", 'frequencies', 'chrony.skew', 'area'],
+ 'options': [None, 'Chrony Skew, error bound on frequency', 'ppm', 'frequencies', 'chrony.skew', 'area'],
'lines': [
['skew', None, 'absolute', 1, 1000]
- ]}
+ ]
+ }
}
-CHRONY = [('Frequency', 'frequency', 1e3),
- ('Last offset', 'lastoffset', 1e9),
- ('RMS offset', 'rmsoffset', 1e9),
- ('Residual freq', 'residualfreq', 1e3),
- ('Root delay', 'rootdelay', 1e9),
- ('Root dispersion', 'rootdispersion', 1e9),
- ('Skew', 'skew', 1e3),
- ('Stratum', 'stratum', 1),
- ('System time', 'timediff', 1e9)]
+CHRONY = [
+ ('Frequency', 'frequency', 1e3),
+ ('Last offset', 'lastoffset', 1e9),
+ ('RMS offset', 'rmsoffset', 1e9),
+ ('Residual freq', 'residualfreq', 1e3),
+ ('Root delay', 'rootdelay', 1e9),
+ ('Root dispersion', 'rootdispersion', 1e9),
+ ('Skew', 'skew', 1e3),
+ ('Stratum', 'stratum', 1),
+ ('System time', 'timediff', 1e9)
+]
class Service(ExecutableService):
def __init__(self, configuration=None, name=None):
ExecutableService.__init__(
self, configuration=configuration, name=name)
- self.command = "chronyc -n tracking"
+ self.command = 'chronyc -n tracking'
self.order = ORDER
self.definitions = CHARTS
diff --git a/conf.d/python.d/chrony.conf b/collectors/python.d.plugin/chrony/chrony.conf
index 9ac906b5f..9ac906b5f 100644
--- a/conf.d/python.d/chrony.conf
+++ b/collectors/python.d.plugin/chrony/chrony.conf
diff --git a/collectors/python.d.plugin/couchdb/Makefile.inc b/collectors/python.d.plugin/couchdb/Makefile.inc
new file mode 100644
index 000000000..89dfb51c7
--- /dev/null
+++ b/collectors/python.d.plugin/couchdb/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += couchdb/couchdb.chart.py
+dist_pythonconfig_DATA += couchdb/couchdb.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += couchdb/README.md couchdb/Makefile.inc
+
diff --git a/collectors/python.d.plugin/couchdb/README.md b/collectors/python.d.plugin/couchdb/README.md
new file mode 100644
index 000000000..eff8c0810
--- /dev/null
+++ b/collectors/python.d.plugin/couchdb/README.md
@@ -0,0 +1,35 @@
+# couchdb
+
+This module monitors vital statistics of a local Apache CouchDB 2.x server, including:
+
+* Overall server reads/writes
+* HTTP traffic breakdown
+ * Request methods (`GET`, `PUT`, `POST`, etc.)
+ * Response status codes (`200`, `201`, `4xx`, etc.)
+* Active server tasks
+* Replication status (CouchDB 2.1 and up only)
+* Erlang VM stats
+* Optional per-database statistics: sizes, # of docs, # of deleted docs
+
+### Configuration
+
+Sample for a local server running on port 5984:
+```yaml
+local:
+ user: 'admin'
+ pass: 'password'
+ node: 'couchdb@127.0.0.1'
+```
+
+Be sure to specify a correct admin-level username and password.
+
+You may also need to change the `node` name; this should match the value of `-name NODENAME` in your CouchDB's `etc/vm.args` file. Typically this is of the form `couchdb@fully.qualified.domain.name` in a cluster, or `couchdb@127.0.0.1` / `couchdb@localhost` for a single-node server.
+
+If you want per-database statistics, these need to be added to the configuration, separated by spaces:
+```yaml
+local:
+ ...
+ databases: 'db1 db2 db3 ...'
+```
+
+---
diff --git a/python.d/couchdb.chart.py b/collectors/python.d.plugin/couchdb/couchdb.chart.py
index 558bac587..5d6b9916f 100644
--- a/python.d/couchdb.chart.py
+++ b/collectors/python.d.plugin/couchdb/couchdb.chart.py
@@ -2,6 +2,7 @@
# Description: couchdb netdata python.d module
# Author: wohali <wohali@apache.org>
# Thanks to l2isbad for good examples :)
+# SPDX-License-Identifier: GPL-3.0-or-later
from collections import namedtuple, defaultdict
from json import loads
@@ -24,7 +25,7 @@ METHODS = namedtuple('METHODS', ['get_data', 'url', 'stats'])
OVERVIEW_STATS = [
'couchdb.database_reads.value',
'couchdb.database_writes.value',
- 'couchdb.httpd.view_reads.value'
+ 'couchdb.httpd.view_reads.value',
'couchdb.httpd_request_methods.COPY.value',
'couchdb.httpd_request_methods.DELETE.value',
'couchdb.httpd_request_methods.GET.value',
diff --git a/conf.d/python.d/couchdb.conf b/collectors/python.d.plugin/couchdb/couchdb.conf
index 5f6e75cff..5f6e75cff 100644
--- a/conf.d/python.d/couchdb.conf
+++ b/collectors/python.d.plugin/couchdb/couchdb.conf
diff --git a/collectors/python.d.plugin/cpufreq/Makefile.inc b/collectors/python.d.plugin/cpufreq/Makefile.inc
new file mode 100644
index 000000000..d6138801d
--- /dev/null
+++ b/collectors/python.d.plugin/cpufreq/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += cpufreq/cpufreq.chart.py
+dist_pythonconfig_DATA += cpufreq/cpufreq.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += cpufreq/README.md cpufreq/Makefile.inc
+
diff --git a/collectors/python.d.plugin/cpufreq/README.md b/collectors/python.d.plugin/cpufreq/README.md
new file mode 100644
index 000000000..33891d59d
--- /dev/null
+++ b/collectors/python.d.plugin/cpufreq/README.md
@@ -0,0 +1,30 @@
+# cpufreq
+
+This module shows the current CPU frequency as set by the cpufreq kernel
+module.
+
+**Requirement:**
+You need to have `CONFIG_CPU_FREQ` and (optionally) `CONFIG_CPU_FREQ_STAT`
+enabled in your kernel.
+
+This module tries to read from one of two possible locations. On
+initialization, it tries to read the `time_in_state` files provided by
+cpufreq\_stats. If this file does not exist, or doesn't contain valid data, it
+falls back to using the more inaccurate `scaling_cur_freq` file (which only
+represents the **current** CPU frequency, and doesn't account for any state
+changes which happen between updates).
+
+It produces one chart with multiple lines (one line per core).
+
+### configuration
+
+Sample:
+
+```yaml
+sys_dir: "/sys/devices"
+```
+
+If no configuration is given, module will search for cpufreq files in `/sys/devices` directory.
+Directory is also prefixed with `NETDATA_HOST_PREFIX` if specified.
+
+---
diff --git a/python.d/cpufreq.chart.py b/collectors/python.d.plugin/cpufreq/cpufreq.chart.py
index 3abde736c..cbbab6d7f 100644
--- a/python.d/cpufreq.chart.py
+++ b/collectors/python.d.plugin/cpufreq/cpufreq.chart.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
# Description: cpufreq netdata python.d module
-# Author: Pawel Krupa (paulfantom) and Steven Noonan (tycho)
+# Author: Pawel Krupa (paulfantom)
+# Author: Steven Noonan (tycho)
+# SPDX-License-Identifier: GPL-3.0-or-later
import glob
import os
@@ -17,7 +19,8 @@ CHARTS = {
'options': [None, 'CPU Clock', 'MHz', 'cpufreq', 'cpufreq.cpufreq', 'line'],
'lines': [
# lines are created dynamically in `check()` method
- ]}
+ ]
+ }
}
@@ -92,7 +95,7 @@ class Service(SimpleService):
self.assignment[cpu]['accurate'] = path
self.accurate_last[cpu] = {}
- if len(self.assignment) == 0:
+ if not self.assignment:
self.accurate_exists = False
for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/scaling_cur_freq'):
@@ -102,7 +105,7 @@ class Service(SimpleService):
self.assignment[cpu] = {}
self.assignment[cpu]['inaccurate'] = path
- if len(self.assignment) == 0:
+ if not self.assignment:
self.error("couldn't find a method to read cpufreq statistics")
return False
@@ -110,4 +113,3 @@ class Service(SimpleService):
self.definitions[ORDER[0]]['lines'].append([name, name, 'absolute', 1, 1000])
return True
-
diff --git a/conf.d/python.d/cpufreq.conf b/collectors/python.d.plugin/cpufreq/cpufreq.conf
index 0890245d9..0890245d9 100644
--- a/conf.d/python.d/cpufreq.conf
+++ b/collectors/python.d.plugin/cpufreq/cpufreq.conf
diff --git a/collectors/python.d.plugin/cpuidle/Makefile.inc b/collectors/python.d.plugin/cpuidle/Makefile.inc
new file mode 100644
index 000000000..66c47d3cf
--- /dev/null
+++ b/collectors/python.d.plugin/cpuidle/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += cpuidle/cpuidle.chart.py
+dist_pythonconfig_DATA += cpuidle/cpuidle.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += cpuidle/README.md cpuidle/Makefile.inc
+
diff --git a/collectors/python.d.plugin/cpuidle/README.md b/collectors/python.d.plugin/cpuidle/README.md
new file mode 100644
index 000000000..495169638
--- /dev/null
+++ b/collectors/python.d.plugin/cpuidle/README.md
@@ -0,0 +1,11 @@
+# cpuidle
+
+This module monitors the usage of CPU idle states.
+
+**Requirement:**
+Your kernel needs to have `CONFIG_CPU_IDLE` enabled.
+
+It produces one stacked chart per CPU, showing the percentage of time spent in
+each state.
+
+---
diff --git a/python.d/cpuidle.chart.py b/collectors/python.d.plugin/cpuidle/cpuidle.chart.py
index d14c6aaf3..feac025bf 100644
--- a/python.d/cpuidle.chart.py
+++ b/collectors/python.d.plugin/cpuidle/cpuidle.chart.py
@@ -1,14 +1,15 @@
# -*- coding: utf-8 -*-
# Description: cpuidle netdata python.d module
# Author: Steven Noonan (tycho)
+# SPDX-License-Identifier: GPL-3.0-or-later
+import ctypes
import glob
import os
import platform
from bases.FrameworkServices.SimpleService import SimpleService
-import ctypes
syscall = ctypes.CDLL('libc.so.6').syscall
# default module values (can be overridden per job in `config`)
@@ -107,7 +108,7 @@ class Service(SimpleService):
def check(self):
if self.__gettid() is None:
- self.error("Cannot get thread ID. Stats would be completely broken.")
+ self.error('Cannot get thread ID. Stats would be completely broken.')
return False
for path in sorted(glob.glob(self.sys_dir + '/cpu*/cpuidle/state*/name')):
@@ -140,9 +141,8 @@ class Service(SimpleService):
# Sort order by kernel-specified CPU index
self.order.sort(key=lambda x: int(x.split('_')[0][3:]))
- if len(self.definitions) == 0:
+ if not self.definitions:
self.error("couldn't find cstate stats")
return False
return True
-
diff --git a/collectors/python.d.plugin/cpuidle/cpuidle.conf b/collectors/python.d.plugin/cpuidle/cpuidle.conf
new file mode 100644
index 000000000..bc276fcd2
--- /dev/null
+++ b/collectors/python.d.plugin/cpuidle/cpuidle.conf
@@ -0,0 +1,40 @@
+# netdata python.d.plugin configuration for cpuidle
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
diff --git a/collectors/python.d.plugin/dns_query_time/Makefile.inc b/collectors/python.d.plugin/dns_query_time/Makefile.inc
new file mode 100644
index 000000000..7eca3e0b6
--- /dev/null
+++ b/collectors/python.d.plugin/dns_query_time/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += dns_query_time/dns_query_time.chart.py
+dist_pythonconfig_DATA += dns_query_time/dns_query_time.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += dns_query_time/README.md dns_query_time/Makefile.inc
+
diff --git a/collectors/python.d.plugin/dns_query_time/README.md b/collectors/python.d.plugin/dns_query_time/README.md
new file mode 100644
index 000000000..3703e8aaf
--- /dev/null
+++ b/collectors/python.d.plugin/dns_query_time/README.md
@@ -0,0 +1,10 @@
+# dns_query_time
+
+This module provides DNS query time statistics.
+
+**Requirement:**
+* `python-dnspython` package
+
+It produces one aggregate chart or one chart per DNS server, showing the query time.
+
+---
diff --git a/python.d/dns_query_time.chart.py b/collectors/python.d.plugin/dns_query_time/dns_query_time.chart.py
index 9a794a9c9..d3c3db788 100644
--- a/python.d/dns_query_time.chart.py
+++ b/collectors/python.d.plugin/dns_query_time/dns_query_time.chart.py
@@ -1,20 +1,25 @@
# -*- coding: utf-8 -*-
# Description: dns_query_time netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
from random import choice
-from threading import Thread
from socket import getaddrinfo, gaierror
+from threading import Thread
try:
from time import monotonic as time
except ImportError:
from time import time
+
try:
- import dns.message, dns.query, dns.name
+ import dns.message
+ import dns.query
+ import dns.name
DNS_PYTHON = True
except ImportError:
DNS_PYTHON = False
+
try:
from queue import Queue
except ImportError:
@@ -117,8 +122,12 @@ def check_ns(ns):
def create_charts(aggregate, server_list):
if aggregate:
order = ['dns_group']
- definitions = {'dns_group': {'options': [None, 'DNS Response Time', 'ms', 'name servers',
- 'dns_query_time.response_time', 'line'], 'lines': []}}
+ definitions = {
+ 'dns_group': {
+ 'options': [None, 'DNS Response Time', 'ms', 'name servers', 'dns_query_time.response_time', 'line'],
+ 'lines': []
+ }
+ }
for ns in server_list:
definitions['dns_group']['lines'].append(['_'.join(['ns', ns.replace('.', '_')]), ns, 'absolute'])
@@ -127,8 +136,10 @@ def create_charts(aggregate, server_list):
order = [''.join(['dns_', ns.replace('.', '_')]) for ns in server_list]
definitions = dict()
for ns in server_list:
- definitions[''.join(['dns_', ns.replace('.', '_')])] = {'options': [None, 'DNS Response Time', 'ms', ns,
- 'dns_query_time.response_time', 'area'],
- 'lines': [['_'.join(['ns', ns.replace('.', '_')]),
- ns, 'absolute']]}
+ definitions[''.join(['dns_', ns.replace('.', '_')])] = {
+ 'options': [None, 'DNS Response Time', 'ms', ns, 'dns_query_time.response_time', 'area'],
+ 'lines': [
+ ['_'.join(['ns', ns.replace('.', '_')]), ns, 'absolute']
+ ]
+ }
return order, definitions
diff --git a/conf.d/python.d/dns_query_time.conf b/collectors/python.d.plugin/dns_query_time/dns_query_time.conf
index d32c6db83..d32c6db83 100644
--- a/conf.d/python.d/dns_query_time.conf
+++ b/collectors/python.d.plugin/dns_query_time/dns_query_time.conf
diff --git a/collectors/python.d.plugin/dnsdist/Makefile.inc b/collectors/python.d.plugin/dnsdist/Makefile.inc
new file mode 100644
index 000000000..a53f518f0
--- /dev/null
+++ b/collectors/python.d.plugin/dnsdist/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += dnsdist/dnsdist.chart.py
+dist_pythonconfig_DATA += dnsdist/dnsdist.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += dnsdist/README.md dnsdist/Makefile.inc
+
diff --git a/collectors/python.d.plugin/dnsdist/README.md b/collectors/python.d.plugin/dnsdist/README.md
new file mode 100644
index 000000000..b646ae27c
--- /dev/null
+++ b/collectors/python.d.plugin/dnsdist/README.md
@@ -0,0 +1,54 @@
+# dnsdist
+
+Module monitor dnsdist performance and health metrics.
+
+Following charts are drawn:
+
+1. **Response latency**
+ * latency-slow
+ * latency100-1000
+ * latency50-100
+ * latency10-50
+ * latency1-10
+ * latency0-1
+
+2. **Cache performance**
+ * cache-hits
+ * cache-misses
+
+3. **ACL events**
+ * acl-drops
+ * rule-drop
+ * rule-nxdomain
+ * rule-refused
+
+4. **Noncompliant data**
+ * empty-queries
+ * no-policy
+ * noncompliant-queries
+ * noncompliant-responses
+
+5. **Queries**
+ * queries
+ * rdqueries
+ * rdqueries
+
+6. **Health**
+ * downstream-send-errors
+ * downstream-timeouts
+ * servfail-responses
+ * trunc-failures
+
+### configuration
+
+```yaml
+localhost:
+ name : 'local'
+ url : 'http://127.0.0.1:5053/jsonstat?command=stats'
+ user : 'username'
+ pass : 'password'
+ header:
+ X-API-Key: 'dnsdist-api-key'
+```
+
+---
diff --git a/collectors/python.d.plugin/dnsdist/dnsdist.chart.py b/collectors/python.d.plugin/dnsdist/dnsdist.chart.py
new file mode 100644
index 000000000..1aff3f803
--- /dev/null
+++ b/collectors/python.d.plugin/dnsdist/dnsdist.chart.py
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from json import loads
+
+from bases.FrameworkServices.UrlService import UrlService
+
+
+ORDER = [
+ 'queries',
+ 'queries_dropped',
+ 'packets_dropped',
+ 'answers',
+ 'backend_responses',
+ 'backend_commerrors',
+ 'backend_errors',
+ 'cache',
+ 'servercpu',
+ 'servermem',
+ 'query_latency',
+ 'query_latency_avg'
+]
+
+
+CHARTS = {
+ 'queries': {
+ 'options': [None, 'Client queries received', 'queries/s', 'queries', 'dnsdist.queries', 'line'],
+ 'lines': [
+ ['queries', 'all', 'incremental'],
+ ['rdqueries', 'recursive', 'incremental'],
+ ['empty-queries', 'empty', 'incremental']
+ ]
+ },
+ 'queries_dropped': {
+ 'options': [None, 'Client queries dropped', 'queries/s', 'queries', 'dnsdist.queries_dropped', 'line'],
+ 'lines': [
+ ['rule-drop', 'rule drop', 'incremental'],
+ ['dyn-blocked', 'dynamic block', 'incremental'],
+ ['no-policy', 'no policy', 'incremental'],
+ ['noncompliant-queries', 'non compliant', 'incremental']
+ ]
+ },
+ 'packets_dropped': {
+ 'options': [None, 'Packets dropped', 'packets/s', 'packets', 'dnsdist.packets_dropped', 'line'],
+ 'lines': [
+ ['acl-drops', 'acl', 'incremental']
+ ]
+ },
+ 'answers': {
+ 'options': [None, 'Answers statistics', 'answers/s', 'answers', 'dnsdist.answers', 'line'],
+ 'lines': [
+ ['self-answered', 'self answered', 'incremental'],
+ ['rule-nxdomain', 'nxdomain', 'incremental', -1],
+ ['rule-refused', 'refused', 'incremental', -1],
+ ['trunc-failures', 'trunc failures', 'incremental', -1]
+ ]
+ },
+ 'backend_responses': {
+ 'options': [None, 'Backend responses', 'responses/s', 'backends', 'dnsdist.backend_responses', 'line'],
+ 'lines': [
+ ['responses', 'responses', 'incremental']
+ ]
+ },
+ 'backend_commerrors': {
+ 'options': [None, 'Backend Communication Errors', 'errors/s', 'backends', 'dnsdist.backend_commerrors', 'line'],
+ 'lines': [
+ ['downstream-send-errors', 'send errors', 'incremental']
+ ]
+ },
+ 'backend_errors': {
+ 'options': [None, 'Backend error responses', 'responses/s', 'backends', 'dnsdist.backend_errors', 'line'],
+ 'lines': [
+ ['downstream-timeouts', 'timeout', 'incremental'],
+ ['servfail-responses', 'servfail', 'incremental'],
+ ['noncompliant-responses', 'non compliant', 'incremental']
+ ]
+ },
+ 'cache': {
+ 'options': [None, 'Cache performance', 'answers/s', 'cache', 'dnsdist.cache', 'area'],
+ 'lines': [
+ ['cache-hits', 'hits', 'incremental'],
+ ['cache-misses', 'misses', 'incremental', -1]
+ ]
+ },
+ 'servercpu': {
+ 'options': [None, 'DNSDIST server CPU utilization', 'ms/s', 'server', 'dnsdist.servercpu', 'stacked'],
+ 'lines': [
+ ['cpu-sys-msec', 'system state', 'incremental'],
+ ['cpu-user-msec', 'user state', 'incremental']
+ ]
+ },
+ 'servermem': {
+ 'options': [None, 'DNSDIST server memory utilization', 'MB', 'server', 'dnsdist.servermem', 'area'],
+ 'lines': [
+ ['real-memory-usage', 'memory usage', 'absolute', 1, 1048576]
+ ]
+ },
+ 'query_latency': {
+ 'options': [None, 'Query latency', 'queries/s', 'latency', 'dnsdist.query_latency', 'stacked'],
+ 'lines': [
+ ['latency0-1', '1ms', 'incremental'],
+ ['latency1-10', '10ms', 'incremental'],
+ ['latency10-50', '50ms', 'incremental'],
+ ['latency50-100', '100ms', 'incremental'],
+ ['latency100-1000', '1sec', 'incremental'],
+ ['latency-slow', 'slow', 'incremental']
+ ]
+ },
+ 'query_latency_avg': {
+ 'options': [None, 'Average latency for the last N queries', 'ms/query', 'latency',
+ 'dnsdist.query_latency_avg', 'line'],
+ 'lines': [
+ ['latency-avg100', '100', 'absolute'],
+ ['latency-avg1000', '1k', 'absolute'],
+ ['latency-avg10000', '10k', 'absolute'],
+ ['latency-avg1000000', '1000k', 'absolute']
+ ]
+ }
+}
+
+
+class Service(UrlService):
+ def __init__(self, configuration=None, name=None):
+ UrlService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+
+ def _get_data(self):
+ data = self._get_raw_data()
+ if not data:
+ return None
+
+ return loads(data)
diff --git a/conf.d/python.d/dnsdist.conf b/collectors/python.d.plugin/dnsdist/dnsdist.conf
index aec58b8e1..aec58b8e1 100644
--- a/conf.d/python.d/dnsdist.conf
+++ b/collectors/python.d.plugin/dnsdist/dnsdist.conf
diff --git a/collectors/python.d.plugin/dockerd/Makefile.inc b/collectors/python.d.plugin/dockerd/Makefile.inc
new file mode 100644
index 000000000..b100bc6a1
--- /dev/null
+++ b/collectors/python.d.plugin/dockerd/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += dockerd/dockerd.chart.py
+dist_pythonconfig_DATA += dockerd/dockerd.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += dockerd/README.md dockerd/Makefile.inc
+
diff --git a/collectors/python.d.plugin/dockerd/README.md b/collectors/python.d.plugin/dockerd/README.md
new file mode 100644
index 000000000..d3f603808
--- /dev/null
+++ b/collectors/python.d.plugin/dockerd/README.md
@@ -0,0 +1,26 @@
+# dockerd
+
+Module monitor docker health metrics.
+
+**Requirement:**
+* `docker` package
+
+Following charts are drawn:
+
+1. **running containers**
+ * count
+
+2. **healthy containers**
+ * count
+
+3. **unhealthy containers**
+ * count
+
+### configuration
+
+```yaml
+ update_every : 1
+ priority : 60000
+ ```
+
+---
diff --git a/collectors/python.d.plugin/dockerd/dockerd.chart.py b/collectors/python.d.plugin/dockerd/dockerd.chart.py
new file mode 100644
index 000000000..a0d3d7e65
--- /dev/null
+++ b/collectors/python.d.plugin/dockerd/dockerd.chart.py
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+# Description: docker netdata python.d module
+# Author: Kévin Darcel (@tuxity)
+
+try:
+ import docker
+ HAS_DOCKER = True
+except ImportError:
+ HAS_DOCKER = False
+
+from bases.FrameworkServices.SimpleService import SimpleService
+
+# default module values (can be overridden per job in `config`)
+# update_every = 1
+priority = 60000
+retries = 60
+
+# charts order (can be overridden if you want less charts, or different order)
+ORDER = [
+ 'running_containers',
+ 'healthy_containers',
+ 'unhealthy_containers'
+]
+
+CHARTS = {
+ 'running_containers': {
+ 'options': [None, 'Number of running containers', 'running containers', 'running containers',
+ 'docker.running_containers', 'line'],
+ 'lines': [
+ ['running_containers', 'running']
+ ]
+ },
+ 'healthy_containers': {
+ 'options': [None, 'Number of healthy containers', 'healthy containers', 'healthy containers',
+ 'docker.healthy_containers', 'line'],
+ 'lines': [
+ ['healthy_containers', 'healthy']
+ ]
+ },
+ 'unhealthy_containers': {
+ 'options': [None, 'Number of unhealthy containers', 'unhealthy containers', 'unhealthy containers',
+ 'docker.unhealthy_containers', 'line'],
+ 'lines': [
+ ['unhealthy_containers', 'unhealthy']
+ ]
+ }
+}
+
+
+class Service(SimpleService):
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+
+ def check(self):
+ if not HAS_DOCKER:
+ self.error('\'docker\' package is needed to use docker.chart.py')
+ return False
+
+ self.client = docker.DockerClient(base_url=self.configuration.get('url', 'unix://var/run/docker.sock'))
+
+ try:
+ self.client.ping()
+ except docker.errors.APIError as error:
+ self.error(error)
+ return False
+
+ return True
+
+ def get_data(self):
+ data = dict()
+ data['running_containers'] = len(self.client.containers.list(sparse=True))
+ data['healthy_containers'] = len(self.client.containers.list(filters={'health': 'healthy'}, sparse=True))
+ data['unhealthy_containers'] = len(self.client.containers.list(filters={'health': 'unhealthy'}, sparse=True))
+
+ return data or None
diff --git a/collectors/python.d.plugin/dockerd/dockerd.conf b/collectors/python.d.plugin/dockerd/dockerd.conf
new file mode 100644
index 000000000..5ef17a1f5
--- /dev/null
+++ b/collectors/python.d.plugin/dockerd/dockerd.conf
@@ -0,0 +1,79 @@
+# netdata python.d.plugin configuration for dockerd health data API
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 10 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# Additionally to the above, dockerd plugin also supports the following:
+#
+# url: '<scheme>://<host>:<port>/<health_page_api>'
+# # http://localhost:8080/health
+#
+# if the URL is password protected, the following are supported:
+#
+# user: 'username'
+# pass: 'password'
+#
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
+# only one of them will run (they have the same name)
+#
+local:
+ url: 'unix://var/run/docker.sock'
diff --git a/collectors/python.d.plugin/dovecot/Makefile.inc b/collectors/python.d.plugin/dovecot/Makefile.inc
new file mode 100644
index 000000000..fd7d13bbb
--- /dev/null
+++ b/collectors/python.d.plugin/dovecot/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += dovecot/dovecot.chart.py
+dist_pythonconfig_DATA += dovecot/dovecot.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += dovecot/README.md dovecot/Makefile.inc
+
diff --git a/collectors/python.d.plugin/dovecot/README.md b/collectors/python.d.plugin/dovecot/README.md
new file mode 100644
index 000000000..50950ecc1
--- /dev/null
+++ b/collectors/python.d.plugin/dovecot/README.md
@@ -0,0 +1,73 @@
+# dovecot
+
+This module provides statistics information from Dovecot server.
+Statistics are taken from dovecot socket by executing `EXPORT global` command.
+More information about dovecot stats can be found on [project wiki page.](http://wiki2.dovecot.org/Statistics)
+
+**Requirement:**
+Dovecot UNIX socket with R/W permissions for user netdata or Dovecot with configured TCP/IP socket.
+
+Module gives information with following charts:
+
+1. **sessions**
+ * active sessions
+
+2. **logins**
+ * logins
+
+3. **commands** - number of IMAP commands
+ * commands
+
+4. **Faults**
+ * minor
+ * major
+
+5. **Context Switches**
+ * volountary
+ * involountary
+
+6. **disk** in bytes/s
+ * read
+ * write
+
+7. **bytes** in bytes/s
+ * read
+ * write
+
+8. **number of syscalls** in syscalls/s
+ * read
+ * write
+
+9. **lookups** - number of lookups per second
+ * path
+ * attr
+
+10. **hits** - number of cache hits
+ * hits
+
+11. **attempts** - authorization attempts
+ * success
+ * failure
+
+12. **cache** - cached authorization hits
+ * hit
+ * miss
+
+### configuration
+
+Sample:
+
+```yaml
+localtcpip:
+ name : 'local'
+ host : '127.0.0.1'
+ port : 24242
+
+localsocket:
+ name : 'local'
+ socket : '/var/run/dovecot/stats'
+```
+
+If no configuration is given, module will attempt to connect to dovecot using unix socket localized in `/var/run/dovecot/stats`
+
+---
diff --git a/python.d/dovecot.chart.py b/collectors/python.d.plugin/dovecot/dovecot.chart.py
index 5689f2ec9..7fee3bfac 100644
--- a/python.d/dovecot.chart.py
+++ b/collectors/python.d.plugin/dovecot/dovecot.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: dovecot netdata python.d module
# Author: Pawel Krupa (paulfantom)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.FrameworkServices.SocketService import SocketService
@@ -10,93 +11,113 @@ priority = 60000
retries = 60
# charts order (can be overridden if you want less charts, or different order)
-ORDER = ['sessions', 'logins', 'commands',
- 'faults',
- 'context_switches',
- 'io', 'net', 'syscalls',
- 'lookup', 'cache',
- 'auth', 'auth_cache']
+ORDER = [
+ 'sessions',
+ 'logins',
+ 'commands',
+ 'faults',
+ 'context_switches',
+ 'io',
+ 'net',
+ 'syscalls',
+ 'lookup',
+ 'cache',
+ 'auth',
+ 'auth_cache'
+]
CHARTS = {
'sessions': {
- 'options': [None, "Dovecot Active Sessions", 'number', 'sessions', 'dovecot.sessions', 'line'],
+ 'options': [None, 'Dovecot Active Sessions', 'number', 'sessions', 'dovecot.sessions', 'line'],
'lines': [
['num_connected_sessions', 'active sessions', 'absolute']
- ]},
+ ]
+ },
'logins': {
- 'options': [None, "Dovecot Logins", 'number', 'logins', 'dovecot.logins', 'line'],
+ 'options': [None, 'Dovecot Logins', 'number', 'logins', 'dovecot.logins', 'line'],
'lines': [
['num_logins', 'logins', 'absolute']
- ]},
+ ]
+ },
'commands': {
- 'options': [None, "Dovecot Commands", "commands", 'commands', 'dovecot.commands', 'line'],
+ 'options': [None, 'Dovecot Commands', 'commands', 'commands', 'dovecot.commands', 'line'],
'lines': [
['num_cmds', 'commands', 'absolute']
- ]},
+ ]
+ },
'faults': {
- 'options': [None, "Dovecot Page Faults", "faults", 'page faults', 'dovecot.faults', 'line'],
+ 'options': [None, 'Dovecot Page Faults', 'faults', 'page faults', 'dovecot.faults', 'line'],
'lines': [
['min_faults', 'minor', 'absolute'],
['maj_faults', 'major', 'absolute']
- ]},
+ ]
+ },
'context_switches': {
- 'options': [None, "Dovecot Context Switches", '', 'context switches', 'dovecot.context_switches', 'line'],
+ 'options': [None, 'Dovecot Context Switches', '', 'context switches', 'dovecot.context_switches', 'line'],
'lines': [
['vol_cs', 'voluntary', 'absolute'],
['invol_cs', 'involuntary', 'absolute']
- ]},
+ ]
+ },
'io': {
- 'options': [None, "Dovecot Disk I/O", 'kilobytes/s', 'disk', 'dovecot.io', 'area'],
+ 'options': [None, 'Dovecot Disk I/O', 'kilobytes/s', 'disk', 'dovecot.io', 'area'],
'lines': [
['disk_input', 'read', 'incremental', 1, 1024],
['disk_output', 'write', 'incremental', -1, 1024]
- ]},
+ ]
+ },
'net': {
- 'options': [None, "Dovecot Network Bandwidth", 'kilobits/s', 'network', 'dovecot.net', 'area'],
+ 'options': [None, 'Dovecot Network Bandwidth', 'kilobits/s', 'network', 'dovecot.net', 'area'],
'lines': [
['read_bytes', 'read', 'incremental', 8, 1024],
['write_bytes', 'write', 'incremental', -8, 1024]
- ]},
+ ]
+ },
'syscalls': {
- 'options': [None, "Dovecot Number of SysCalls", 'syscalls/s', 'system', 'dovecot.syscalls', 'line'],
+ 'options': [None, 'Dovecot Number of SysCalls', 'syscalls/s', 'system', 'dovecot.syscalls', 'line'],
'lines': [
['read_count', 'read', 'incremental'],
['write_count', 'write', 'incremental']
- ]},
+ ]
+ },
'lookup': {
- 'options': [None, "Dovecot Lookups", 'number/s', 'lookups', 'dovecot.lookup', 'stacked'],
+ 'options': [None, 'Dovecot Lookups', 'number/s', 'lookups', 'dovecot.lookup', 'stacked'],
'lines': [
['mail_lookup_path', 'path', 'incremental'],
['mail_lookup_attr', 'attr', 'incremental']
- ]},
+ ]
+ },
'cache': {
- 'options': [None, "Dovecot Cache Hits", 'hits/s', 'cache', 'dovecot.cache', 'line'],
+ 'options': [None, 'Dovecot Cache Hits', 'hits/s', 'cache', 'dovecot.cache', 'line'],
'lines': [
['mail_cache_hits', 'hits', 'incremental']
- ]},
+ ]
+ },
'auth': {
- 'options': [None, "Dovecot Authentications", 'attempts', 'logins', 'dovecot.auth', 'stacked'],
+ 'options': [None, 'Dovecot Authentications', 'attempts', 'logins', 'dovecot.auth', 'stacked'],
'lines': [
['auth_successes', 'ok', 'absolute'],
['auth_failures', 'failed', 'absolute']
- ]},
+ ]
+ },
'auth_cache': {
- 'options': [None, "Dovecot Authentication Cache", 'number', 'cache', 'dovecot.auth_cache', 'stacked'],
+ 'options': [None, 'Dovecot Authentication Cache', 'number', 'cache', 'dovecot.auth_cache', 'stacked'],
'lines': [
['auth_cache_hits', 'hit', 'absolute'],
['auth_cache_misses', 'miss', 'absolute']
- ]}
+ ]
+ }
}
class Service(SocketService):
def __init__(self, configuration=None, name=None):
SocketService.__init__(self, configuration=configuration, name=name)
- self.request = "EXPORT\tglobal\r\n"
+ self.request = 'EXPORT\tglobal\r\n'
self.host = None # localhost
self.port = None # 24242
# self._keep_alive = True
- self.unix_socket = "/var/run/dovecot/stats"
+ self.unix_socket = '/var/run/dovecot/stats'
self.order = ORDER
self.definitions = CHARTS
@@ -111,7 +132,7 @@ class Service(SocketService):
return None
if raw is None:
- self.debug("dovecot returned no data")
+ self.debug('dovecot returned no data')
return None
data = raw.split('\n')[:2]
diff --git a/conf.d/python.d/dovecot.conf b/collectors/python.d.plugin/dovecot/dovecot.conf
index 56c394991..56c394991 100644
--- a/conf.d/python.d/dovecot.conf
+++ b/collectors/python.d.plugin/dovecot/dovecot.conf
diff --git a/collectors/python.d.plugin/elasticsearch/Makefile.inc b/collectors/python.d.plugin/elasticsearch/Makefile.inc
new file mode 100644
index 000000000..15c63c2fa
--- /dev/null
+++ b/collectors/python.d.plugin/elasticsearch/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += elasticsearch/elasticsearch.chart.py
+dist_pythonconfig_DATA += elasticsearch/elasticsearch.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += elasticsearch/README.md elasticsearch/Makefile.inc
+
diff --git a/collectors/python.d.plugin/elasticsearch/README.md b/collectors/python.d.plugin/elasticsearch/README.md
new file mode 100644
index 000000000..75e17015b
--- /dev/null
+++ b/collectors/python.d.plugin/elasticsearch/README.md
@@ -0,0 +1,60 @@
+# elasticsearch
+
+This module monitors Elasticsearch performance and health metrics.
+
+It produces:
+
+1. **Search performance** charts:
+ * Number of queries, fetches
+ * Time spent on queries, fetches
+ * Query and fetch latency
+
+2. **Indexing performance** charts:
+ * Number of documents indexed, index refreshes, flushes
+ * Time spent on indexing, refreshing, flushing
+ * Indexing and flushing latency
+
+3. **Memory usage and garbace collection** charts:
+ * JVM heap currently in use, committed
+ * Count of garbage collections
+ * Time spent on garbage collections
+
+4. **Host metrics** charts:
+ * Available file descriptors in percent
+ * Opened HTTP connections
+ * Cluster communication transport metrics
+
+5. **Queues and rejections** charts:
+ * Number of queued/rejected threads in thread pool
+
+6. **Fielddata cache** charts:
+ * Fielddata cache size
+ * Fielddata evictions and circuit breaker tripped count
+
+7. **Cluster health API** charts:
+ * Cluster status
+ * Nodes and tasks statistics
+ * Shards statistics
+
+8. **Cluster stats API** charts:
+ * Nodes statistics
+ * Query cache statistics
+ * Docs statistics
+ * Store statistics
+ * Indices and shards statistics
+
+### configuration
+
+Sample:
+
+```yaml
+local:
+ host : 'ipaddress' # Server ip address or hostname
+ port : 'password' # Port on which elasticsearch listed
+ cluster_health : True/False # Calls to cluster health elasticsearch API. Enabled by default.
+ cluster_stats : True/False # Calls to cluster stats elasticsearch API. Enabled by default.
+```
+
+If no configuration is given, module will fail to run.
+
+---
diff --git a/python.d/elasticsearch.chart.py b/collectors/python.d.plugin/elasticsearch/elasticsearch.chart.py
index 9c2c58944..3f431f6e0 100644
--- a/python.d/elasticsearch.chart.py
+++ b/collectors/python.d.plugin/elasticsearch/elasticsearch.chart.py
@@ -1,11 +1,14 @@
# -*- coding: utf-8 -*-
# Description: elastic search node stats netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import json
+import threading
from collections import namedtuple
-from json import loads
from socket import gethostbyname, gaierror
-from threading import Thread
+
try:
from queue import Queue
except ImportError:
@@ -15,8 +18,6 @@ from bases.FrameworkServices.UrlService import UrlService
# default module values (can be overridden per job in `config`)
update_every = 5
-priority = 60000
-retries = 60
METHODS = namedtuple('METHODS', ['get_data', 'url', 'run'])
@@ -63,6 +64,8 @@ NODE_STATS = [
'jvm.buffer_pools.mapped.total_capacity_in_bytes',
'thread_pool.bulk.queue',
'thread_pool.bulk.rejected',
+ 'thread_pool.write.queue',
+ 'thread_pool.write.rejected',
'thread_pool.index.queue',
'thread_pool.index.rejected',
'thread_pool.search.queue',
@@ -107,30 +110,62 @@ HEALTH_STATS = [
]
LATENCY = {
- 'query_latency':
- {'total': 'indices_search_query_total',
- 'spent_time': 'indices_search_query_time_in_millis'},
- 'fetch_latency':
- {'total': 'indices_search_fetch_total',
- 'spent_time': 'indices_search_fetch_time_in_millis'},
- 'indexing_latency':
- {'total': 'indices_indexing_index_total',
- 'spent_time': 'indices_indexing_index_time_in_millis'},
- 'flushing_latency':
- {'total': 'indices_flush_total',
- 'spent_time': 'indices_flush_total_time_in_millis'}
+ 'query_latency': {
+ 'total': 'indices_search_query_total',
+ 'spent_time': 'indices_search_query_time_in_millis'
+ },
+ 'fetch_latency': {
+ 'total': 'indices_search_fetch_total',
+ 'spent_time': 'indices_search_fetch_time_in_millis'
+ },
+ 'indexing_latency': {
+ 'total': 'indices_indexing_index_total',
+ 'spent_time': 'indices_indexing_index_time_in_millis'
+ },
+ 'flushing_latency': {
+ 'total': 'indices_flush_total',
+ 'spent_time': 'indices_flush_total_time_in_millis'
+ }
}
# charts order (can be overridden if you want less charts, or different order)
-ORDER = ['search_performance_total', 'search_performance_current', 'search_performance_time',
- 'search_latency', 'index_performance_total', 'index_performance_current', 'index_performance_time',
- 'index_latency', 'index_translog_operations', 'index_translog_size', 'index_segments_count', 'index_segments_memory_writer',
- 'index_segments_memory', 'jvm_mem_heap', 'jvm_mem_heap_bytes', 'jvm_buffer_pool_count',
- 'jvm_direct_buffers_memory', 'jvm_mapped_buffers_memory', 'jvm_gc_count', 'jvm_gc_time', 'host_metrics_file_descriptors',
- 'host_metrics_http', 'host_metrics_transport', 'thread_pool_queued', 'thread_pool_rejected',
- 'fielddata_cache', 'fielddata_evictions_tripped', '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_performance_total',
+ 'search_performance_current',
+ 'search_performance_time',
+ 'search_latency',
+ 'index_performance_total',
+ 'index_performance_current',
+ 'index_performance_time',
+ 'index_latency',
+ 'index_translog_operations',
+ 'index_translog_size',
+ 'index_segments_count',
+ 'index_segments_memory_writer',
+ 'index_segments_memory',
+ 'jvm_mem_heap',
+ 'jvm_mem_heap_bytes',
+ 'jvm_buffer_pool_count',
+ 'jvm_direct_buffers_memory',
+ 'jvm_mapped_buffers_memory',
+ 'jvm_gc_count',
+ 'jvm_gc_time',
+ 'host_metrics_file_descriptors',
+ 'host_metrics_http',
+ 'host_metrics_transport',
+ 'thread_pool_queued',
+ 'thread_pool_rejected',
+ 'fielddata_cache',
+ 'fielddata_evictions_tripped',
+ '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_performance_total': {
@@ -139,27 +174,31 @@ CHARTS = {
'lines': [
['indices_search_query_total', 'queries', 'incremental'],
['indices_search_fetch_total', 'fetches', 'incremental']
- ]},
+ ]
+ },
'search_performance_current': {
'options': [None, 'Queries and Fetches In Progress', 'number of', 'search performance',
'elastic.search_performance_current', 'stacked'],
'lines': [
['indices_search_query_current', 'queries', 'absolute'],
['indices_search_fetch_current', 'fetches', 'absolute']
- ]},
+ ]
+ },
'search_performance_time': {
'options': [None, 'Time Spent On Queries And Fetches', 'seconds', 'search performance',
'elastic.search_performance_time', 'stacked'],
'lines': [
['indices_search_query_time_in_millis', 'query', 'incremental', 1, 1000],
['indices_search_fetch_time_in_millis', 'fetch', 'incremental', 1, 1000]
- ]},
+ ]
+ },
'search_latency': {
'options': [None, 'Query And Fetch Latency', 'ms', 'search performance', 'elastic.search_latency', 'stacked'],
'lines': [
['query_latency', 'query', 'absolute', 1, 1000],
['fetch_latency', 'fetch', 'absolute', 1, 1000]
- ]},
+ ]
+ },
'index_performance_total': {
'options': [None, 'Indexed Documents, Index Refreshes, Index Flushes To Disk', 'number of',
'indexing performance', 'elastic.index_performance_total', 'stacked'],
@@ -167,13 +206,15 @@ CHARTS = {
['indices_indexing_index_total', 'indexed', 'incremental'],
['indices_refresh_total', 'refreshes', 'incremental'],
['indices_flush_total', 'flushes', 'incremental']
- ]},
+ ]
+ },
'index_performance_current': {
'options': [None, 'Number Of Documents Currently Being Indexed', 'currently indexed',
'indexing performance', 'elastic.index_performance_current', 'stacked'],
'lines': [
['indices_indexing_index_current', 'documents', 'absolute']
- ]},
+ ]
+ },
'index_performance_time': {
'options': [None, 'Time Spent On Indexing, Refreshing, Flushing', 'seconds', 'indexing performance',
'elastic.index_performance_time', 'stacked'],
@@ -181,40 +222,46 @@ CHARTS = {
['indices_indexing_index_time_in_millis', 'indexing', 'incremental', 1, 1000],
['indices_refresh_total_time_in_millis', 'refreshing', 'incremental', 1, 1000],
['indices_flush_total_time_in_millis', 'flushing', 'incremental', 1, 1000]
- ]},
+ ]
+ },
'index_latency': {
'options': [None, 'Indexing And Flushing Latency', 'ms', 'indexing performance',
'elastic.index_latency', 'stacked'],
'lines': [
['indexing_latency', 'indexing', 'absolute', 1, 1000],
['flushing_latency', 'flushing', 'absolute', 1, 1000]
- ]},
+ ]
+ },
'index_translog_operations': {
'options': [None, 'Translog Operations', 'count', 'translog',
'elastic.index_translog_operations', 'area'],
'lines': [
['indices_translog_operations', 'total', 'absolute'],
['indices_translog_uncommitted_operations', 'uncommited', 'absolute']
- ]},
+ ]
+ },
'index_translog_size': {
'options': [None, 'Translog Size', 'MB', 'translog',
'elastic.index_translog_size', 'area'],
'lines': [
['indices_translog_size_in_bytes', 'total', 'absolute', 1, 1048567],
['indices_translog_uncommitted_size_in_bytes', 'uncommited', 'absolute', 1, 1048567]
- ]},
+ ]
+ },
'index_segments_count': {
'options': [None, 'Total Number Of Indices Segments', 'count', 'indices segments',
'elastic.index_segments_count', 'line'],
'lines': [
['indices_segments_count', 'segments', 'absolute']
- ]},
+ ]
+ },
'index_segments_memory_writer': {
'options': [None, 'Index Writer Memory Usage', 'MB', 'indices segments',
'elastic.index_segments_memory_writer', 'area'],
'lines': [
['indices_segments_index_writer_memory_in_bytes', 'total', 'absolute', 1, 1048567]
- ]},
+ ]
+ },
'index_segments_memory': {
'options': [None, 'Indices Segments Memory Usage', 'MB', 'indices segments',
'elastic.index_segments_memory', 'stacked'],
@@ -227,84 +274,98 @@ CHARTS = {
['indices_segments_doc_values_memory_in_bytes', 'doc values', 'absolute', 1, 1048567],
['indices_segments_version_map_memory_in_bytes', 'version map', 'absolute', 1, 1048567],
['indices_segments_fixed_bit_set_memory_in_bytes', 'fixed bit set', 'absolute', 1, 1048567]
- ]},
+ ]
+ },
'jvm_mem_heap': {
'options': [None, 'JVM Heap Percentage Currently in Use', 'percent', 'memory usage and gc',
'elastic.jvm_heap', 'area'],
'lines': [
['jvm_mem_heap_used_percent', 'inuse', 'absolute']
- ]},
+ ]
+ },
'jvm_mem_heap_bytes': {
'options': [None, 'JVM Heap Commit And Usage', 'MB', 'memory usage and gc',
'elastic.jvm_heap_bytes', 'area'],
'lines': [
['jvm_mem_heap_committed_in_bytes', 'commited', 'absolute', 1, 1048576],
['jvm_mem_heap_used_in_bytes', 'used', 'absolute', 1, 1048576]
- ]},
+ ]
+ },
'jvm_buffer_pool_count': {
'options': [None, 'JVM Buffers', 'count', 'memory usage and gc',
'elastic.jvm_buffer_pool_count', 'line'],
'lines': [
['jvm_buffer_pools_direct_count', 'direct', 'absolute'],
['jvm_buffer_pools_mapped_count', 'mapped', 'absolute']
- ]},
+ ]
+ },
'jvm_direct_buffers_memory': {
'options': [None, 'JVM Direct Buffers Memory', 'MB', 'memory usage and gc',
'elastic.jvm_direct_buffers_memory', 'area'],
'lines': [
['jvm_buffer_pools_direct_used_in_bytes', 'used', 'absolute', 1, 1048567],
['jvm_buffer_pools_direct_total_capacity_in_bytes', 'total capacity', 'absolute', 1, 1048567]
- ]},
+ ]
+ },
'jvm_mapped_buffers_memory': {
'options': [None, 'JVM Mapped Buffers Memory', 'MB', 'memory usage and gc',
'elastic.jvm_mapped_buffers_memory', 'area'],
'lines': [
['jvm_buffer_pools_mapped_used_in_bytes', 'used', 'absolute', 1, 1048567],
['jvm_buffer_pools_mapped_total_capacity_in_bytes', 'total capacity', 'absolute', 1, 1048567]
- ]},
+ ]
+ },
'jvm_gc_count': {
'options': [None, 'Garbage Collections', 'counts', 'memory usage and gc', 'elastic.gc_count', 'stacked'],
'lines': [
['jvm_gc_collectors_young_collection_count', 'young', 'incremental'],
['jvm_gc_collectors_old_collection_count', 'old', 'incremental']
- ]},
+ ]
+ },
'jvm_gc_time': {
'options': [None, 'Time Spent On Garbage Collections', 'ms', 'memory usage and gc',
'elastic.gc_time', 'stacked'],
'lines': [
['jvm_gc_collectors_young_collection_time_in_millis', 'young', 'incremental'],
['jvm_gc_collectors_old_collection_time_in_millis', 'old', 'incremental']
- ]},
+ ]
+ },
'thread_pool_queued': {
'options': [None, 'Number Of Queued Threads In Thread Pool', 'queued threads', 'queues and rejections',
'elastic.thread_pool_queued', 'stacked'],
'lines': [
['thread_pool_bulk_queue', 'bulk', 'absolute'],
+ ['thread_pool_write_queue', 'write', 'absolute'],
['thread_pool_index_queue', 'index', 'absolute'],
['thread_pool_search_queue', 'search', 'absolute'],
['thread_pool_merge_queue', 'merge', 'absolute']
- ]},
+ ]
+ },
'thread_pool_rejected': {
'options': [None, 'Rejected Threads In Thread Pool', 'rejected threads', 'queues and rejections',
'elastic.thread_pool_rejected', 'stacked'],
'lines': [
['thread_pool_bulk_rejected', 'bulk', 'absolute'],
+ ['thread_pool_write_rejected', 'write', 'absolute'],
['thread_pool_index_rejected', 'index', 'absolute'],
['thread_pool_search_rejected', 'search', 'absolute'],
['thread_pool_merge_rejected', 'merge', 'absolute']
- ]},
+ ]
+ },
'fielddata_cache': {
'options': [None, 'Fielddata Cache', 'MB', 'fielddata cache', 'elastic.fielddata_cache', 'line'],
'lines': [
['indices_fielddata_memory_size_in_bytes', 'cache', 'absolute', 1, 1048576]
- ]},
+ ]
+ },
'fielddata_evictions_tripped': {
'options': [None, 'Fielddata Evictions And Circuit Breaker Tripped Count', 'number of events',
'fielddata cache', 'elastic.fielddata_evictions_tripped', 'line'],
'lines': [
['indices_fielddata_evictions', 'evictions', 'incremental'],
['indices_fielddata_tripped', 'tripped', 'incremental']
- ]},
+ ]
+ },
'cluster_health_nodes': {
'options': [None, 'Nodes And Tasks Statistics', 'units', 'cluster health API',
'elastic.cluster_health_nodes', 'stacked'],
@@ -313,7 +374,8 @@ CHARTS = {
['number_of_data_nodes', 'data_nodes', 'absolute'],
['number_of_pending_tasks', 'pending_tasks', 'absolute'],
['number_of_in_flight_fetch', 'in_flight_fetch', 'absolute']
- ]},
+ ]
+ },
'cluster_health_status': {
'options': [None, 'Cluster Status', 'status', 'cluster health API',
'elastic.cluster_health_status', 'area'],
@@ -324,7 +386,8 @@ CHARTS = {
['status_foo2', None, 'absolute'],
['status_foo3', None, 'absolute'],
['status_yellow', 'yellow', 'absolute']
- ]},
+ ]
+ },
'cluster_health_shards': {
'options': [None, 'Shards Statistics', 'shards', 'cluster health API',
'elastic.cluster_health_shards', 'stacked'],
@@ -335,7 +398,8 @@ CHARTS = {
['delayed_unassigned_shards', 'delayed_unassigned', 'absolute'],
['initializing_shards', 'initializing', 'absolute'],
['active_shards_percent_as_number', 'active_percent', 'absolute']
- ]},
+ ]
+ },
'cluster_stats_nodes': {
'options': [None, 'Nodes Statistics', 'nodes', 'cluster stats API',
'elastic.cluster_nodes', 'stacked'],
@@ -345,52 +409,60 @@ CHARTS = {
['nodes_count_total', 'total', 'absolute'],
['nodes_count_master_only', 'master_only', 'absolute'],
['nodes_count_client', 'client', 'absolute']
- ]},
+ ]
+ },
'cluster_stats_query_cache': {
'options': [None, 'Query Cache Statistics', 'queries', 'cluster stats API',
'elastic.cluster_query_cache', 'stacked'],
'lines': [
['indices_query_cache_hit_count', 'hit', 'incremental'],
['indices_query_cache_miss_count', 'miss', 'incremental']
- ]},
+ ]
+ },
'cluster_stats_docs': {
'options': [None, 'Docs Statistics', 'count', 'cluster stats API',
'elastic.cluster_docs', 'line'],
'lines': [
['indices_docs_count', 'docs', 'absolute']
- ]},
+ ]
+ },
'cluster_stats_store': {
'options': [None, 'Store Statistics', 'MB', 'cluster stats API',
'elastic.cluster_store', 'line'],
'lines': [
['indices_store_size_in_bytes', 'size', 'absolute', 1, 1048567]
- ]},
+ ]
+ },
'cluster_stats_indices_shards': {
'options': [None, 'Indices And Shards Statistics', 'count', 'cluster stats API',
'elastic.cluster_indices_shards', 'stacked'],
'lines': [
['indices_count', 'indices', 'absolute'],
['indices_shards_total', 'shards', 'absolute']
- ]},
+ ]
+ },
'host_metrics_transport': {
'options': [None, 'Cluster Communication Transport Metrics', 'kilobit/s', 'host metrics',
'elastic.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',
'elastic.host_descriptors', 'area'],
'lines': [
['file_descriptors_used', 'used', 'absolute', 1, 10]
- ]},
+ ]
+ },
'host_metrics_http': {
'options': [None, 'Opened HTTP Connections', 'connections', 'host metrics',
'elastic.host_http_connections', 'line'],
'lines': [
['http_current_open', 'opened', 'absolute', 1, 1]
- ]}
+ ]
+ }
}
@@ -444,8 +516,8 @@ class Service(UrlService):
for method in self.methods:
if not method.run:
continue
- th = Thread(target=method.get_data,
- args=(queue, method.url))
+ th = threading.Thread(target=method.get_data,
+ args=(queue, method.url))
th.start()
threads.append(th)
@@ -466,7 +538,11 @@ class Service(UrlService):
if not raw_data:
return queue.put(dict())
- data = loads(raw_data)
+ data = self.json_reply(raw_data)
+
+ if not data:
+ return queue.put(dict())
+
to_netdata = fetch_data_(raw_data=data,
metrics=HEALTH_STATS)
@@ -488,7 +564,11 @@ class Service(UrlService):
if not raw_data:
return queue.put(dict())
- data = loads(raw_data)
+ data = self.json_reply(raw_data)
+
+ if not data:
+ return queue.put(dict())
+
to_netdata = fetch_data_(raw_data=data,
metrics=CLUSTER_STATS)
@@ -505,7 +585,10 @@ class Service(UrlService):
if not raw_data:
return queue.put(dict())
- data = loads(raw_data)
+ data = self.json_reply(raw_data)
+
+ if not data:
+ return queue.put(dict())
node = list(data['nodes'].keys())[0]
to_netdata = fetch_data_(raw_data=data['nodes'][node],
@@ -525,6 +608,13 @@ class Service(UrlService):
return queue.put(to_netdata)
+ def json_reply(self, reply):
+ try:
+ return json.loads(reply)
+ except ValueError as err:
+ self.error(err)
+ return None
+
def find_avg(self, total, spent_time, key):
if key not in self.latency:
self.latency[key] = dict(total=total,
diff --git a/conf.d/python.d/elasticsearch.conf b/collectors/python.d.plugin/elasticsearch/elasticsearch.conf
index 213843bf9..213843bf9 100644
--- a/conf.d/python.d/elasticsearch.conf
+++ b/collectors/python.d.plugin/elasticsearch/elasticsearch.conf
diff --git a/collectors/python.d.plugin/example/Makefile.inc b/collectors/python.d.plugin/example/Makefile.inc
new file mode 100644
index 000000000..1b027d5a7
--- /dev/null
+++ b/collectors/python.d.plugin/example/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += example/example.chart.py
+dist_pythonconfig_DATA += example/example.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += example/README.md example/Makefile.inc
+
diff --git a/collectors/python.d.plugin/example/README.md b/collectors/python.d.plugin/example/README.md
new file mode 100644
index 000000000..f9f314ac4
--- /dev/null
+++ b/collectors/python.d.plugin/example/README.md
@@ -0,0 +1 @@
+An example python data collection module. \ No newline at end of file
diff --git a/python.d/example.chart.py b/collectors/python.d.plugin/example/example.chart.py
index ee7ff62fc..85defa4d1 100644
--- a/python.d/example.chart.py
+++ b/collectors/python.d.plugin/example/example.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: example netdata python.d module
-# Author: Pawel Krupa (paulfantom)
+# Author: Put your name here (your github login)
+# SPDX-License-Identifier: GPL-3.0-or-later
from random import SystemRandom
diff --git a/conf.d/python.d/example.conf b/collectors/python.d.plugin/example/example.conf
index e7fed9b50..e7fed9b50 100644
--- a/conf.d/python.d/example.conf
+++ b/collectors/python.d.plugin/example/example.conf
diff --git a/collectors/python.d.plugin/exim/Makefile.inc b/collectors/python.d.plugin/exim/Makefile.inc
new file mode 100644
index 000000000..36ffa56d2
--- /dev/null
+++ b/collectors/python.d.plugin/exim/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += exim/exim.chart.py
+dist_pythonconfig_DATA += exim/exim.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += exim/README.md exim/Makefile.inc
+
diff --git a/collectors/python.d.plugin/exim/README.md b/collectors/python.d.plugin/exim/README.md
new file mode 100644
index 000000000..b9a62cad9
--- /dev/null
+++ b/collectors/python.d.plugin/exim/README.md
@@ -0,0 +1,13 @@
+# exim
+
+Simple module executing `exim -bpc` to grab exim queue.
+This command can take a lot of time to finish its execution thus it is not recommended to run it every second.
+
+It produces only one chart:
+
+1. **Exim Queue Emails**
+ * emails
+
+Configuration is not needed.
+
+---
diff --git a/python.d/exim.chart.py b/collectors/python.d.plugin/exim/exim.chart.py
index 2e5b924ba..5431dd46b 100644
--- a/python.d/exim.chart.py
+++ b/collectors/python.d.plugin/exim/exim.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: exim netdata python.d module
# Author: Pawel Krupa (paulfantom)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.FrameworkServices.ExecutableService import ExecutableService
@@ -14,17 +15,18 @@ ORDER = ['qemails']
CHARTS = {
'qemails': {
- 'options': [None, "Exim Queue Emails", "emails", 'queue', 'exim.qemails', 'line'],
+ 'options': [None, 'Exim Queue Emails', 'emails', 'queue', 'exim.qemails', 'line'],
'lines': [
['emails', None, 'absolute']
- ]}
+ ]
+ }
}
class Service(ExecutableService):
def __init__(self, configuration=None, name=None):
ExecutableService.__init__(self, configuration=configuration, name=name)
- self.command = "exim -bpc"
+ self.command = 'exim -bpc'
self.order = ORDER
self.definitions = CHARTS
diff --git a/conf.d/python.d/exim.conf b/collectors/python.d.plugin/exim/exim.conf
index 2add7b2cb..2add7b2cb 100644
--- a/conf.d/python.d/exim.conf
+++ b/collectors/python.d.plugin/exim/exim.conf
diff --git a/collectors/python.d.plugin/fail2ban/Makefile.inc b/collectors/python.d.plugin/fail2ban/Makefile.inc
new file mode 100644
index 000000000..31e117e53
--- /dev/null
+++ b/collectors/python.d.plugin/fail2ban/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += fail2ban/fail2ban.chart.py
+dist_pythonconfig_DATA += fail2ban/fail2ban.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += fail2ban/README.md fail2ban/Makefile.inc
+
diff --git a/collectors/python.d.plugin/fail2ban/README.md b/collectors/python.d.plugin/fail2ban/README.md
new file mode 100644
index 000000000..2ab021965
--- /dev/null
+++ b/collectors/python.d.plugin/fail2ban/README.md
@@ -0,0 +1,23 @@
+# fail2ban
+
+Module monitor fail2ban log file to show all bans for all active jails
+
+**Requirements:**
+ * fail2ban.log file MUST BE readable by netdata (A good idea is to add **create 0640 root netdata** to fail2ban conf at logrotate.d)
+
+It produces one chart with multiple lines (one line per jail)
+
+### configuration
+
+Sample:
+
+```yaml
+local:
+ log_path: '/var/log/fail2ban.log'
+ conf_path: '/etc/fail2ban/jail.local'
+ exclude: 'dropbear apache'
+```
+If no configuration is given, module will attempt to read log file at `/var/log/fail2ban.log` and conf file at `/etc/fail2ban/jail.local`.
+If conf file is not found default jail is `ssh`.
+
+---
diff --git a/collectors/python.d.plugin/fail2ban/fail2ban.chart.py b/collectors/python.d.plugin/fail2ban/fail2ban.chart.py
new file mode 100644
index 000000000..954689008
--- /dev/null
+++ b/collectors/python.d.plugin/fail2ban/fail2ban.chart.py
@@ -0,0 +1,196 @@
+# -*- coding: utf-8 -*-
+# Description: fail2ban log netdata python.d module
+# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import re
+import os
+
+from collections import defaultdict
+from glob import glob
+
+from bases.FrameworkServices.LogService import LogService
+
+
+ORDER = [
+ 'jails_bans',
+ 'jails_in_jail',
+]
+
+
+def charts(jails):
+ """
+ Chart definitions creating
+ """
+
+ ch = {
+ ORDER[0]: {
+ 'options': [None, 'Jails Ban Rate', 'bans/s', 'bans', 'jail.bans', 'line'],
+ 'lines': []
+ },
+ ORDER[1]: {
+ 'options': [None, 'Banned IPs (since the last restart of netdata)', 'IPs', 'in jail',
+ 'jail.in_jail', 'line'],
+ 'lines': []
+ },
+ }
+ for jail in jails:
+ ch[ORDER[0]]['lines'].append([jail, jail, 'incremental'])
+ ch[ORDER[1]]['lines'].append(['{0}_in_jail'.format(jail), jail, 'absolute'])
+
+ return ch
+
+
+RE_JAILS = re.compile(r'\[([a-zA-Z0-9_-]+)\][^\[\]]+?enabled\s+= (true|false)')
+
+# Example:
+# 2018-09-12 11:45:53,715 fail2ban.actions[25029]: WARNING [ssh] Unban 195.201.88.33
+# 2018-09-12 11:45:58,727 fail2ban.actions[25029]: WARNING [ssh] Ban 217.59.246.27
+RE_DATA = re.compile(r'\[(?P<jail>[A-Za-z-_0-9]+)\] (?P<action>Unban|Ban) (?P<ip>[a-f0-9.:]+)')
+
+DEFAULT_JAILS = [
+ 'ssh',
+]
+
+
+class Service(LogService):
+ def __init__(self, configuration=None, name=None):
+ LogService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = dict()
+
+ 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.conf_dir = self.configuration.get('conf_dir', '/etc/fail2ban/jail.d/')
+ self.exclude = self.configuration.get('exclude', str())
+
+ self.monitoring_jails = list()
+ self.banned_ips = defaultdict(set)
+ self.data = dict()
+
+ def check(self):
+ """
+ :return: bool
+ """
+ if not self.conf_path.endswith(('.conf', '.local')):
+ self.error('{0} is a wrong conf path name, must be *.conf or *.local'.format(self.conf_path))
+ return False
+
+ if not os.access(self.log_path, os.R_OK):
+ self.error('{0} is not readable'.format(self.log_path))
+ return False
+
+ if os.path.getsize(self.log_path) == 0:
+ self.error('{0} is empty'.format(self.log_path))
+ return False
+
+ self.monitoring_jails = self.jails_auto_detection()
+ for jail in self.monitoring_jails:
+ self.data[jail] = 0
+ self.data['{0}_in_jail'.format(jail)] = 0
+
+ self.definitions = charts(self.monitoring_jails)
+ self.info('monitoring jails: {0}'.format(self.monitoring_jails))
+
+ return True
+
+ def get_data(self):
+ """
+ :return: dict
+ """
+ raw = self._get_raw_data()
+
+ if not raw:
+ return None if raw is None else self.data
+
+ for row in raw:
+ match = RE_DATA.search(row)
+
+ if not match:
+ continue
+
+ match = match.groupdict()
+
+ if match['jail'] not in self.monitoring_jails:
+ continue
+
+ jail, action, ip = match['jail'], match['action'], match['ip']
+
+ if action == 'Ban':
+ self.data[jail] += 1
+ if ip not in self.banned_ips[jail]:
+ self.banned_ips[jail].add(ip)
+ self.data['{0}_in_jail'.format(jail)] += 1
+ else:
+ if ip in self.banned_ips[jail]:
+ self.banned_ips[jail].remove(ip)
+ self.data['{0}_in_jail'.format(jail)] -= 1
+
+ return self.data
+
+ def get_files_from_dir(self, dir_path, suffix):
+ """
+ :return: list
+ """
+ if not os.path.isdir(dir_path):
+ self.error('{0} is not a directory'.format(dir_path))
+ return list()
+
+ return glob('{0}/*.{1}'.format(self.conf_dir, suffix))
+
+ def get_jails_from_file(self, file_path):
+ """
+ :return: list
+ """
+ if not os.access(file_path, os.R_OK):
+ self.error('{0} is not readable or not exist'.format(file_path))
+ return list()
+
+ with open(file_path, 'rt') as f:
+ lines = f.readlines()
+ raw = ' '.join(line for line in lines if line.startswith(('[', 'enabled')))
+
+ match = RE_JAILS.findall(raw)
+ # Result: [('ssh', 'true'), ('dropbear', 'true'), ('pam-generic', 'true'), ...]
+
+ if not match:
+ self.debug('{0} parse failed'.format(file_path))
+ return list()
+
+ return match
+
+ def jails_auto_detection(self):
+ """
+ :return: list
+
+ Parses jail configuration files. Returns list of enabled jails.
+ According man jail.conf parse order must be
+ * jail.conf
+ * jail.d/*.conf (in alphabetical order)
+ * jail.local
+ * jail.d/*.local (in alphabetical order)
+ """
+ jails_files, all_jails, active_jails = list(), list(), list()
+
+ jails_files.append('{0}.conf'.format(self.conf_path.rsplit('.')[0]))
+ jails_files.extend(self.get_files_from_dir(self.conf_dir, 'conf'))
+ jails_files.append('{0}.local'.format(self.conf_path.rsplit('.')[0]))
+ jails_files.extend(self.get_files_from_dir(self.conf_dir, 'local'))
+
+ self.debug('config files to parse: {0}'.format(jails_files))
+
+ for f in jails_files:
+ all_jails.extend(self.get_jails_from_file(f))
+
+ exclude = self.exclude.split()
+
+ for name, status in all_jails:
+ if name in exclude:
+ continue
+
+ if status == 'true' and name not in active_jails:
+ active_jails.append(name)
+ elif status == 'false' and name in active_jails:
+ active_jails.remove(name)
+
+ return active_jails or DEFAULT_JAILS
diff --git a/conf.d/python.d/fail2ban.conf b/collectors/python.d.plugin/fail2ban/fail2ban.conf
index 60ca87231..60ca87231 100644
--- a/conf.d/python.d/fail2ban.conf
+++ b/collectors/python.d.plugin/fail2ban/fail2ban.conf
diff --git a/collectors/python.d.plugin/freeradius/Makefile.inc b/collectors/python.d.plugin/freeradius/Makefile.inc
new file mode 100644
index 000000000..54aa6492f
--- /dev/null
+++ b/collectors/python.d.plugin/freeradius/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += freeradius/freeradius.chart.py
+dist_pythonconfig_DATA += freeradius/freeradius.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += freeradius/README.md freeradius/Makefile.inc
+
diff --git a/collectors/python.d.plugin/freeradius/README.md b/collectors/python.d.plugin/freeradius/README.md
new file mode 100644
index 000000000..e5fe88ec3
--- /dev/null
+++ b/collectors/python.d.plugin/freeradius/README.md
@@ -0,0 +1,70 @@
+# freeradius
+
+Uses the `radclient` command to provide freeradius statistics. It is not recommended to run it every second.
+
+It produces:
+
+1. **Authentication counters:**
+ * access-accepts
+ * access-rejects
+ * auth-dropped-requests
+ * auth-duplicate-requests
+ * auth-invalid-requests
+ * auth-malformed-requests
+ * auth-unknown-types
+
+2. **Accounting counters:** [optional]
+ * accounting-requests
+ * accounting-responses
+ * acct-dropped-requests
+ * acct-duplicate-requests
+ * acct-invalid-requests
+ * acct-malformed-requests
+ * acct-unknown-types
+
+3. **Proxy authentication counters:** [optional]
+ * proxy-access-accepts
+ * proxy-access-rejects
+ * proxy-auth-dropped-requests
+ * proxy-auth-duplicate-requests
+ * proxy-auth-invalid-requests
+ * proxy-auth-malformed-requests
+ * proxy-auth-unknown-types
+
+4. **Proxy accounting counters:** [optional]
+ * proxy-accounting-requests
+ * proxy-accounting-responses
+ * proxy-acct-dropped-requests
+ * proxy-acct-duplicate-requests
+ * proxy-acct-invalid-requests
+ * proxy-acct-malformed-requests
+ * proxy-acct-unknown-typesa
+
+
+### configuration
+
+Sample:
+
+```yaml
+local:
+ host : 'localhost'
+ port : '18121'
+ secret : 'adminsecret'
+ acct : False # Freeradius accounting statistics.
+ proxy_auth : False # Freeradius proxy authentication statistics.
+ proxy_acct : False # Freeradius proxy accounting statistics.
+```
+
+**Freeradius server configuration:**
+
+The configuration for the status server is automatically created in the sites-available directory.
+By default, server is enabled and can be queried from every client.
+FreeRADIUS will only respond to status-server messages, if the status-server virtual server has been enabled.
+
+To do this, create a link from the sites-enabled directory to the status file in the sites-available directory:
+ * cd sites-enabled
+ * ln -s ../sites-available/status status
+
+and restart/reload your FREERADIUS server.
+
+---
diff --git a/python.d/freeradius.chart.py b/collectors/python.d.plugin/freeradius/freeradius.chart.py
index 3acc58d1a..3126831b7 100644
--- a/python.d/freeradius.chart.py
+++ b/collectors/python.d.plugin/freeradius/freeradius.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: freeradius netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
from re import findall
from subprocess import Popen, PIPE
@@ -20,7 +21,7 @@ ORDER = ['authentication', 'accounting', 'proxy-auth', 'proxy-acct']
CHARTS = {
'authentication': {
- 'options': [None, "Authentication", "packets/s", 'Authentication', 'freerad.auth', 'line'],
+ 'options': [None, 'Authentication', 'packets/s', 'Authentication', 'freerad.auth', 'line'],
'lines': [
['access-accepts', None, 'incremental'],
['access-rejects', None, 'incremental'],
@@ -29,9 +30,10 @@ CHARTS = {
['auth-invalid-requests', 'invalid-requests', 'incremental'],
['auth-malformed-requests', 'malformed-requests', 'incremental'],
['auth-unknown-types', 'unknown-types', 'incremental']
- ]},
+ ]
+ },
'accounting': {
- 'options': [None, "Accounting", "packets/s", 'Accounting', 'freerad.acct', 'line'],
+ 'options': [None, 'Accounting', 'packets/s', 'Accounting', 'freerad.acct', 'line'],
'lines': [
['accounting-requests', 'requests', 'incremental'],
['accounting-responses', 'responses', 'incremental'],
@@ -40,9 +42,10 @@ CHARTS = {
['acct-invalid-requests', 'invalid-requests', 'incremental'],
['acct-malformed-requests', 'malformed-requests', 'incremental'],
['acct-unknown-types', 'unknown-types', 'incremental']
- ]},
+ ]
+ },
'proxy-auth': {
- 'options': [None, "Proxy Authentication", "packets/s", 'Authentication', 'freerad.proxy.auth', 'line'],
+ 'options': [None, 'Proxy Authentication', 'packets/s', 'Authentication', 'freerad.proxy.auth', 'line'],
'lines': [
['proxy-access-accepts', 'access-accepts', 'incremental'],
['proxy-access-rejects', 'access-rejects', 'incremental'],
@@ -51,9 +54,10 @@ CHARTS = {
['proxy-auth-invalid-requests', 'invalid-requests', 'incremental'],
['proxy-auth-malformed-requests', 'malformed-requests', 'incremental'],
['proxy-auth-unknown-types', 'unknown-types', 'incremental']
- ]},
+ ]
+ },
'proxy-acct': {
- 'options': [None, "Proxy Accounting", "packets/s", 'Accounting', 'freerad.proxy.acct', 'line'],
+ 'options': [None, 'Proxy Accounting', 'packets/s', 'Accounting', 'freerad.proxy.acct', 'line'],
'lines': [
['proxy-accounting-requests', 'requests', 'incremental'],
['proxy-accounting-responses', 'responses', 'incremental'],
@@ -62,8 +66,8 @@ CHARTS = {
['proxy-acct-invalid-requests', 'invalid-requests', 'incremental'],
['proxy-acct-malformed-requests', 'malformed-requests', 'incremental'],
['proxy-acct-unknown-types', 'unknown-types', 'incremental']
- ]}
-
+ ]
+ }
}
@@ -105,7 +109,7 @@ class Service(SimpleService):
"""
result = self._get_raw_data()
return dict([(elem[0].lower(), int(elem[1])) for elem in findall(r'((?<=-)[AP][a-zA-Z-]+) = (\d+)', result)])
-
+
def _get_raw_data(self):
"""
The following code is equivalent to
diff --git a/conf.d/python.d/freeradius.conf b/collectors/python.d.plugin/freeradius/freeradius.conf
index 3336d4c49..3336d4c49 100644
--- a/conf.d/python.d/freeradius.conf
+++ b/collectors/python.d.plugin/freeradius/freeradius.conf
diff --git a/collectors/python.d.plugin/go_expvar/Makefile.inc b/collectors/python.d.plugin/go_expvar/Makefile.inc
new file mode 100644
index 000000000..74f50d765
--- /dev/null
+++ b/collectors/python.d.plugin/go_expvar/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += go_expvar/go_expvar.chart.py
+dist_pythonconfig_DATA += go_expvar/go_expvar.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += go_expvar/README.md go_expvar/Makefile.inc
+
diff --git a/collectors/python.d.plugin/go_expvar/README.md b/collectors/python.d.plugin/go_expvar/README.md
new file mode 100644
index 000000000..6309c195f
--- /dev/null
+++ b/collectors/python.d.plugin/go_expvar/README.md
@@ -0,0 +1,276 @@
+# go_expvar
+
+The `go_expvar` module can monitor any Go application that exposes its metrics with the use of
+`expvar` package from the Go standard library.
+
+`go_expvar` produces charts for Go runtime memory statistics and optionally any number of custom charts.
+
+For the memory statistics, it produces the following charts:
+
+1. **Heap allocations** in kB
+ * alloc: size of objects allocated on the heap
+ * inuse: size of allocated heap spans
+
+2. **Stack allocations** in kB
+ * inuse: size of allocated stack spans
+
+3. **MSpan allocations** in kB
+ * inuse: size of allocated mspan structures
+
+4. **MCache allocations** in kB
+ * inuse: size of allocated mcache structures
+
+5. **Virtual memory** in kB
+ * sys: size of reserved virtual address space
+
+6. **Live objects**
+ * live: number of live objects in memory
+
+7. **GC pauses average** in ns
+ * avg: average duration of all GC stop-the-world pauses
+
+
+## Monitoring Go Applications
+
+Netdata can be used to monitor running Go applications that expose their metrics with
+the use of the [expvar package](https://golang.org/pkg/expvar/) included in Go standard library.
+
+The `expvar` package exposes these metrics over HTTP and is very easy to use.
+Consider this minimal sample below:
+
+```go
+package main
+
+import (
+ _ "expvar"
+ "net/http"
+)
+
+func main() {
+ http.ListenAndServe("127.0.0.1:8080", nil)
+}
+```
+
+When imported this way, the `expvar` package registers a HTTP handler at `/debug/vars` that
+exposes Go runtime's memory statistics in JSON format. You can inspect the output by opening
+the URL in your browser (or by using `wget` or `curl`).
+
+Sample output:
+
+```json
+{
+"cmdline": ["./expvar-demo-binary"],
+"memstats": {"Alloc":630856,"TotalAlloc":630856,"Sys":3346432,"Lookups":27, <ommited for brevity>}
+}
+```
+
+You can of course expose and monitor your own variables as well.
+Here is a sample Go application that exposes a few custom variables:
+
+```go
+package main
+
+import (
+ "expvar"
+ "net/http"
+ "runtime"
+ "time"
+)
+
+func main() {
+
+ tick := time.NewTicker(1 * time.Second)
+ num_go := expvar.NewInt("runtime.goroutines")
+ counters := expvar.NewMap("counters")
+ counters.Set("cnt1", new(expvar.Int))
+ counters.Set("cnt2", new(expvar.Float))
+
+ go http.ListenAndServe(":8080", nil)
+
+ for {
+ select {
+ case <- tick.C:
+ num_go.Set(int64(runtime.NumGoroutine()))
+ counters.Add("cnt1", 1)
+ counters.AddFloat("cnt2", 1.452)
+ }
+ }
+}
+```
+
+Apart from the runtime memory stats, this application publishes two counters and the
+number of currently running Goroutines and updates these stats every second.
+
+In the next section, we will cover how to monitor and chart these exposed stats with
+the use of `netdata`s ```go_expvar``` module.
+
+### Using netdata go_expvar module
+
+The `go_expvar` module is disabled by default. To enable it, edit [`python.d.conf`](../python.d.conf)
+(to edit it on your system run `/etc/netdata/edit-config python.d.conf`), and change the `go_expvar`
+variable to `yes`:
+
+```
+# Enable / Disable python.d.plugin modules
+#default_run: yes
+#
+# 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.
+...
+go_expvar: yes
+...
+```
+
+Next, we need to edit the module configuration file (found at [`/etc/netdata/python.d/go_expvar.conf`](go_expvar.conf) by default)
+(to edit it on your system run `/etc/netdata/edit-config python.d/go_expvar.conf`).
+The module configuration consists of jobs, where each job can be used to monitor a separate Go application.
+Let's see a sample job configuration:
+
+```
+# /etc/netdata/python.d/go_expvar.conf
+
+app1:
+ name : 'app1'
+ url : 'http://127.0.0.1:8080/debug/vars'
+ collect_memstats: true
+ extra_charts: {}
+```
+
+Let's go over each of the defined options:
+
+ name: 'app1'
+
+This is the job name that will appear at the netdata dashboard.
+If not defined, the job_name (top level key) will be used.
+
+ url: 'http://127.0.0.1:8080/debug/vars'
+
+This is the URL of the expvar endpoint. As the expvar handler can be installed
+in a custom path, the whole URL has to be specified. This value is mandatory.
+
+ collect_memstats: true
+
+Whether to enable collecting stats about Go runtime's memory. You can find more
+information about the exposed values at the [runtime package docs](https://golang.org/pkg/runtime/#MemStats).
+
+ extra_charts: {}
+
+Enables the user to specify custom expvars to monitor and chart.
+Will be explained in more detail below.
+
+**Note: if `collect_memstats` is disabled and no `extra_charts` are defined, the plugin will
+disable itself, as there will be no data to collect!**
+
+Apart from these options, each job supports options inherited from netdata's `python.d.plugin`
+and its base `UrlService` class. These are:
+
+ update_every: 1 # the job's data collection frequency
+ priority: 60000 # the job's order on the dashboard
+ retries: 60 # the job's number of restoration attempts
+ user: admin # use when the expvar endpoint is protected by HTTP Basic Auth
+ password: sekret # use when the expvar endpoint is protected by HTTP Basic Auth
+
+### Monitoring custom vars with go_expvar
+
+Now, memory stats might be useful, but what if you want netdata to monitor some custom values
+that your Go application exposes? The `go_expvar` module can do that as well with the use of
+the `extra_charts` configuration variable.
+
+The `extra_charts` variable is a YaML list of netdata chart definitions.
+Each chart definition has the following keys:
+
+ id: netdata chart ID
+ options: a key-value mapping of chart options
+ lines: a list of line definitions
+
+**Note: please do not use dots in the chart or line ID field.
+See [this issue](https://github.com/netdata/netdata/pull/1902#issuecomment-284494195) for explanation.**
+
+Please see these two links to the official netdata documentation for more information about the values:
+
+- [External plugins - charts](../../plugins.d/#chart)
+- [Chart variables](https://github.com/netdata/netdata/wiki/How-to-write-new-module#global-variables-order-and-chart)
+
+**Line definitions**
+
+Each chart can define multiple lines (dimensions).
+A line definition is a key-value mapping of line options.
+Each line can have the following options:
+
+ # mandatory
+ expvar_key: the name of the expvar as present in the JSON output of /debug/vars endpoint
+ expvar_type: value type; supported are "float" or "int"
+ id: the id of this line/dimension in netdata
+
+ # optional - netdata defaults are used if these options are not defined
+ name: ''
+ algorithm: absolute
+ multiplier: 1
+ divisor: 100 if expvar_type == float, 1 if expvar_type == int
+ hidden: False
+
+Please see the following link for more information about the options and their default values:
+[External plugins - dimensions](../../plugins.d/#dimension)
+
+Apart from top-level expvars, this plugin can also parse expvars stored in a multi-level map;
+All dicts in the resulting JSON document are then flattened to one level.
+Expvar names are joined together with '.' when flattening.
+
+Example:
+```
+{
+ "counters": {"cnt1": 1042, "cnt2": 1512.9839999999983},
+ "runtime.goroutines": 5
+}
+```
+
+In the above case, the exported variables will be available under `runtime.goroutines`,
+`counters.cnt1` and `counters.cnt2` expvar_keys. If the flattening results in a key collision,
+the first defined key wins and all subsequent keys with the same name are ignored.
+
+**Configuration example**
+
+The configuration below matches the second Go application described above.
+Netdata will monitor and chart memory stats for the application, as well as a custom chart of
+running goroutines and two dummy counters.
+
+```
+app1:
+ name : 'app1'
+ url : 'http://127.0.0.1:8080/debug/vars'
+ collect_memstats: true
+ extra_charts:
+ - id: "runtime_goroutines"
+ options:
+ name: num_goroutines
+ title: "runtime: number of goroutines"
+ units: goroutines
+ family: runtime
+ context: expvar.runtime.goroutines
+ chart_type: line
+ lines:
+ - {expvar_key: 'runtime.goroutines', expvar_type: int, id: runtime_goroutines}
+ - id: "foo_counters"
+ options:
+ name: counters
+ title: "some random counters"
+ units: awesomeness
+ family: counters
+ context: expvar.foo.counters
+ chart_type: line
+ lines:
+ - {expvar_key: 'counters.cnt1', expvar_type: int, id: counters_cnt1}
+ - {expvar_key: 'counters.cnt2', expvar_type: float, id: counters_cnt2}
+```
+
+**Netdata charts example**
+
+The images below show how do the final charts in netdata look.
+
+![Memory stats charts](https://cloud.githubusercontent.com/assets/15180106/26762052/62b4af58-493b-11e7-9e69-146705acfc2c.png)
+
+![Custom charts](https://cloud.githubusercontent.com/assets/15180106/26762051/62ae915e-493b-11e7-8518-bd25a3886650.png)
+
diff --git a/python.d/go_expvar.chart.py b/collectors/python.d.plugin/go_expvar/go_expvar.chart.py
index cbd462570..76e8b72ec 100644
--- a/python.d/go_expvar.chart.py
+++ b/collectors/python.d.plugin/go_expvar/go_expvar.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: go_expvar netdata python.d module
# Author: Jan Kral (kralewitz)
+# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import division
import json
@@ -20,43 +21,50 @@ MEMSTATS_CHARTS = {
'lines': [
['memstats_heap_alloc', 'alloc', 'absolute', 1, 1024],
['memstats_heap_inuse', 'inuse', 'absolute', 1, 1024]
- ]},
+ ]
+ },
'memstats_stack': {
'options': ['stack', 'memory: size of stack memory structures', 'kB', 'memstats',
'expvar.memstats.stack', 'line'],
'lines': [
['memstats_stack_inuse', 'inuse', 'absolute', 1, 1024]
- ]},
+ ]
+ },
'memstats_mspan': {
'options': ['mspan', 'memory: size of mspan memory structures', 'kB', 'memstats',
'expvar.memstats.mspan', 'line'],
'lines': [
['memstats_mspan_inuse', 'inuse', 'absolute', 1, 1024]
- ]},
+ ]
+ },
'memstats_mcache': {
'options': ['mcache', 'memory: size of mcache memory structures', 'kB', 'memstats',
'expvar.memstats.mcache', 'line'],
'lines': [
['memstats_mcache_inuse', 'inuse', 'absolute', 1, 1024]
- ]},
+ ]
+ },
'memstats_live_objects': {
'options': ['live_objects', 'memory: number of live objects', 'objects', 'memstats',
'expvar.memstats.live_objects', 'line'],
'lines': [
['memstats_live_objects', 'live']
- ]},
+ ]
+ },
'memstats_sys': {
'options': ['sys', 'memory: size of reserved virtual address space', 'kB', 'memstats',
'expvar.memstats.sys', 'line'],
'lines': [
['memstats_sys', 'sys', 'absolute', 1, 1024]
- ]},
+ ]
+ },
'memstats_gc_pauses': {
'options': ['gc_pauses', 'memory: average duration of GC pauses', 'ns', 'memstats',
'expvar.memstats.gc_pauses', 'line'],
'lines': [
['memstats_gc_pauses', 'avg']
- ]},
+ ]
+ }
}
MEMSTATS_ORDER = ['memstats_heap', 'memstats_stack', 'memstats_mspan', 'memstats_mcache',
diff --git a/conf.d/python.d/go_expvar.conf b/collectors/python.d.plugin/go_expvar/go_expvar.conf
index c352b1674..ba8922d2e 100644
--- a/conf.d/python.d/go_expvar.conf
+++ b/collectors/python.d.plugin/go_expvar/go_expvar.conf
@@ -76,7 +76,7 @@
#
# Please visit the module wiki page for more information on how to use the extra_charts variable:
#
-# https://github.com/firehol/netdata/wiki/Monitoring-Go-Applications#monitoring-custom-vars-with-go_expvar
+# https://github.com/netdata/netdata/wiki/Monitoring-Go-Applications#monitoring-custom-vars-with-go_expvar
#
# Configuration example
# ---------------------
diff --git a/collectors/python.d.plugin/haproxy/Makefile.inc b/collectors/python.d.plugin/haproxy/Makefile.inc
new file mode 100644
index 000000000..ad24deaa0
--- /dev/null
+++ b/collectors/python.d.plugin/haproxy/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += haproxy/haproxy.chart.py
+dist_pythonconfig_DATA += haproxy/haproxy.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += haproxy/README.md haproxy/Makefile.inc
+
diff --git a/collectors/python.d.plugin/haproxy/README.md b/collectors/python.d.plugin/haproxy/README.md
new file mode 100644
index 000000000..4bff25670
--- /dev/null
+++ b/collectors/python.d.plugin/haproxy/README.md
@@ -0,0 +1,49 @@
+# haproxy
+
+Module monitors frontend and backend metrics such as bytes in, bytes out, sessions current, sessions in queue current.
+And health metrics such as backend servers status (server check should be used).
+
+Plugin can obtain data from url **OR** unix socket.
+
+**Requirement:**
+Socket MUST be readable AND writable by netdata user.
+
+It produces:
+
+1. **Frontend** family charts
+ * Kilobytes in/s
+ * Kilobytes out/s
+ * Sessions current
+ * Sessions in queue current
+
+2. **Backend** family charts
+ * Kilobytes in/s
+ * Kilobytes out/s
+ * Sessions current
+ * Sessions in queue current
+
+3. **Health** chart
+ * number of failed servers for every backend (in DOWN state)
+
+
+### configuration
+
+Sample:
+
+```yaml
+via_url:
+ user : 'username' # ONLY IF stats auth is used
+ pass : 'password' # # ONLY IF stats auth is used
+ url : 'http://ip.address:port/url;csv;norefresh'
+```
+
+OR
+
+```yaml
+via_socket:
+ socket : 'path/to/haproxy/sock'
+```
+
+If no configuration is given, module will fail to run.
+
+---
diff --git a/python.d/haproxy.chart.py b/collectors/python.d.plugin/haproxy/haproxy.chart.py
index 3061f5ef2..a46689f50 100644
--- a/python.d/haproxy.chart.py
+++ b/collectors/python.d.plugin/haproxy/haproxy.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: haproxy netdata python.d module
# Author: l2isbad, ktarasz
+# SPDX-License-Identifier: GPL-3.0-or-later
from collections import defaultdict
from re import compile as re_compile
@@ -20,155 +21,185 @@ priority = 60000
retries = 60
# charts order (can be overridden if you want less charts, or different order)
-ORDER = ['fbin', 'fbout', 'fscur', 'fqcur',
- 'fhrsp_1xx', 'fhrsp_2xx', 'fhrsp_3xx', 'fhrsp_4xx', 'fhrsp_5xx', 'fhrsp_other', 'fhrsp_total',
- 'bbin', 'bbout', 'bscur', 'bqcur',
- 'bhrsp_1xx', 'bhrsp_2xx', 'bhrsp_3xx', 'bhrsp_4xx', 'bhrsp_5xx', 'bhrsp_other', 'bhrsp_total',
- 'bqtime', 'bttime', 'brtime', 'bctime',
- 'health_sup', 'health_sdown', 'health_bdown', 'health_idle']
+ORDER = [
+ 'fbin',
+ 'fbout',
+ 'fscur',
+ 'fqcur',
+ 'fhrsp_1xx',
+ 'fhrsp_2xx',
+ 'fhrsp_3xx',
+ 'fhrsp_4xx',
+ 'fhrsp_5xx',
+ 'fhrsp_other',
+ 'fhrsp_total',
+ 'bbin',
+ 'bbout',
+ 'bscur',
+ 'bqcur',
+ 'bhrsp_1xx',
+ 'bhrsp_2xx',
+ 'bhrsp_3xx',
+ 'bhrsp_4xx',
+ 'bhrsp_5xx',
+ 'bhrsp_other',
+ 'bhrsp_total',
+ 'bqtime',
+ 'bttime',
+ 'brtime',
+ 'bctime',
+ 'health_sup',
+ 'health_sdown',
+ 'health_bdown',
+ 'health_idle'
+]
CHARTS = {
'fbin': {
- 'options': [None, "Kilobytes In", "KB/s", 'frontend', 'haproxy_f.bin', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'Kilobytes In', 'KB/s', 'frontend', 'haproxy_f.bin', 'line'],
+ 'lines': []
+ },
'fbout': {
- 'options': [None, "Kilobytes Out", "KB/s", 'frontend', 'haproxy_f.bout', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'Kilobytes Out', 'KB/s', 'frontend', 'haproxy_f.bout', 'line'],
+ 'lines': []
+ },
'fscur': {
- 'options': [None, "Sessions Active", "sessions", 'frontend', 'haproxy_f.scur', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'Sessions Active', 'sessions', 'frontend', 'haproxy_f.scur', 'line'],
+ 'lines': []
+ },
'fqcur': {
- 'options': [None, "Session In Queue", "sessions", 'frontend', 'haproxy_f.qcur', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'Session In Queue', 'sessions', 'frontend', 'haproxy_f.qcur', 'line'],
+ 'lines': []
+ },
'fhrsp_1xx': {
- 'options': [None, "HTTP responses with 1xx code", "responses/s", 'frontend', 'haproxy_f.hrsp_1xx', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with 1xx code', 'responses/s', 'frontend', 'haproxy_f.hrsp_1xx', 'line'],
+ 'lines': []
+ },
'fhrsp_2xx': {
- 'options': [None, "HTTP responses with 2xx code", "responses/s", 'frontend', 'haproxy_f.hrsp_2xx', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with 2xx code', 'responses/s', 'frontend', 'haproxy_f.hrsp_2xx', 'line'],
+ 'lines': []
+ },
'fhrsp_3xx': {
- 'options': [None, "HTTP responses with 3xx code", "responses/s", 'frontend', 'haproxy_f.hrsp_3xx', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with 3xx code', 'responses/s', 'frontend', 'haproxy_f.hrsp_3xx', 'line'],
+ 'lines': []
+ },
'fhrsp_4xx': {
- 'options': [None, "HTTP responses with 4xx code", "responses/s", 'frontend', 'haproxy_f.hrsp_4xx', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with 4xx code', 'responses/s', 'frontend', 'haproxy_f.hrsp_4xx', 'line'],
+ 'lines': []
+ },
'fhrsp_5xx': {
- 'options': [None, "HTTP responses with 5xx code", "responses/s", 'frontend', 'haproxy_f.hrsp_5xx', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with 5xx code', 'responses/s', 'frontend', 'haproxy_f.hrsp_5xx', 'line'],
+ 'lines': []
+ },
'fhrsp_other': {
- 'options': [None, "HTTP responses with other codes (protocol error)", "responses/s", 'frontend', 'haproxy_f.hrsp_other', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with other codes (protocol error)', 'responses/s', 'frontend',
+ 'haproxy_f.hrsp_other', 'line'],
+ 'lines': []
+ },
'fhrsp_total': {
- 'options': [None, "HTTP responses", "responses", 'frontend', 'haproxy_f.hrsp_total', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses', 'responses', 'frontend', 'haproxy_f.hrsp_total', 'line'],
+ 'lines': []
+ },
'bbin': {
- 'options': [None, "Kilobytes In", "KB/s", 'backend', 'haproxy_b.bin', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'Kilobytes In', 'KB/s', 'backend', 'haproxy_b.bin', 'line'],
+ 'lines': []
+ },
'bbout': {
- 'options': [None, "Kilobytes Out", "KB/s", 'backend', 'haproxy_b.bout', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'Kilobytes Out', 'KB/s', 'backend', 'haproxy_b.bout', 'line'],
+ 'lines': []
+ },
'bscur': {
- 'options': [None, "Sessions Active", "sessions", 'backend', 'haproxy_b.scur', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'Sessions Active', 'sessions', 'backend', 'haproxy_b.scur', 'line'],
+ 'lines': []
+ },
'bqcur': {
- 'options': [None, "Sessions In Queue", "sessions", 'backend', 'haproxy_b.qcur', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'Sessions In Queue', 'sessions', 'backend', 'haproxy_b.qcur', 'line'],
+ 'lines': []
+ },
'bhrsp_1xx': {
- 'options': [None, "HTTP responses with 1xx code", "responses/s", 'backend', 'haproxy_b.hrsp_1xx', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with 1xx code', 'responses/s', 'backend', 'haproxy_b.hrsp_1xx', 'line'],
+ 'lines': []
+ },
'bhrsp_2xx': {
- 'options': [None, "HTTP responses with 2xx code", "responses/s", 'backend', 'haproxy_b.hrsp_2xx', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with 2xx code', 'responses/s', 'backend', 'haproxy_b.hrsp_2xx', 'line'],
+ 'lines': []
+ },
'bhrsp_3xx': {
- 'options': [None, "HTTP responses with 3xx code", "responses/s", 'backend', 'haproxy_b.hrsp_3xx', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with 3xx code', 'responses/s', 'backend', 'haproxy_b.hrsp_3xx', 'line'],
+ 'lines': []
+ },
'bhrsp_4xx': {
- 'options': [None, "HTTP responses with 4xx code", "responses/s", 'backend', 'haproxy_b.hrsp_4xx', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with 4xx code', 'responses/s', 'backend', 'haproxy_b.hrsp_4xx', 'line'],
+ 'lines': []
+ },
'bhrsp_5xx': {
- 'options': [None, "HTTP responses with 5xx code", "responses/s", 'backend', 'haproxy_b.hrsp_5xx', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses with 5xx code', 'responses/s', 'backend', 'haproxy_b.hrsp_5xx', 'line'],
+ 'lines': []
+ },
'bhrsp_other': {
- 'options': [None, "HTTP responses with other codes (protocol error)", "responses/s", 'backend',
+ 'options': [None, 'HTTP responses with other codes (protocol error)', 'responses/s', 'backend',
'haproxy_b.hrsp_other', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'bhrsp_total': {
- 'options': [None, "HTTP responses (total)", "responses/s", 'backend', 'haproxy_b.hrsp_total', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'HTTP responses (total)', 'responses/s', 'backend', 'haproxy_b.hrsp_total', 'line'],
+ 'lines': []
+ },
'bqtime': {
- 'options': [None, "The average queue time over the 1024 last requests", "ms", 'backend', 'haproxy_b.qtime', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'The average queue time over the 1024 last requests', 'ms', 'backend',
+ 'haproxy_b.qtime', 'line'],
+ 'lines': []
+ },
'bctime': {
- 'options': [None, "The average connect time over the 1024 last requests", "ms", 'backend',
+ 'options': [None, 'The average connect time over the 1024 last requests', 'ms', 'backend',
'haproxy_b.ctime', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'brtime': {
- 'options': [None, "The average response time over the 1024 last requests", "ms", 'backend',
+ 'options': [None, 'The average response time over the 1024 last requests', 'ms', 'backend',
'haproxy_b.rtime', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'bttime': {
- 'options': [None, "The average total session time over the 1024 last requests", "ms", 'backend',
+ 'options': [None, 'The average total session time over the 1024 last requests', 'ms', 'backend',
'haproxy_b.ttime', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'health_sdown': {
- 'options': [None, "Backend Servers In DOWN State", "failed servers", 'health',
+ 'options': [None, 'Backend Servers In DOWN State', 'failed servers', 'health',
'haproxy_hs.down', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'health_sup': {
- 'options': [None, "Backend Servers In UP State", "health servers", 'health',
+ 'options': [None, 'Backend Servers In UP State', 'health servers', 'health',
'haproxy_hs.up', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'health_bdown': {
- 'options': [None, "Is Backend Alive? 1 = DOWN", "failed backend", 'health', 'haproxy_hb.down', 'line'],
- 'lines': [
- ]},
+ 'options': [None, 'Is Backend Alive? 1 = DOWN', 'failed backend', 'health', 'haproxy_hb.down', 'line'],
+ 'lines': []
+ },
'health_idle': {
- 'options': [None, "The Ratio Of Polling Time Vs Total Time", "percent", 'health', 'haproxy.idle', 'line'],
+ 'options': [None, 'The Ratio Of Polling Time Vs Total Time', 'percent', 'health', 'haproxy.idle', 'line'],
'lines': [
['idle', None, 'absolute']
- ]}
+ ]
+ }
}
-METRICS = {'bin': {'algorithm': 'incremental', 'divisor': 1024},
- 'bout': {'algorithm': 'incremental', 'divisor': 1024},
- 'scur': {'algorithm': 'absolute', 'divisor': 1},
- 'qcur': {'algorithm': 'absolute', 'divisor': 1},
- 'hrsp_1xx': {'algorithm': 'incremental', 'divisor': 1},
- 'hrsp_2xx': {'algorithm': 'incremental', 'divisor': 1},
- 'hrsp_3xx': {'algorithm': 'incremental', 'divisor': 1},
- 'hrsp_4xx': {'algorithm': 'incremental', 'divisor': 1},
- 'hrsp_5xx': {'algorithm': 'incremental', 'divisor': 1},
- 'hrsp_other': {'algorithm': 'incremental', 'divisor': 1},
- }
+METRICS = {
+ 'bin': {'algorithm': 'incremental', 'divisor': 1024},
+ 'bout': {'algorithm': 'incremental', 'divisor': 1024},
+ 'scur': {'algorithm': 'absolute', 'divisor': 1},
+ 'qcur': {'algorithm': 'absolute', 'divisor': 1},
+ 'hrsp_1xx': {'algorithm': 'incremental', 'divisor': 1},
+ 'hrsp_2xx': {'algorithm': 'incremental', 'divisor': 1},
+ 'hrsp_3xx': {'algorithm': 'incremental', 'divisor': 1},
+ 'hrsp_4xx': {'algorithm': 'incremental', 'divisor': 1},
+ 'hrsp_5xx': {'algorithm': 'incremental', 'divisor': 1},
+ 'hrsp_other': {'algorithm': 'incremental', 'divisor': 1}
+}
BACKEND_METRICS = {
diff --git a/conf.d/python.d/haproxy.conf b/collectors/python.d.plugin/haproxy/haproxy.conf
index a40dd76a5..a40dd76a5 100644
--- a/conf.d/python.d/haproxy.conf
+++ b/collectors/python.d.plugin/haproxy/haproxy.conf
diff --git a/collectors/python.d.plugin/hddtemp/Makefile.inc b/collectors/python.d.plugin/hddtemp/Makefile.inc
new file mode 100644
index 000000000..22852b646
--- /dev/null
+++ b/collectors/python.d.plugin/hddtemp/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += hddtemp/hddtemp.chart.py
+dist_pythonconfig_DATA += hddtemp/hddtemp.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += hddtemp/README.md hddtemp/Makefile.inc
+
diff --git a/collectors/python.d.plugin/hddtemp/README.md b/collectors/python.d.plugin/hddtemp/README.md
new file mode 100644
index 000000000..1236186a5
--- /dev/null
+++ b/collectors/python.d.plugin/hddtemp/README.md
@@ -0,0 +1,22 @@
+# hddtemp
+
+Module monitors disk temperatures from one or more hddtemp daemons.
+
+**Requirement:**
+Running `hddtemp` in daemonized mode with access on tcp port
+
+It produces one chart **Temperature** with dynamic number of dimensions (one per disk)
+
+### configuration
+
+Sample:
+
+```yaml
+update_every: 3
+host: "127.0.0.1"
+port: 7634
+```
+
+If no configuration is given, module will attempt to connect to hddtemp daemon on `127.0.0.1:7634` address
+
+---
diff --git a/collectors/python.d.plugin/hddtemp/hddtemp.chart.py b/collectors/python.d.plugin/hddtemp/hddtemp.chart.py
new file mode 100644
index 000000000..dea701171
--- /dev/null
+++ b/collectors/python.d.plugin/hddtemp/hddtemp.chart.py
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+# Description: hddtemp netdata python.d module
+# Author: Pawel Krupa (paulfantom)
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+
+import re
+
+from copy import deepcopy
+
+from bases.FrameworkServices.SocketService import SocketService
+
+
+ORDER = ['temperatures']
+
+CHARTS = {
+ 'temperatures': {
+ 'options': ['disks_temp', 'Disks Temperatures', 'Celsius', 'temperatures', 'hddtemp.temperatures', 'line'],
+ 'lines': [
+ # lines are created dynamically in `check()` method
+ ]}}
+
+RE = re.compile(r'\/dev\/([^|]+)\|([^|]+)\|([0-9]+|SLP|UNK)\|')
+
+
+class Disk:
+ def __init__(self, id_, name, temp):
+ self.id = id_.split('/')[-1]
+ self.name = name.replace(' ', '_')
+ self.temp = temp if temp.isdigit() else 0
+
+ def __repr__(self):
+ return self.id
+
+
+class Service(SocketService):
+ def __init__(self, configuration=None, name=None):
+ SocketService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = deepcopy(CHARTS)
+ self._keep_alive = False
+ self.request = ""
+ self.host = "127.0.0.1"
+ self.port = 7634
+ self.do_only = self.configuration.get('devices')
+
+ def get_disks(self):
+ r = self._get_raw_data()
+
+ if not r:
+ return None
+
+ m = RE.findall(r)
+
+ if not m:
+ self.error("received data doesn't have needed records")
+ return None
+
+ rv = [Disk(*d) for d in m]
+ self.debug('available disks: {0}'.format(rv))
+
+ if self.do_only:
+ return [v for v in rv if v.id in self.do_only]
+ return rv
+
+ def get_data(self):
+ """
+ Get data from TCP/IP socket
+ :return: dict
+ """
+
+ disks = self.get_disks()
+
+ if not disks:
+ return None
+
+ return dict((d.id, d.temp) for d in disks)
+
+ def check(self):
+ """
+ Parse configuration, check if hddtemp is available, and dynamically create chart lines data
+ :return: boolean
+ """
+ self._parse_config()
+ disks = self.get_disks()
+
+ if not disks:
+ return False
+
+ for d in disks:
+ n = d.id if d.id.startswith('sd') else d.name
+ dim = [d.id, n]
+ self.definitions['temperatures']['lines'].append(dim)
+
+ return True
+
+ @staticmethod
+ def _check_raw_data(data):
+ return not bool(data)
diff --git a/conf.d/python.d/hddtemp.conf b/collectors/python.d.plugin/hddtemp/hddtemp.conf
index 9165798a2..9165798a2 100644
--- a/conf.d/python.d/hddtemp.conf
+++ b/collectors/python.d.plugin/hddtemp/hddtemp.conf
diff --git a/collectors/python.d.plugin/httpcheck/Makefile.inc b/collectors/python.d.plugin/httpcheck/Makefile.inc
new file mode 100644
index 000000000..4a5bd856d
--- /dev/null
+++ b/collectors/python.d.plugin/httpcheck/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += httpcheck/httpcheck.chart.py
+dist_pythonconfig_DATA += httpcheck/httpcheck.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += httpcheck/README.md httpcheck/Makefile.inc
+
diff --git a/collectors/python.d.plugin/httpcheck/README.md b/collectors/python.d.plugin/httpcheck/README.md
new file mode 100644
index 000000000..759107663
--- /dev/null
+++ b/collectors/python.d.plugin/httpcheck/README.md
@@ -0,0 +1,41 @@
+# httpcheck
+
+Module monitors remote http server for availability and response time.
+
+Following charts are drawn per job:
+
+1. **Response time** ms
+ * Time in 0.1 ms resolution in which the server responds.
+ If the connection failed, the value is missing.
+
+2. **Status** boolean
+ * Connection successful
+ * Unexpected content: No Regex match found in the response
+ * Unexpected status code: Do we get 500 errors?
+ * Connection failed: port not listening or blocked
+ * Connection timed out: host or port unreachable
+
+### configuration
+
+Sample configuration and their default values.
+
+```yaml
+server:
+ url: 'http://host:port/path' # required
+ status_accepted: # optional
+ - 200
+ timeout: 1 # optional, supports decimals (e.g. 0.2)
+ update_every: 3 # optional
+ regex: 'REGULAR_EXPRESSION' # optional, see https://docs.python.org/3/howto/regex.html
+ redirect: yes # optional
+```
+
+### notes
+
+ * The status chart is primarily intended for alarms, badges or for access via API.
+ * A system/service/firewall might block netdata's access if a portscan or
+ similar is detected.
+ * This plugin is meant for simple use cases. Currently, the accuracy of the
+ response time is low and should be used as reference only.
+
+---
diff --git a/python.d/httpcheck.chart.py b/collectors/python.d.plugin/httpcheck/httpcheck.chart.py
index b0177ff90..f046f33c0 100644
--- a/python.d/httpcheck.chart.py
+++ b/collectors/python.d.plugin/httpcheck/httpcheck.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: http check netdata python.d module
# Original Author: ccremer (github.com/ccremer)
+# SPDX-License-Identifier: GPL-3.0-or-later
import urllib3
import re
@@ -35,12 +36,14 @@ CHARTS = {
'options': [None, 'HTTP response time', 'ms', 'response', 'httpcheck.responsetime', 'line'],
'lines': [
[HTTP_RESPONSE_TIME, 'time', 'absolute', 100, 1000]
- ]},
+ ]
+ },
'response_length': {
'options': [None, 'HTTP response body length', 'characters', 'response', 'httpcheck.responselength', 'line'],
'lines': [
[HTTP_RESPONSE_LENGTH, 'length', 'absolute']
- ]},
+ ]
+ },
'status': {
'options': [None, 'HTTP status', 'boolean', 'status', 'httpcheck.status', 'line'],
'lines': [
@@ -49,7 +52,8 @@ CHARTS = {
[HTTP_BAD_STATUS, 'bad status', 'absolute'],
[HTTP_TIMEOUT, 'timeout', 'absolute'],
[HTTP_NO_CONNECTION, 'no connection', 'absolute']
- ]}
+ ]
+ }
}
@@ -87,15 +91,15 @@ class Service(UrlService):
self.process_response(content, data, status)
except urllib3.exceptions.NewConnectionError as error:
- self.debug("Connection failed: {url}. Error: {error}".format(url=url, error=error))
+ self.debug('Connection failed: {url}. Error: {error}'.format(url=url, error=error))
data[HTTP_NO_CONNECTION] = 1
except (urllib3.exceptions.TimeoutError, urllib3.exceptions.PoolError) as error:
- self.debug("Connection timed out: {url}. Error: {error}".format(url=url, error=error))
+ self.debug('Connection timed out: {url}. Error: {error}'.format(url=url, error=error))
data[HTTP_TIMEOUT] = 1
except urllib3.exceptions.HTTPError as error:
- self.debug("Connection failed: {url}. Error: {error}".format(url=url, error=error))
+ self.debug('Connection failed: {url}. Error: {error}'.format(url=url, error=error))
data[HTTP_NO_CONNECTION] = 1
except (TypeError, AttributeError) as error:
@@ -109,7 +113,7 @@ class Service(UrlService):
self.debug('Content: \n\n{content}\n'.format(content=content))
if status in self.status_codes_accepted:
if self.regex and self.regex.search(content) is None:
- self.debug("No match for regex '{regex}' found".format(regex=self.regex.pattern))
+ self.debug('No match for regex "{regex}" found'.format(regex=self.regex.pattern))
data[HTTP_BAD_CONTENT] = 1
else:
data[HTTP_SUCCESS] = 1
diff --git a/conf.d/python.d/httpcheck.conf b/collectors/python.d.plugin/httpcheck/httpcheck.conf
index 058e057a6..bd21b5af8 100644
--- a/conf.d/python.d/httpcheck.conf
+++ b/collectors/python.d.plugin/httpcheck/httpcheck.conf
@@ -66,6 +66,7 @@ chart_cleanup: 0
# url: 'http[s]://host-ip-or-dns[:port][path]'
# # [required] the remote host url to connect to. If [:port] is missing, it defaults to 80
# # for HTTP and 443 for HTTPS. [path] is optional too, defaults to /
+# method: GET # [optional] the HTTP request method (POST, PUT, DELETE, HEAD etc.)
# redirect: yes # [optional] If the remote host returns 3xx status codes, the redirection url will be
# # followed (default).
# status_accepted: # [optional] By default, 200 is accepted. Anything else will result in 'bad status' in the
diff --git a/collectors/python.d.plugin/icecast/Makefile.inc b/collectors/python.d.plugin/icecast/Makefile.inc
new file mode 100644
index 000000000..cb7c6fa0e
--- /dev/null
+++ b/collectors/python.d.plugin/icecast/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += icecast/icecast.chart.py
+dist_pythonconfig_DATA += icecast/icecast.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += icecast/README.md icecast/Makefile.inc
+
diff --git a/collectors/python.d.plugin/icecast/README.md b/collectors/python.d.plugin/icecast/README.md
new file mode 100644
index 000000000..a28a6c398
--- /dev/null
+++ b/collectors/python.d.plugin/icecast/README.md
@@ -0,0 +1,26 @@
+# icecast
+
+This module will monitor number of listeners for active sources.
+
+**Requirements:**
+ * icecast version >= 2.4.0
+
+It produces the following charts:
+
+1. **Listeners** in listeners
+ * source number
+
+### configuration
+
+Needs only `url` to server's `/status-json.xsl`
+
+Here is an example for remote server:
+
+```yaml
+remote:
+ url : 'http://1.2.3.4:8443/status-json.xsl'
+```
+
+Without configuration, module attempts to connect to `http://localhost:8443/status-json.xsl`
+
+---
diff --git a/python.d/icecast.chart.py b/collectors/python.d.plugin/icecast/icecast.chart.py
index 792b99f3f..d8813f9ba 100644
--- a/python.d/icecast.chart.py
+++ b/collectors/python.d.plugin/icecast/icecast.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: icecast netdata python.d module
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
import json
@@ -15,10 +16,10 @@ ORDER = ['listeners']
CHARTS = {
'listeners': {
- 'options': [None, 'Number Of Listeners', 'listeners',
- 'listeners', 'icecast.listeners', 'line'],
+ 'options': [None, 'Number Of Listeners', 'listeners', 'listeners', 'icecast.listeners', 'line'],
'lines': [
- ]}
+ ]
+ }
}
@@ -86,7 +87,11 @@ class Service(UrlService):
try:
data = json.loads(raw_data)
except ValueError as error:
- self.error("JSON decode error:", error)
+ self.error('JSON decode error:', error)
return None
- return data['icestats'].get('source')
+ sources = data['icestats'].get('source')
+ if not sources:
+ return None
+
+ return sources if isinstance(sources, list) else [sources]
diff --git a/conf.d/python.d/icecast.conf b/collectors/python.d.plugin/icecast/icecast.conf
index a900d06d3..a900d06d3 100644
--- a/conf.d/python.d/icecast.conf
+++ b/collectors/python.d.plugin/icecast/icecast.conf
diff --git a/collectors/python.d.plugin/ipfs/Makefile.inc b/collectors/python.d.plugin/ipfs/Makefile.inc
new file mode 100644
index 000000000..68458cb38
--- /dev/null
+++ b/collectors/python.d.plugin/ipfs/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += ipfs/ipfs.chart.py
+dist_pythonconfig_DATA += ipfs/ipfs.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += ipfs/README.md ipfs/Makefile.inc
+
diff --git a/collectors/python.d.plugin/ipfs/README.md b/collectors/python.d.plugin/ipfs/README.md
new file mode 100644
index 000000000..a30649a5f
--- /dev/null
+++ b/collectors/python.d.plugin/ipfs/README.md
@@ -0,0 +1,25 @@
+# ipfs
+
+Module monitors [IPFS](https://ipfs.io) basic information.
+
+1. **Bandwidth** in kbits/s
+ * in
+ * out
+
+2. **Peers**
+ * peers
+
+### configuration
+
+Only url to IPFS server is needed.
+
+Sample:
+
+```yaml
+localhost:
+ name : 'local'
+ url : 'http://localhost:5001'
+```
+
+---
+
diff --git a/python.d/ipfs.chart.py b/collectors/python.d.plugin/ipfs/ipfs.chart.py
index 43500dfb5..3f6794e48 100644
--- a/python.d/ipfs.chart.py
+++ b/collectors/python.d.plugin/ipfs/ipfs.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: IPFS netdata python.d module
-# Authors: Pawel Krupa (paulfantom), davidak
+# Authors: davidak
+# SPDX-License-Identifier: GPL-3.0-or-later
import json
@@ -26,31 +27,43 @@ CHARTS = {
'bandwidth': {
'options': [None, 'IPFS Bandwidth', 'kbits/s', 'Bandwidth', 'ipfs.bandwidth', 'line'],
'lines': [
- ["in", None, "absolute", 8, 1000],
- ["out", None, "absolute", -8, 1000]
- ]},
+ ['in', None, 'absolute', 8, 1000],
+ ['out', None, 'absolute', -8, 1000]
+ ]
+ },
'peers': {
'options': [None, 'IPFS Peers', 'peers', 'Peers', 'ipfs.peers', 'line'],
'lines': [
- ["peers", None, 'absolute']
- ]},
+ ['peers', None, 'absolute']
+ ]
+ },
'repo_size': {
'options': [None, 'IPFS Repo Size', 'GB', 'Size', 'ipfs.repo_size', 'area'],
'lines': [
- ["avail", None, "absolute", 1, 1e9],
- ["size", None, "absolute", 1, 1e9],
- ]},
+ ['avail', None, 'absolute', 1, 1e9],
+ ['size', None, 'absolute', 1, 1e9],
+ ]
+ },
'repo_objects': {
'options': [None, 'IPFS Repo Objects', 'objects', 'Objects', 'ipfs.repo_objects', 'line'],
'lines': [
- ["objects", None, "absolute", 1, 1],
- ["pinned", None, "absolute", 1, 1],
- ["recursive_pins", None, "absolute", 1, 1]
- ]},
+ ['objects', None, 'absolute', 1, 1],
+ ['pinned', None, 'absolute', 1, 1],
+ ['recursive_pins', None, 'absolute', 1, 1]
+ ]
+ }
}
-SI_zeroes = {'k': 3, 'm': 6, 'g': 9, 't': 12,
- 'p': 15, 'e': 18, 'z': 21, 'y': 24}
+SI_zeroes = {
+ 'k': 3,
+ 'm': 6,
+ 'g': 9,
+ 't': 12,
+ 'p': 15,
+ 'e': 18,
+ 'z': 21,
+ 'y': 24
+}
class Service(UrlService):
@@ -60,6 +73,7 @@ class Service(UrlService):
self.order = ORDER
self.definitions = CHARTS
self.__storage_max = None
+ self.do_pinapi = self.configuration.get('pinapi')
def _get_json(self, sub_url):
"""
@@ -73,7 +87,7 @@ class Service(UrlService):
@staticmethod
def _recursive_pins(keys):
- return len([k for k in keys if keys[k]["Type"] == b"recursive"])
+ return sum(1 for k in keys if keys[k]['Type'] == b'recursive')
@staticmethod
def _dehumanize(store_max):
@@ -93,7 +107,7 @@ class Service(UrlService):
def _storagemax(self, store_cfg):
if self.__storage_max is None:
- self.__storage_max = self._dehumanize(store_cfg['StorageMax'])
+ self.__storage_max = self._dehumanize(store_cfg)
return self.__storage_max
def _get_data(self):
@@ -106,13 +120,15 @@ class Service(UrlService):
'/api/v0/stats/bw':
[('in', 'RateIn', int), ('out', 'RateOut', int)],
'/api/v0/swarm/peers':
- [('peers', 'Strings', len)],
+ [('peers', 'Peers', len)],
'/api/v0/stats/repo':
- [('size', 'RepoSize', int), ('objects', 'NumObjects', int)],
- '/api/v0/pin/ls':
- [('pinned', 'Keys', len), ('recursive_pins', 'Keys', self._recursive_pins)],
- '/api/v0/config/show': [('avail', 'Datastore', self._storagemax)]
+ [('size', 'RepoSize', int), ('objects', 'NumObjects', int), ('avail', 'StorageMax', self._storagemax)],
}
+ if self.do_pinapi:
+ cfg.update({
+ '/api/v0/pin/ls':
+ [('pinned', 'Keys', len), ('recursive_pins', 'Keys', self._recursive_pins)]
+ })
r = dict()
for suburl in cfg:
in_json = self._get_json(suburl)
diff --git a/conf.d/python.d/ipfs.conf b/collectors/python.d.plugin/ipfs/ipfs.conf
index c247c1b7a..e3df0f6bb 100644
--- a/conf.d/python.d/ipfs.conf
+++ b/collectors/python.d.plugin/ipfs/ipfs.conf
@@ -64,11 +64,16 @@
# Additionally to the above, ipfs also supports the following:
#
# url: 'URL' # URL to the IPFS API
+# pinapi: no # Set status of IPFS pinned object polling
+# # Currently defaults to disabled due to IPFS Bug
+# # https://github.com/ipfs/go-ipfs/issues/3874
+# # resulting in very high CPU Usage
#
# ----------------------------------------------------------------------
# AUTO-DETECTION JOBS
# only one of them will run (they have the same name)
localhost:
- name : 'local'
- url : 'http://localhost:5001'
+ name : 'local'
+ url : 'http://localhost:5001'
+ pinapi : no
diff --git a/collectors/python.d.plugin/isc_dhcpd/Makefile.inc b/collectors/python.d.plugin/isc_dhcpd/Makefile.inc
new file mode 100644
index 000000000..44343fc9d
--- /dev/null
+++ b/collectors/python.d.plugin/isc_dhcpd/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += isc_dhcpd/isc_dhcpd.chart.py
+dist_pythonconfig_DATA += isc_dhcpd/isc_dhcpd.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += isc_dhcpd/README.md isc_dhcpd/Makefile.inc
+
diff --git a/collectors/python.d.plugin/isc_dhcpd/README.md b/collectors/python.d.plugin/isc_dhcpd/README.md
new file mode 100644
index 000000000..334d86e33
--- /dev/null
+++ b/collectors/python.d.plugin/isc_dhcpd/README.md
@@ -0,0 +1,34 @@
+# isc_dhcpd
+
+Module monitor leases database to show all active leases for given pools.
+
+**Requirements:**
+ * dhcpd leases file MUST BE readable by netdata
+ * pools MUST BE in CIDR format
+
+It produces:
+
+1. **Pools utilization** Aggregate chart for all pools.
+ * utilization in percent
+
+2. **Total leases**
+ * leases (overall number of leases for all pools)
+
+3. **Active leases** for every pools
+ * leases (number of active leases in pool)
+
+
+### configuration
+
+Sample:
+
+```yaml
+local:
+ leases_path : '/var/lib/dhcp/dhcpd.leases'
+ pools : '192.168.3.0/24 192.168.4.0/24 192.168.5.0/24'
+```
+
+In case of python2 you need to install `py2-ipaddress` to make plugin work.
+The module will not work If no configuration is given.
+
+---
diff --git a/python.d/isc_dhcpd.chart.py b/collectors/python.d.plugin/isc_dhcpd/isc_dhcpd.chart.py
index eb6338452..a9f274949 100644
--- a/python.d/isc_dhcpd.chart.py
+++ b/collectors/python.d.plugin/isc_dhcpd/isc_dhcpd.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: isc dhcpd lease netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
import os
import re
@@ -25,17 +26,18 @@ ORDER = ['pools_utilization', 'pools_active_leases', 'leases_total']
CHARTS = {
'pools_utilization': {
- 'options': [None, 'Pools Utilization', '%', 'utilization',
- 'isc_dhcpd.utilization', 'line'],
- 'lines': []},
+ 'options': [None, 'Pools Utilization', '%', 'utilization', 'isc_dhcpd.utilization', 'line'],
+ 'lines': []
+ },
'pools_active_leases': {
- 'options': [None, 'Active Leases Per Pool', 'leases', 'active leases',
- 'isc_dhcpd.active_leases', 'line'],
- 'lines': []},
+ 'options': [None, 'Active Leases Per Pool', 'leases', 'active leases', 'isc_dhcpd.active_leases', 'line'],
+ 'lines': []
+ },
'leases_total': {
- 'options': [None, 'All Active Leases', 'leases', 'active leases',
- 'isc_dhcpd.leases_total', 'line'],
- 'lines': [['leases_total', 'leases', 'absolute']],
+ 'options': [None, 'All Active Leases', 'leases', 'active leases', 'isc_dhcpd.leases_total', 'line'],
+ 'lines': [
+ ['leases_total', 'leases', 'absolute']
+ ],
'variables': [
['leases_size']
]
diff --git a/conf.d/python.d/isc_dhcpd.conf b/collectors/python.d.plugin/isc_dhcpd/isc_dhcpd.conf
index 4a4c4a5e3..4a4c4a5e3 100644
--- a/conf.d/python.d/isc_dhcpd.conf
+++ b/collectors/python.d.plugin/isc_dhcpd/isc_dhcpd.conf
diff --git a/collectors/python.d.plugin/linux_power_supply/Makefile.inc b/collectors/python.d.plugin/linux_power_supply/Makefile.inc
new file mode 100644
index 000000000..1864ba524
--- /dev/null
+++ b/collectors/python.d.plugin/linux_power_supply/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += linux_power_supply/linux_power_supply.chart.py
+dist_pythonconfig_DATA += linux_power_supply/linux_power_supply.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += linux_power_supply/README.md linux_power_supply/Makefile.inc
+
diff --git a/collectors/python.d.plugin/linux_power_supply/README.md b/collectors/python.d.plugin/linux_power_supply/README.md
new file mode 100644
index 000000000..5cfbe41ce
--- /dev/null
+++ b/collectors/python.d.plugin/linux_power_supply/README.md
@@ -0,0 +1,67 @@
+# linux\_power\_supply
+
+This module monitors variosu metrics reported by power supply drivers
+on Linux. This allows tracking and alerting on things like remaining
+battery capacity.
+
+Depending on the uderlying driver, it may provide the following charts
+and metrics:
+
+1. Capacity: The power supply capacity expressed as a percentage.
+ * capacity\_now
+
+2. Charge: The charge for the power supply, expressed as microamphours.
+ * charge\_full\_design
+ * charge\_full
+ * charge\_now
+ * charge\_empty
+ * charge\_empty\_design
+
+3. Energy: The energy for the power supply, expressed as microwatthours.
+ * energy\_full\_design
+ * energy\_full
+ * energy\_now
+ * energy\_empty
+ * energy\_empty\_design
+
+2. Voltage: The voltage for the power supply, expressed as microvolts.
+ * voltage\_max\_design
+ * voltage\_max
+ * voltage\_now
+ * voltage\_min
+ * voltage\_min\_design
+
+### configuration
+
+Sample:
+
+```yaml
+battery:
+ supply: 'BAT0'
+ charts: 'capacity charge energy voltage'
+```
+
+The `supply` key specifies the name of the power supply device to monitor.
+You can use `ls /sys/class/power_supply` to get a list of such devices
+on your system.
+
+The `charts` key is a space separated list of which charts to try
+to display. It defaults to trying to display everything.
+
+### notes
+
+* Most drivers provide at least the first chart. Battery powered ACPI
+compliant systems (like most laptops) provide all but the third, but do
+not provide all of the metrics for each chart.
+
+* Current, energy, and voltages are reported with a _very_ high precision
+by the power\_supply framework. Usually, this is far higher than the
+actual hardware supports reporting, so expect to see changes in these
+charts jump instead of scaling smoothly.
+
+* If `max` or `full` attribute is defined by the driver, but not a
+corresponding `min or `empty` attribute, then netdata will still provide
+the corresponding `min` or `empty`, which will then always read as zero.
+This way, alerts which match on these will still work.
+
+---
diff --git a/collectors/python.d.plugin/linux_power_supply/linux_power_supply.chart.py b/collectors/python.d.plugin/linux_power_supply/linux_power_supply.chart.py
new file mode 100644
index 000000000..71d834e5d
--- /dev/null
+++ b/collectors/python.d.plugin/linux_power_supply/linux_power_supply.chart.py
@@ -0,0 +1,160 @@
+# -*- coding: utf-8 -*-
+# Description: Linux power_supply netdata python.d module
+# Author: Austin S. Hemmelgarn (Ferroin)
+
+import os
+import platform
+
+from bases.FrameworkServices.SimpleService import SimpleService
+
+# Everything except percentages is reported as µ units.
+PRECISION = 10 ** 6
+
+# A priority of 90000 places us next to the other PSU related stuff.
+PRIORITY = 90000
+
+# We add our charts dynamically when we probe for the device attributes,
+# so these are empty by default.
+ORDER = []
+
+CHARTS = {}
+
+
+def get_capacity_chart(syspath):
+ # Capacity is measured in percent. We track one value.
+ options = [None, 'Capacity', '%', 'power_supply', 'power_supply.capacity', 'line']
+ lines = list()
+ attr_now = 'capacity'
+ if get_sysfs_value(os.path.join(syspath, attr_now)) is not None:
+ lines.append([attr_now, attr_now, 'absolute', 1, 1])
+ return {'capacity': {'options': options, 'lines': lines}}, [attr_now]
+ else:
+ return None, None
+
+
+def get_generic_chart(syspath, name, unit, maxname, minname):
+ # Used to generate charts for energy, charge, and voltage.
+ options = [None, name.title(), unit, 'power_supply', 'power_supply.{0}'.format(name), 'line']
+ lines = list()
+ attrlist = list()
+ attr_max_design = '{0}_{1}_design'.format(name, maxname)
+ attr_max = '{0}_{1}'.format(name, maxname)
+ attr_now = '{0}_now'.format(name)
+ attr_min = '{0}_{1}'.format(name, minname)
+ attr_min_design = '{0}_{1}_design'.format(name, minname)
+ if get_sysfs_value(os.path.join(syspath, attr_now)) is not None:
+ lines.append([attr_now, attr_now, 'absolute', 1, PRECISION])
+ attrlist.append(attr_now)
+ else:
+ return None, None
+ if get_sysfs_value(os.path.join(syspath, attr_max)) is not None:
+ lines.insert(0, [attr_max, attr_max, 'absolute', 1, PRECISION])
+ lines.append([attr_min, attr_min, 'absolute', 1, PRECISION])
+ attrlist.append(attr_max)
+ attrlist.append(attr_min)
+ elif get_sysfs_value(os.path.join(syspath, attr_min)) is not None:
+ lines.append([attr_min, attr_min, 'absolute', 1, PRECISION])
+ attrlist.append(attr_min)
+ if get_sysfs_value(os.path.join(syspath, attr_max_design)) is not None:
+ lines.insert(0, [attr_max_design, attr_max_design, 'absolute', 1, PRECISION])
+ lines.append([attr_min_design, attr_min_design, 'absolute', 1, PRECISION])
+ attrlist.append(attr_max_design)
+ attrlist.append(attr_min_design)
+ elif get_sysfs_value(os.path.join(syspath, attr_min_design)) is not None:
+ lines.append([attr_min_design, attr_min_design, 'absolute', 1, PRECISION])
+ attrlist.append(attr_min_design)
+ return {name: {'options': options, 'lines': lines}}, attrlist
+
+
+def get_charge_chart(syspath):
+ # Charge is measured in microamphours. We track up to five
+ # attributes.
+ return get_generic_chart(syspath, 'charge', 'µAh', 'full', 'empty')
+
+
+def get_energy_chart(syspath):
+ # Energy is measured in microwatthours. We track up to five
+ # attributes.
+ return get_generic_chart(syspath, 'energy', 'µWh', 'full', 'empty')
+
+
+def get_voltage_chart(syspath):
+ # Voltage is measured in microvolts. We track up to five attributes.
+ return get_generic_chart(syspath, 'voltage', 'µV', 'min', 'max')
+
+
+# This is a list of functions for generating charts. Used below to save
+# a bit of code (and to make it a bit easier to add new charts).
+GET_CHART = {
+ 'capacity': get_capacity_chart,
+ 'charge': get_charge_chart,
+ 'energy': get_energy_chart,
+ 'voltage': get_voltage_chart
+}
+
+
+# This opens the specified file and returns the value in it or None if
+# the file doesn't exist.
+def get_sysfs_value(filepath):
+ try:
+ with open(filepath, 'r') as datasource:
+ return int(datasource.read())
+ except (OSError, IOError):
+ return None
+
+
+class Service(SimpleService):
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.definitions = dict()
+ self.order = list()
+ self.attrlist = list()
+ self.supply = self.configuration.get('supply', None)
+ if self.supply is not None:
+ self.syspath = '/sys/class/power_supply/{0}'.format(self.supply)
+ self.types = self.configuration.get('charts', 'capacity').split()
+
+ def check(self):
+ if platform.system() != 'Linux':
+ self.error('Only supported on Linux.')
+ return False
+ if self.supply is None:
+ self.error('No power supply specified for monitoring.')
+ return False
+ if not self.types:
+ self.error('No attributes requested for monitoring.')
+ return False
+ if not os.access(self.syspath, os.R_OK):
+ self.error('Unable to access {0}'.format(self.syspath))
+ return False
+ return self.create_charts()
+
+ def create_charts(self):
+ chartset = set(GET_CHART).intersection(set(self.types))
+ if not chartset:
+ self.error('No valid attributes requested for monitoring.')
+ return False
+ charts = dict()
+ attrlist = list()
+ for item in chartset:
+ chart, attrs = GET_CHART[item](self.syspath)
+ if chart is not None:
+ charts.update(chart)
+ attrlist.extend(attrs)
+ if len(charts) == 0:
+ self.error('No charts can be created.')
+ return False
+ self.definitions.update(charts)
+ self.order.extend(sorted(charts))
+ self.attrlist.extend(attrlist)
+ return True
+
+ def _get_data(self):
+ data = dict()
+ for attr in self.attrlist:
+ attrpath = os.path.join(self.syspath, attr)
+ if attr.endswith(('_min', '_min_design', '_empty', '_empty_design')):
+ data[attr] = get_sysfs_value(attrpath) or 0
+ else:
+ data[attr] = get_sysfs_value(attrpath)
+ return data
diff --git a/collectors/python.d.plugin/linux_power_supply/linux_power_supply.conf b/collectors/python.d.plugin/linux_power_supply/linux_power_supply.conf
new file mode 100644
index 000000000..3cb610f7f
--- /dev/null
+++ b/collectors/python.d.plugin/linux_power_supply/linux_power_supply.conf
@@ -0,0 +1,81 @@
+# netdata python.d.plugin configuration for linux_power_supply
+#
+# 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_everye
+# and only if the module has collected values in the past.
+# retries: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# In addition to the above parameters, linux_power_supply also supports
+# the following extra parameters.
+#
+# supply: '' # the name of the power supply to monitor
+# charts: 'capacity' # a space separated list of the charts to try
+# # and generate valid charts are 'capacity',
+# # 'charge', 'current', and 'voltage'
+#
+# Note that linux_power_supply will not automatically detect power
+# supplies in the system, you have to manually specify which ones you
+# want it to monitor.
+#
+# The following config will work to monitor the first battery in most
+# ACPI compliant battery powered systems (such as most laptops).
+#
+# battery:
+# name: battery
+# supply: BAT0
diff --git a/collectors/python.d.plugin/litespeed/Makefile.inc b/collectors/python.d.plugin/litespeed/Makefile.inc
new file mode 100644
index 000000000..5dd645020
--- /dev/null
+++ b/collectors/python.d.plugin/litespeed/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += litespeed/litespeed.chart.py
+dist_pythonconfig_DATA += litespeed/litespeed.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += litespeed/README.md litespeed/Makefile.inc
+
diff --git a/collectors/python.d.plugin/litespeed/README.md b/collectors/python.d.plugin/litespeed/README.md
new file mode 100644
index 000000000..d1482f33c
--- /dev/null
+++ b/collectors/python.d.plugin/litespeed/README.md
@@ -0,0 +1,47 @@
+# litespeed
+
+Module monitor litespeed web server performance metrics.
+
+It produces:
+
+1. **Network Throughput HTTP** in kilobits/s
+ * in
+ * out
+
+2. **Network Throughput HTTPS** in kilobits/s
+ * in
+ * out
+
+3. **Connections HTTP** in connections
+ * free
+ * used
+
+4. **Connections HTTPS** in connections
+ * free
+ * used
+
+5. **Requests** in requests/s
+ * requests
+
+6. **Requests In Processing** in requests
+ * processing
+
+7. **Public Cache Hits** in hits/s
+ * hits
+
+8. **Private Cache Hits** in hits/s
+ * hits
+
+9. **Static Hits** in hits/s
+ * hits
+
+
+### configuration
+```yaml
+local:
+ path : 'PATH'
+```
+
+If no configuration is given, module will use "/tmp/lshttpd/".
+
+---
diff --git a/collectors/python.d.plugin/litespeed/litespeed.chart.py b/collectors/python.d.plugin/litespeed/litespeed.chart.py
new file mode 100644
index 000000000..efdc6869c
--- /dev/null
+++ b/collectors/python.d.plugin/litespeed/litespeed.chart.py
@@ -0,0 +1,186 @@
+# -*- coding: utf-8 -*-
+# Description: litespeed netdata python.d module
+# Author: Ilya Maschenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import glob
+import re
+import os
+
+from collections import namedtuple
+
+from bases.FrameworkServices.SimpleService import SimpleService
+
+
+update_every = 10
+
+# charts order (can be overridden if you want less charts, or different order)
+ORDER = [
+ 'net_throughput_http', 'net_throughput_https', # net throughput
+ 'connections_http', 'connections_https', # connections
+ 'requests', 'requests_processing', # requests
+ 'pub_cache_hits', 'private_cache_hits', # cache
+ 'static_hits' # static
+]
+
+CHARTS = {
+ 'net_throughput_http': {
+ 'options': [None, 'Network Throughput HTTP', 'kilobits/s', 'net throughput',
+ 'litespeed.net_throughput', 'area'],
+ 'lines': [
+ ['bps_in', 'in', 'absolute'],
+ ['bps_out', 'out', 'absolute', -1]
+ ]
+ },
+ 'net_throughput_https': {
+ 'options': [None, 'Network Throughput HTTPS', 'kilobits/s', 'net throughput',
+ 'litespeed.net_throughput', 'area'],
+ 'lines': [
+ ['ssl_bps_in', 'in', 'absolute'],
+ ['ssl_bps_out', 'out', 'absolute', -1]
+ ]
+ },
+ 'connections_http': {
+ 'options': [None, 'Connections HTTP', 'conns', 'connections', 'litespeed.connections', 'stacked'],
+ 'lines': [
+ ['conn_free', 'free', 'absolute'],
+ ['conn_used', 'used', 'absolute']
+ ]
+ },
+ 'connections_https': {
+ 'options': [None, 'Connections HTTPS', 'conns', 'connections', 'litespeed.connections', 'stacked'],
+ 'lines': [
+ ['ssl_conn_free', 'free', 'absolute'],
+ ['ssl_conn_used', 'used', 'absolute']
+ ]
+ },
+ 'requests': {
+ 'options': [None, 'Requests', 'requests/s', 'requests', 'litespeed.requests', 'line'],
+ 'lines': [
+ ['requests', None, 'absolute', 1, 100]
+ ]
+ },
+ 'requests_processing': {
+ 'options': [None, 'Requests In Processing', 'requests', 'requests', 'litespeed.requests_processing', 'line'],
+ 'lines': [
+ ['requests_processing', 'processing', 'absolute']
+ ]
+ },
+ 'pub_cache_hits': {
+ 'options': [None, 'Public Cache Hits', 'hits/s', 'cache', 'litespeed.cache', 'line'],
+ 'lines': [
+ ['pub_cache_hits', 'hits', 'absolute', 1, 100]
+ ]
+ },
+ 'private_cache_hits': {
+ 'options': [None, 'Private Cache Hits', 'hits/s', 'cache', 'litespeed.cache', 'line'],
+ 'lines': [
+ ['private_cache_hits', 'hits', 'absolute', 1, 100]
+ ]
+ },
+ 'static_hits': {
+ 'options': [None, 'Static Hits', 'hits/s', 'static', 'litespeed.static', 'line'],
+ 'lines': [
+ ['static_hits', 'hits', 'absolute', 1, 100]
+ ]
+ }
+}
+
+t = namedtuple('T', ['key', 'id', 'mul'])
+
+T = [
+ t('BPS_IN', 'bps_in', 8),
+ t('BPS_OUT', 'bps_out', 8),
+ t('SSL_BPS_IN', 'ssl_bps_in', 8),
+ t('SSL_BPS_OUT', 'ssl_bps_out', 8),
+ t('REQ_PER_SEC', 'requests', 100),
+ t('REQ_PROCESSING', 'requests_processing', 1),
+ t('PUB_CACHE_HITS_PER_SEC', 'pub_cache_hits', 100),
+ t('PRIVATE_CACHE_HITS_PER_SEC', 'private_cache_hits', 100),
+ t('STATIC_HITS_PER_SEC', 'static_hits', 100),
+ t('PLAINCONN', 'conn_used', 1),
+ t('AVAILCONN', 'conn_free', 1),
+ t('SSLCONN', 'ssl_conn_used', 1),
+ t('AVAILSSL', 'ssl_conn_free', 1),
+]
+
+RE = re.compile(r'([A-Z_]+): ([0-9.]+)')
+
+ZERO_DATA = {
+ 'bps_in': 0,
+ 'bps_out': 0,
+ 'ssl_bps_in': 0,
+ 'ssl_bps_out': 0,
+ 'requests': 0,
+ 'requests_processing': 0,
+ 'pub_cache_hits': 0,
+ 'private_cache_hits': 0,
+ 'static_hits': 0,
+ 'conn_used': 0,
+ 'conn_free': 0,
+ 'ssl_conn_used': 0,
+ 'ssl_conn_free': 0,
+}
+
+
+class Service(SimpleService):
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+ self.path = self.configuration.get('path', '/tmp/lshttpd/')
+ self.files = list()
+
+ def check(self):
+ if not self.path:
+ self.error('"path" not specified')
+ return False
+
+ fs = glob.glob(os.path.join(self.path, '.rtreport*'))
+
+ if not fs:
+ self.error('"{0}" has no "rtreport" files or dir is not readable'.format(self.path))
+ return None
+
+ self.debug('stats files:', fs)
+
+ for f in fs:
+ if not is_readable_file(f):
+ self.error('{0} is not readable'.format(f))
+ continue
+ self.files.append(f)
+
+ return bool(self.files)
+
+ def get_data(self):
+ """
+ Format data received from http request
+ :return: dict
+ """
+ data = dict(ZERO_DATA)
+
+ for f in self.files:
+ try:
+ with open(f) as b:
+ lines = b.readlines()
+ except (OSError, IOError) as err:
+ self.error(err)
+ return None
+ else:
+ parse_file(data, lines)
+
+ return data
+
+
+def parse_file(data, lines):
+ for line in lines:
+ if not line.startswith(('BPS_IN:', 'MAXCONN:', 'REQ_RATE []:')):
+ continue
+ m = dict(RE.findall(line))
+ for v in T:
+ if v.key in m:
+ data[v.id] += float(m[v.key]) * v.mul
+
+
+def is_readable_file(v):
+ return os.path.isfile(v) and os.access(v, os.R_OK)
diff --git a/collectors/python.d.plugin/litespeed/litespeed.conf b/collectors/python.d.plugin/litespeed/litespeed.conf
new file mode 100644
index 000000000..17d0f690e
--- /dev/null
+++ b/collectors/python.d.plugin/litespeed/litespeed.conf
@@ -0,0 +1,74 @@
+# netdata python.d.plugin configuration for litespeed
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# Additionally to the above, lightspeed also supports the following:
+#
+# path: 'PATH' # path to lightspeed stats files directory
+#
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
+# only one of them will run (they have the same name)
+
+localhost:
+ name : 'local'
+ path : '/tmp/lshttpd/'
diff --git a/collectors/python.d.plugin/logind/Makefile.inc b/collectors/python.d.plugin/logind/Makefile.inc
new file mode 100644
index 000000000..adadab120
--- /dev/null
+++ b/collectors/python.d.plugin/logind/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += logind/logind.chart.py
+dist_pythonconfig_DATA += logind/logind.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += logind/README.md logind/Makefile.inc
+
diff --git a/collectors/python.d.plugin/logind/README.md b/collectors/python.d.plugin/logind/README.md
new file mode 100644
index 000000000..8f8670d4a
--- /dev/null
+++ b/collectors/python.d.plugin/logind/README.md
@@ -0,0 +1,54 @@
+# logind
+
+This module monitors active sessions, users, and seats tracked by systemd-logind or elogind.
+
+It provides the following charts:
+
+1. **Sessions** Tracks the total number of sessions.
+ * Graphical: Local graphical sessions (running X11, or Wayland, or something else).
+ * Console: Local console sessions.
+ * Remote: Remote sessions.
+
+2. **Users** Tracks total number of unique user logins of each type.
+ * Graphical
+ * Console
+ * Remote
+
+3. **Seats** Total number of seats in use.
+ * Seats
+
+### configuration
+
+This module needs no configuration. Just make sure the netdata user
+can run the `loginctl` command and get a session list without having to
+specify a path.
+
+This will work with any command that can output data in the _exact_
+same format as `loginctl list-sessions --no-legend`. If you have some
+other command you want to use that outputs data in this format, you can
+specify it using the `command` key like so:
+
+```yaml
+command: '/path/to/other/command'
+```
+
+### notes
+
+* This module's ability to track logins is dependent on what PAM services
+are configured to register sessions with logind. In particular, for
+most systems, it will only track TTY logins, local desktop logins,
+and logins through remote shell connections.
+
+* The users chart counts _usernames_ not UID's. This is potentially
+important in configurations where multiple users have the same UID.
+
+* The users chart counts any given user name up to once for _each_ type
+of login. So if the same user has a graphical and a console login on a
+system, they will show up once in the graphical count, and once in the
+console count.
+
+* Because the data collection process is rather expensive, this plugin
+is currently disabled by default, and needs to be explicitly enabled in
+`/etc/netdata/python.d.conf` before it will run.
+
+---
diff --git a/collectors/python.d.plugin/logind/logind.chart.py b/collectors/python.d.plugin/logind/logind.chart.py
new file mode 100644
index 000000000..bfc486c7f
--- /dev/null
+++ b/collectors/python.d.plugin/logind/logind.chart.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+# Description: logind netdata python.d module
+# Author: Austin S. Hemmelgarn (Ferroin)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from bases.FrameworkServices.ExecutableService import ExecutableService
+
+priority = 59999
+disabled_by_default = True
+
+ORDER = ['sessions', 'users', 'seats']
+
+CHARTS = {
+ 'sessions': {
+ 'options': [None, 'Logind Sessions', 'sessions', 'sessions', 'logind.sessions', 'stacked'],
+ 'lines': [
+ ['sessions_graphical', 'Graphical', 'absolute', 1, 1],
+ ['sessions_console', 'Console', 'absolute', 1, 1],
+ ['sessions_remote', 'Remote', 'absolute', 1, 1]
+ ]
+ },
+ 'users': {
+ 'options': [None, 'Logind Users', 'users', 'users', 'logind.users', 'stacked'],
+ 'lines': [
+ ['users_graphical', 'Graphical', 'absolute', 1, 1],
+ ['users_console', 'Console', 'absolute', 1, 1],
+ ['users_remote', 'Remote', 'absolute', 1, 1]
+ ]
+ },
+ 'seats': {
+ 'options': [None, 'Logind Seats', 'seats', 'seats', 'logind.seats', 'line'],
+ 'lines': [
+ ['seats', 'Active Seats', 'absolute', 1, 1]
+ ]
+ }
+}
+
+
+class Service(ExecutableService):
+ def __init__(self, configuration=None, name=None):
+ ExecutableService.__init__(self, configuration=configuration, name=name)
+ self.command = 'loginctl list-sessions --no-legend'
+ self.order = ORDER
+ self.definitions = CHARTS
+
+ def _get_data(self):
+ ret = {
+ 'sessions_graphical': 0,
+ 'sessions_console': 0,
+ 'sessions_remote': 0,
+ }
+ users = {
+ 'graphical': list(),
+ 'console': list(),
+ 'remote': list()
+ }
+ seats = list()
+ data = self._get_raw_data()
+
+ for item in data:
+ fields = item.split()
+ if len(fields) == 3:
+ users['remote'].append(fields[2])
+ ret['sessions_remote'] += 1
+ elif len(fields) == 4:
+ users['graphical'].append(fields[2])
+ ret['sessions_graphical'] += 1
+ seats.append(fields[3])
+ elif len(fields) == 5:
+ users['console'].append(fields[2])
+ ret['sessions_console'] += 1
+ seats.append(fields[3])
+
+ ret['users_graphical'] = len(set(users['graphical']))
+ ret['users_console'] = len(set(users['console']))
+ ret['users_remote'] = len(set(users['remote']))
+ ret['seats'] = len(set(seats))
+
+ return ret
diff --git a/collectors/python.d.plugin/logind/logind.conf b/collectors/python.d.plugin/logind/logind.conf
new file mode 100644
index 000000000..0623493de
--- /dev/null
+++ b/collectors/python.d.plugin/logind/logind.conf
@@ -0,0 +1,62 @@
+# netdata python.d.plugin configuration for logind
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
diff --git a/collectors/python.d.plugin/mdstat/Makefile.inc b/collectors/python.d.plugin/mdstat/Makefile.inc
new file mode 100644
index 000000000..5125a271b
--- /dev/null
+++ b/collectors/python.d.plugin/mdstat/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += mdstat/mdstat.chart.py
+dist_pythonconfig_DATA += mdstat/mdstat.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += mdstat/README.md mdstat/Makefile.inc
+
diff --git a/collectors/python.d.plugin/mdstat/README.md b/collectors/python.d.plugin/mdstat/README.md
new file mode 100644
index 000000000..1ff8f7dab
--- /dev/null
+++ b/collectors/python.d.plugin/mdstat/README.md
@@ -0,0 +1,26 @@
+# mdstat
+
+Module monitor /proc/mdstat
+
+It produces:
+
+1. **Health** Number of failed disks in every array (aggregate chart).
+
+2. **Disks stats**
+ * total (number of devices array ideally would have)
+ * inuse (number of devices currently are in use)
+
+3. **Current status**
+ * resync in percent
+ * recovery in percent
+ * reshape in percent
+ * check in percent
+
+4. **Operation status** (if resync/recovery/reshape/check is active)
+ * finish in minutes
+ * speed in megabytes/s
+
+### configuration
+No configuration is needed.
+
+---
diff --git a/collectors/python.d.plugin/mdstat/mdstat.chart.py b/collectors/python.d.plugin/mdstat/mdstat.chart.py
new file mode 100644
index 000000000..b7306b6a7
--- /dev/null
+++ b/collectors/python.d.plugin/mdstat/mdstat.chart.py
@@ -0,0 +1,205 @@
+# -*- coding: utf-8 -*-
+# Description: mdstat netdata python.d module
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import re
+
+from collections import defaultdict
+
+from bases.FrameworkServices.SimpleService import SimpleService
+
+MDSTAT = '/proc/mdstat'
+MISMATCH_CNT = '/sys/block/{0}/md/mismatch_cnt'
+
+ORDER = ['mdstat_health']
+
+CHARTS = {
+ 'mdstat_health': {
+ 'options': [None, 'Faulty Devices In MD', 'failed disks', 'health', 'md.health', 'line'],
+ 'lines': []
+ }
+}
+
+RE_DISKS = re.compile(r' (?P<array>[a-zA-Z_0-9]+) : active .+\['
+ r'(?P<total_disks>[0-9]+)/'
+ r'(?P<inuse_disks>[0-9]+)\]')
+
+RE_STATUS = re.compile(r' (?P<array>[a-zA-Z_0-9]+) : active .+ '
+ r'(?P<operation>[a-z]+) =[ ]{1,2}'
+ r'(?P<operation_status>[0-9.]+).+finish='
+ r'(?P<finish_in>([0-9.]+))min speed='
+ r'(?P<speed>[0-9]+)')
+
+
+def md_charts(name):
+ order = [
+ '{0}_disks'.format(name),
+ '{0}_operation'.format(name),
+ '{0}_mismatch_cnt'.format(name),
+ '{0}_finish'.format(name),
+ '{0}_speed'.format(name)
+ ]
+
+ charts = dict()
+ charts[order[0]] = {
+ 'options': [None, 'Disks Stats', 'disks', name, 'md.disks', 'stacked'],
+ 'lines': [
+ ['{0}_total_disks'.format(name), 'total', 'absolute'],
+ ['{0}_inuse_disks'.format(name), 'inuse', 'absolute']
+ ]
+ }
+
+ charts[order[1]] = {
+ 'options': [None, 'Current Status', 'percent', name, 'md.status', 'line'],
+ 'lines': [
+ ['{0}_resync'.format(name), 'resync', 'absolute', 1, 100],
+ ['{0}_recovery'.format(name), 'recovery', 'absolute', 1, 100],
+ ['{0}_reshape'.format(name), 'reshape', 'absolute', 1, 100],
+ ['{0}_check'.format(name), 'check', 'absolute', 1, 100],
+ ]
+ }
+
+ charts[order[2]] = {
+ 'options': [None, 'Mismatch Count', 'unsynchronized blocks', name, 'md.mismatch_cnt', 'line'],
+ 'lines': [
+ ['{0}_mismatch_cnt'.format(name), 'count', 'absolute']
+ ]
+ }
+
+ charts[order[3]] = {
+ 'options': [None, 'Approximate Time Until Finish', 'seconds', name, 'md.rate', 'line'],
+ 'lines': [
+ ['{0}_finish_in'.format(name), 'finish in', 'absolute', 1, 1000]
+ ]
+ }
+
+ charts[order[4]] = {
+ 'options': [None, 'Operation Speed', 'KB/s', name, 'md.rate', 'line'],
+ 'lines': [
+ ['{0}_speed'.format(name), 'speed', 'absolute', 1, 1000]
+ ]
+ }
+
+ return order, charts
+
+
+class MD:
+ def __init__(self, raw_data):
+ self.name = raw_data['array']
+ self.d = raw_data
+
+ def data(self):
+ rv = {
+ 'total_disks': self.d['total_disks'],
+ 'inuse_disks': self.d['inuse_disks'],
+ 'health': int(self.d['total_disks']) - int(self.d['inuse_disks']),
+ 'resync': 0,
+ 'recovery': 0,
+ 'reshape': 0,
+ 'check': 0,
+ 'finish_in': 0,
+ 'speed': 0,
+ }
+
+ v = read_lines(MISMATCH_CNT.format(self.name))
+ if v:
+ rv['mismatch_cnt'] = v
+
+ if self.d.get('operation'):
+ rv[self.d['operation']] = float(self.d['operation_status']) * 100
+ rv['finish_in'] = float(self.d['finish_in']) * 1000 * 60
+ rv['speed'] = float(self.d['speed']) * 1000
+
+ return dict(('{0}_{1}'.format(self.name, k), v) for k, v in rv.items())
+
+
+class Service(SimpleService):
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+ self.mds = list()
+
+ @staticmethod
+ def get_mds():
+ raw = read_lines(MDSTAT)
+
+ if not raw:
+ return None
+
+ return find_mds(raw)
+
+ def get_data(self):
+ """
+ Parse data from _get_raw_data()
+ :return: dict
+ """
+ mds = self.get_mds()
+
+ if not mds:
+ return None
+
+ data = dict()
+ for md in mds:
+ if md.name not in self.mds:
+ self.mds.append(md.name)
+ self.add_new_md_charts(md.name)
+ data.update(md.data())
+ return data
+
+ def check(self):
+ if not self.get_mds():
+ self.error('Failed to read data from {0} or there is no active arrays'.format(MDSTAT))
+ return False
+ return True
+
+ def add_new_md_charts(self, name):
+ order, charts = md_charts(name)
+
+ self.charts['mdstat_health'].add_dimension(['{0}_health'.format(name), name])
+
+ for chart_name in order:
+ params = [chart_name] + charts[chart_name]['options']
+ dims = charts[chart_name]['lines']
+
+ chart = self.charts.add_chart(params)
+ for dim in dims:
+ chart.add_dimension(dim)
+
+
+def find_mds(raw_data):
+ data = defaultdict(str)
+ counter = 1
+
+ for row in (elem.strip() for elem in raw_data):
+ if not row:
+ counter += 1
+ continue
+ data[counter] = ' '.join([data[counter], row])
+
+ mds = list()
+
+ for v in data.values():
+ m = RE_DISKS.search(v)
+
+ if not m:
+ continue
+
+ d = m.groupdict()
+
+ m = RE_STATUS.search(v)
+ if m:
+ d.update(m.groupdict())
+
+ mds.append(MD(d))
+
+ return sorted(mds, key=lambda md: md.name)
+
+
+def read_lines(path):
+ try:
+ with open(path) as f:
+ return f.readlines()
+ except (IOError, OSError):
+ return None
diff --git a/conf.d/python.d/mdstat.conf b/collectors/python.d.plugin/mdstat/mdstat.conf
index 66a2f153c..66a2f153c 100644
--- a/conf.d/python.d/mdstat.conf
+++ b/collectors/python.d.plugin/mdstat/mdstat.conf
diff --git a/collectors/python.d.plugin/megacli/Makefile.inc b/collectors/python.d.plugin/megacli/Makefile.inc
new file mode 100644
index 000000000..83680d723
--- /dev/null
+++ b/collectors/python.d.plugin/megacli/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += megacli/megacli.chart.py
+dist_pythonconfig_DATA += megacli/megacli.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += megacli/README.md megacli/Makefile.inc
+
diff --git a/collectors/python.d.plugin/megacli/README.md b/collectors/python.d.plugin/megacli/README.md
new file mode 100644
index 000000000..d288a6353
--- /dev/null
+++ b/collectors/python.d.plugin/megacli/README.md
@@ -0,0 +1,48 @@
+# megacli
+
+Module collects adapter, physical drives and battery stats.
+
+**Requirements:**
+ * `megacli` program
+ * `sudo` program
+ * `netdata` user needs to be able to be able to sudo the `megacli` program without password
+
+To grab stats it executes:
+ * `sudo -n megacli -LDPDInfo -aAll`
+ * `sudo -n megacli -AdpBbuCmd -a0`
+
+
+It produces:
+
+1. **Adapter State**
+
+2. **Physical Drives Media Errors**
+
+3. **Physical Drives Predictive Failures**
+
+4. **Battery Relative State of Charge**
+
+5. **Battery Cycle Count**
+
+### prerequisite
+This module uses `megacli` which can only be executed by root. It uses
+`sudo` and assumes that it is configured such that the `netdata` user can
+execute `megacli` as root without password.
+
+Add to `sudoers`:
+
+ netdata ALL=(root) NOPASSWD: /path/to/megacli
+
+### configuration
+
+**megacli** is disabled by default. Should be explicitly enabled in `python.d.conf`.
+```yaml
+megacli: yes
+```
+
+Battery stats disabled by default. To enable them modify `megacli.conf`.
+```yaml
+do_battery: yes
+```
+
+---
diff --git a/collectors/python.d.plugin/megacli/megacli.chart.py b/collectors/python.d.plugin/megacli/megacli.chart.py
new file mode 100644
index 000000000..41a1079f6
--- /dev/null
+++ b/collectors/python.d.plugin/megacli/megacli.chart.py
@@ -0,0 +1,279 @@
+# -*- coding: utf-8 -*-
+# Description: megacli netdata python.d module
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+
+import re
+
+from bases.FrameworkServices.ExecutableService import ExecutableService
+from bases.collection import find_binary
+
+
+disabled_by_default = True
+
+update_every = 5
+
+
+def adapter_charts(ads):
+ order = [
+ 'adapter_degraded',
+ ]
+
+ def dims(ad):
+ return [['adapter_{0}_degraded'.format(a.id), 'adapter {0}'.format(a.id)] for a in ad]
+
+ charts = {
+ 'adapter_degraded': {
+ 'options': [None, 'Adapter State', 'is degraded', 'adapter', 'megacli.adapter_degraded', 'line'],
+ 'lines': dims(ads)
+ },
+ }
+
+ return order, charts
+
+
+def pd_charts(pds):
+ order = [
+ 'pd_media_error',
+ 'pd_predictive_failure',
+ ]
+
+ def dims(k, pd):
+ return [['slot_{0}_{1}'.format(p.id, k), 'slot {0}'.format(p.id), 'incremental'] for p in pd]
+
+ charts = {
+ 'pd_media_error': {
+ 'options': [None, 'Physical Drives Media Errors', 'errors/s', 'pd', 'megacli.pd_media_error', 'line'],
+ 'lines': dims('media_error', pds)
+ },
+ 'pd_predictive_failure': {
+ 'options': [None, 'Physical Drives Predictive Failures', 'failures/s', 'pd',
+ 'megacli.pd_predictive_failure', 'line'],
+ 'lines': dims('predictive_failure', pds)
+ }
+ }
+
+ return order, charts
+
+
+def battery_charts(bats):
+ order = list()
+ charts = dict()
+
+ for b in bats:
+ order.append('bbu_{0}_relative_charge'.format(b.id))
+ charts.update(
+ {
+ 'bbu_{0}_relative_charge'.format(b.id): {
+ 'options': [None, 'Relative State of Charge', '%', 'battery',
+ 'megacli.bbu_relative_charge', 'line'],
+ 'lines': [
+ ['bbu_{0}_relative_charge'.format(b.id), 'adapter {0}'.format(b.id)],
+ ]
+ }
+ }
+ )
+
+ for b in bats:
+ order.append('bbu_{0}_cycle_count'.format(b.id))
+ charts.update(
+ {
+ 'bbu_{0}_cycle_count'.format(b.id): {
+ 'options': [None, 'Cycle Count', 'cycle count', 'battery', 'megacli.bbu_cycle_count', 'line'],
+ 'lines': [
+ ['bbu_{0}_cycle_count'.format(b.id), 'adapter {0}'.format(b.id)],
+ ]
+ }
+ }
+ )
+
+ return order, charts
+
+
+RE_ADAPTER = re.compile(
+ r'Adapter #([0-9]+) State(?:\s+)?: ([a-zA-Z]+)'
+)
+
+RE_VD = re.compile(
+ r'Slot Number: ([0-9]+) Media Error Count: ([0-9]+) Predictive Failure Count: ([0-9]+)'
+)
+
+RE_BATTERY = re.compile(
+ r'BBU Capacity Info for Adapter: ([0-9]+) Relative State of Charge: ([0-9]+) % Cycle Count: ([0-9]+)'
+)
+
+
+def find_adapters(d):
+ keys = ('Adapter #', 'State')
+ d = ' '.join(v.strip() for v in d if v.startswith(keys))
+ return [Adapter(*v) for v in RE_ADAPTER.findall(d)]
+
+
+def find_pds(d):
+ keys = ('Slot Number', 'Media Error Count', 'Predictive Failure Count')
+ d = ' '.join(v.strip() for v in d if v.startswith(keys))
+ return [PD(*v) for v in RE_VD.findall(d)]
+
+
+def find_batteries(d):
+ keys = ('BBU Capacity Info for Adapter', 'Relative State of Charge', 'Cycle Count')
+ d = ' '.join(v.strip() for v in d if v.strip().startswith(keys))
+ return [Battery(*v) for v in RE_BATTERY.findall(d)]
+
+
+class Adapter:
+ def __init__(self, n, state):
+ self.id = n
+ self.state = int(state == 'Degraded')
+
+ def data(self):
+ return {
+ 'adapter_{0}_degraded'.format(self.id): self.state,
+ }
+
+
+class PD:
+ def __init__(self, n, media_err, predict_fail):
+ self.id = n
+ self.media_err = media_err
+ self.predict_fail = predict_fail
+
+ def data(self):
+ return {
+ 'slot_{0}_media_error'.format(self.id): self.media_err,
+ 'slot_{0}_predictive_failure'.format(self.id): self.predict_fail,
+ }
+
+
+class Battery:
+ def __init__(self, adapt_id, rel_charge, cycle_count):
+ self.id = adapt_id
+ self.rel_charge = rel_charge
+ self.cycle_count = cycle_count
+
+ def data(self):
+ return {
+ 'bbu_{0}_relative_charge'.format(self.id): self.rel_charge,
+ 'bbu_{0}_cycle_count'.format(self.id): self.cycle_count,
+ }
+
+
+# TODO: hardcoded sudo...
+class Megacli:
+ def __init__(self):
+ self.s = find_binary('sudo')
+ self.m = find_binary('megacli')
+ self.sudo_check = [self.s, '-n', '-v']
+ self.disk_info = [self.s, '-n', self.m, '-LDPDInfo', '-aAll', '-NoLog']
+ self.battery_info = [self.s, '-n', self.m, '-AdpBbuCmd', '-a0', '-NoLog']
+
+ def __bool__(self):
+ return bool(self.s and self.m)
+
+ def __nonzero__(self):
+ return self.__bool__()
+
+
+class Service(ExecutableService):
+ def __init__(self, configuration=None, name=None):
+ ExecutableService.__init__(self, configuration=configuration, name=name)
+ self.order = list()
+ self.definitions = dict()
+ self.megacli = Megacli()
+ self.do_battery = self.configuration.get('do_battery')
+
+ def check_sudo(self):
+ err = self._get_raw_data(command=self.megacli.sudo_check, stderr=True)
+ if err:
+ self.error(''.join(err))
+ return False
+ return True
+
+ def check_disk_info(self):
+ d = self._get_raw_data(command=self.megacli.disk_info)
+ if not d:
+ return False
+
+ ads = find_adapters(d)
+ pds = find_pds(d)
+
+ if not (ads and pds):
+ self.error('failed to parse "{0}" output'.format(' '.join(self.megacli.disk_info)))
+ return False
+
+ o, c = adapter_charts(ads)
+ self.order.extend(o)
+ self.definitions.update(c)
+
+ o, c = pd_charts(pds)
+ self.order.extend(o)
+ self.definitions.update(c)
+
+ return True
+
+ def check_battery(self):
+ d = self._get_raw_data(command=self.megacli.battery_info)
+ if not d:
+ return False
+
+ bats = find_batteries(d)
+
+ if not bats:
+ self.error('failed to parse "{0}" output'.format(' '.join(self.megacli.battery_info)))
+ return False
+
+ o, c = battery_charts(bats)
+ self.order.extend(o)
+ self.definitions.update(c)
+ return True
+
+ def check(self):
+ if not self.megacli:
+ self.error('can\'t locate "sudo" or "megacli" binary')
+ return None
+
+ if not (self.check_sudo() and self.check_disk_info()):
+ return False
+
+ if self.do_battery:
+ self.do_battery = self.check_battery()
+
+ return True
+
+ def get_data(self):
+ data = dict()
+
+ data.update(self.get_adapter_pd_data())
+
+ if self.do_battery:
+ data.update(self.get_battery_data())
+
+ return data or None
+
+ def get_adapter_pd_data(self):
+ raw = self._get_raw_data(command=self.megacli.disk_info)
+ data = dict()
+
+ if not raw:
+ return data
+
+ for a in find_adapters(raw):
+ data.update(a.data())
+
+ for p in find_pds(raw):
+ data.update(p.data())
+
+ return data
+
+ def get_battery_data(self):
+ raw = self._get_raw_data(command=self.megacli.battery_info)
+ data = dict()
+
+ if not raw:
+ return data
+
+ for b in find_batteries(raw):
+ data.update(b.data())
+
+ return data
diff --git a/collectors/python.d.plugin/megacli/megacli.conf b/collectors/python.d.plugin/megacli/megacli.conf
new file mode 100644
index 000000000..73afb2f7f
--- /dev/null
+++ b/collectors/python.d.plugin/megacli/megacli.conf
@@ -0,0 +1,62 @@
+# netdata python.d.plugin configuration for megacli
+#
+# This file is in YaML format. Generally the format is:
+#
+# name: value
+#
+
+# ----------------------------------------------------------------------
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# Additionally to the above, megacli also supports the following:
+#
+# do_battery: yes/no # default is no. Battery stats (adds additional call to megacli `megacli -AdpBbuCmd -a0`).
+#
+# ----------------------------------------------------------------------
+# uncomment the line below to collect battery statistics
+# do_battery: yes
diff --git a/collectors/python.d.plugin/memcached/Makefile.inc b/collectors/python.d.plugin/memcached/Makefile.inc
new file mode 100644
index 000000000..e60357161
--- /dev/null
+++ b/collectors/python.d.plugin/memcached/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += memcached/memcached.chart.py
+dist_pythonconfig_DATA += memcached/memcached.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += memcached/README.md memcached/Makefile.inc
+
diff --git a/collectors/python.d.plugin/memcached/README.md b/collectors/python.d.plugin/memcached/README.md
new file mode 100644
index 000000000..3521c109d
--- /dev/null
+++ b/collectors/python.d.plugin/memcached/README.md
@@ -0,0 +1,69 @@
+# memcached
+
+Memcached monitoring module. Data grabbed from [stats interface](https://github.com/memcached/memcached/wiki/Commands#stats).
+
+1. **Network** in kilobytes/s
+ * read
+ * written
+
+2. **Connections** per second
+ * current
+ * rejected
+ * total
+
+3. **Items** in cluster
+ * current
+ * total
+
+4. **Evicted and Reclaimed** items
+ * evicted
+ * reclaimed
+
+5. **GET** requests/s
+ * hits
+ * misses
+
+6. **GET rate** rate in requests/s
+ * rate
+
+7. **SET rate** rate in requests/s
+ * rate
+
+8. **DELETE** requests/s
+ * hits
+ * misses
+
+9. **CAS** requests/s
+ * hits
+ * misses
+ * bad value
+
+10. **Increment** requests/s
+ * hits
+ * misses
+
+11. **Decrement** requests/s
+ * hits
+ * misses
+
+12. **Touch** requests/s
+ * hits
+ * misses
+
+13. **Touch rate** rate in requests/s
+ * rate
+
+### configuration
+
+Sample:
+
+```yaml
+localtcpip:
+ name : 'local'
+ host : '127.0.0.1'
+ port : 24242
+```
+
+If no configuration is given, module will attempt to connect to memcached instance on `127.0.0.1:11211` address.
+
+---
diff --git a/python.d/memcached.chart.py b/collectors/python.d.plugin/memcached/memcached.chart.py
index 4f7adfa23..3c310ec69 100644
--- a/python.d/memcached.chart.py
+++ b/collectors/python.d.plugin/memcached/memcached.chart.py
@@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
# Description: memcached netdata python.d module
# Author: Pawel Krupa (paulfantom)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.FrameworkServices.SocketService import SocketService
# default module values (can be overridden per job in `config`)
-#update_every = 2
+# update_every = 2
priority = 60000
retries = 60
@@ -28,92 +29,106 @@ CHARTS = {
'lines': [
['avail', 'available', 'absolute', 1, 1048576],
['used', 'used', 'absolute', 1, 1048576]
- ]},
+ ]
+ },
'net': {
'options': [None, 'Network', 'kilobits/s', 'network', 'memcached.net', 'area'],
'lines': [
['bytes_read', 'in', 'incremental', 8, 1024],
['bytes_written', 'out', 'incremental', -8, 1024]
- ]},
+ ]
+ },
'connections': {
'options': [None, 'Connections', 'connections/s', 'connections', 'memcached.connections', 'line'],
'lines': [
['curr_connections', 'current', 'incremental'],
['rejected_connections', 'rejected', 'incremental'],
['total_connections', 'total', 'incremental']
- ]},
+ ]
+ },
'items': {
'options': [None, 'Items', 'items', 'items', 'memcached.items', 'line'],
'lines': [
['curr_items', 'current', 'absolute'],
['total_items', 'total', 'absolute']
- ]},
+ ]
+ },
'evicted_reclaimed': {
'options': [None, 'Items', 'items', 'items', 'memcached.evicted_reclaimed', 'line'],
'lines': [
['reclaimed', 'reclaimed', 'absolute'],
['evictions', 'evicted', 'absolute']
- ]},
+ ]
+ },
'get': {
'options': [None, 'Requests', 'requests', 'get ops', 'memcached.get', 'stacked'],
'lines': [
['get_hits', 'hits', 'percent-of-absolute-row'],
['get_misses', 'misses', 'percent-of-absolute-row']
- ]},
+ ]
+ },
'get_rate': {
'options': [None, 'Rate', 'requests/s', 'get ops', 'memcached.get_rate', 'line'],
'lines': [
['cmd_get', 'rate', 'incremental']
- ]},
+ ]
+ },
'set_rate': {
'options': [None, 'Rate', 'requests/s', 'set ops', 'memcached.set_rate', 'line'],
'lines': [
['cmd_set', 'rate', 'incremental']
- ]},
+ ]
+ },
'delete': {
'options': [None, 'Requests', 'requests', 'delete ops', 'memcached.delete', 'stacked'],
'lines': [
['delete_hits', 'hits', 'percent-of-absolute-row'],
['delete_misses', 'misses', 'percent-of-absolute-row'],
- ]},
+ ]
+ },
'cas': {
'options': [None, 'Requests', 'requests', 'check and set ops', 'memcached.cas', 'stacked'],
'lines': [
['cas_hits', 'hits', 'percent-of-absolute-row'],
['cas_misses', 'misses', 'percent-of-absolute-row'],
['cas_badval', 'bad value', 'percent-of-absolute-row']
- ]},
+ ]
+ },
'increment': {
'options': [None, 'Requests', 'requests', 'increment ops', 'memcached.increment', 'stacked'],
'lines': [
['incr_hits', 'hits', 'percent-of-absolute-row'],
['incr_misses', 'misses', 'percent-of-absolute-row']
- ]},
+ ]
+ },
'decrement': {
'options': [None, 'Requests', 'requests', 'decrement ops', 'memcached.decrement', 'stacked'],
'lines': [
['decr_hits', 'hits', 'percent-of-absolute-row'],
['decr_misses', 'misses', 'percent-of-absolute-row']
- ]},
+ ]
+ },
'touch': {
'options': [None, 'Requests', 'requests', 'touch ops', 'memcached.touch', 'stacked'],
'lines': [
['touch_hits', 'hits', 'percent-of-absolute-row'],
['touch_misses', 'misses', 'percent-of-absolute-row']
- ]},
+ ]
+ },
'touch_rate': {
'options': [None, 'Rate', 'requests/s', 'touch ops', 'memcached.touch_rate', 'line'],
'lines': [
['cmd_touch', 'rate', 'incremental']
- ]}
+ ]
+ }
}
class Service(SocketService):
def __init__(self, configuration=None, name=None):
SocketService.__init__(self, configuration=configuration, name=name)
- self.request = "stats\r\n"
- self.host = "localhost"
+ self.request = 'stats\r\n'
+ self.host = 'localhost'
self.port = 11211
self._keep_alive = True
self.unix_socket = None
@@ -131,13 +146,13 @@ class Service(SocketService):
return None
if response.startswith('ERROR'):
- self.error("received ERROR")
+ self.error('received ERROR')
return None
try:
- parsed = response.split("\n")
+ parsed = response.split('\n')
except AttributeError:
- self.error("response is invalid/empty")
+ self.error('response is invalid/empty')
return None
# split the response
@@ -148,7 +163,7 @@ class Service(SocketService):
t = line[5:].split(' ')
data[t[0]] = t[1]
except (IndexError, ValueError):
- self.debug("invalid line received: " + str(line))
+ self.debug('invalid line received: ' + str(line))
if not data:
self.error("received data doesn't have any records")
@@ -165,10 +180,10 @@ class Service(SocketService):
def _check_raw_data(self, data):
if data.endswith('END\r\n'):
- self.debug("received full response from memcached")
+ self.debug('received full response from memcached')
return True
- self.debug("waiting more data from memcached")
+ self.debug('waiting more data from memcached')
return False
def check(self):
diff --git a/conf.d/python.d/memcached.conf b/collectors/python.d.plugin/memcached/memcached.conf
index 85c3daf65..85c3daf65 100644
--- a/conf.d/python.d/memcached.conf
+++ b/collectors/python.d.plugin/memcached/memcached.conf
diff --git a/collectors/python.d.plugin/mongodb/Makefile.inc b/collectors/python.d.plugin/mongodb/Makefile.inc
new file mode 100644
index 000000000..784945aa6
--- /dev/null
+++ b/collectors/python.d.plugin/mongodb/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += mongodb/mongodb.chart.py
+dist_pythonconfig_DATA += mongodb/mongodb.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += mongodb/README.md mongodb/Makefile.inc
+
diff --git a/collectors/python.d.plugin/mongodb/README.md b/collectors/python.d.plugin/mongodb/README.md
new file mode 100644
index 000000000..8e5f652c5
--- /dev/null
+++ b/collectors/python.d.plugin/mongodb/README.md
@@ -0,0 +1,141 @@
+# mongodb
+
+Module monitor mongodb performance and health metrics
+
+**Requirements:**
+ * `python-pymongo` package v2.4+.
+
+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
+
+---
diff --git a/python.d/mongodb.chart.py b/collectors/python.d.plugin/mongodb/mongodb.chart.py
index 909a419da..10344342d 100644
--- a/python.d/mongodb.chart.py
+++ b/collectors/python.d.plugin/mongodb/mongodb.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: mongodb netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
from copy import deepcopy
from datetime import datetime
@@ -31,7 +32,8 @@ REPL_SET_STATES = [
('6', 'unknown'),
('9', 'rollback'),
('10', 'removed'),
- ('0', 'startup')]
+ ('0', 'startup')
+]
def multiply_by_100(value):
@@ -141,12 +143,37 @@ DBSTATS = [
]
# 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']
+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': {
@@ -155,7 +182,8 @@ CHARTS = {
'lines': [
['query', None, 'incremental'],
['getmore', None, 'incremental']
- ]},
+ ]
+ },
'write_operations': {
'options': [None, 'Received write requests', 'requests/s', 'throughput metrics',
'mongodb.write_operations', 'line'],
@@ -163,57 +191,66 @@ CHARTS = {
['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'],
@@ -221,14 +258,16 @@ CHARTS = {
['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': [
@@ -236,60 +275,70 @@ CHARTS = {
['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',
+ 'options': [None, 'Currently queued read and write 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'],
+ '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': [
- ]},
+ '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': [
@@ -299,7 +348,8 @@ CHARTS = {
['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': [
@@ -310,7 +360,8 @@ CHARTS = {
['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': [
@@ -321,7 +372,8 @@ CHARTS = {
['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'],
@@ -330,7 +382,8 @@ CHARTS = {
['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'],
@@ -339,7 +392,8 @@ CHARTS = {
['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'],
@@ -348,21 +402,24 @@ CHARTS = {
['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': [
['oplog_r', 'intent_shared', 'incremental'],
['oplog_w', 'intent_exclusive', 'incremental']
- ]}
+ ]
+ }
}
@@ -383,7 +440,7 @@ class Service(SimpleService):
def check(self):
if not PYMONGO:
- self.error('Pymongo module is needed to use mongodb.chart.py')
+ self.error('Pymongo package v2.4+ is needed to use mongodb.chart.py')
return False
self.connection, server_status, error = self._create_connection()
if error:
@@ -491,9 +548,10 @@ class Service(SimpleService):
# 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'],
+ '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')
@@ -561,9 +619,9 @@ class Service(SimpleService):
raw_data['getReplicationInfo'] = dict()
try:
raw_data['getReplicationInfo']['ASCENDING'] = self.connection.local.oplog.rs.find().sort(
- "$natural", ASCENDING).limit(1)[0]
+ '$natural', ASCENDING).limit(1)[0]
raw_data['getReplicationInfo']['DESCENDING'] = self.connection.local.oplog.rs.find().sort(
- "$natural", DESCENDING).limit(1)[0]
+ '$natural', DESCENDING).limit(1)[0]
return raw_data
except PyMongoError:
return None
diff --git a/conf.d/python.d/mongodb.conf b/collectors/python.d.plugin/mongodb/mongodb.conf
index 62faef68d..62faef68d 100644
--- a/conf.d/python.d/mongodb.conf
+++ b/collectors/python.d.plugin/mongodb/mongodb.conf
diff --git a/collectors/python.d.plugin/monit/Makefile.inc b/collectors/python.d.plugin/monit/Makefile.inc
new file mode 100644
index 000000000..4a3673fd5
--- /dev/null
+++ b/collectors/python.d.plugin/monit/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += monit/monit.chart.py
+dist_pythonconfig_DATA += monit/monit.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += monit/README.md monit/Makefile.inc
+
diff --git a/collectors/python.d.plugin/monit/README.md b/collectors/python.d.plugin/monit/README.md
new file mode 100644
index 000000000..6d10240c9
--- /dev/null
+++ b/collectors/python.d.plugin/monit/README.md
@@ -0,0 +1,33 @@
+# monit
+
+Monit monitoring module. Data is grabbed from stats XML interface (exists for a long time, but not mentioned in official documentation). Mostly this plugin shows statuses of monit targets, i.e. [statuses of specified checks](https://mmonit.com/monit/documentation/monit.html#Service-checks).
+
+1. **Filesystems**
+ * Filesystems
+ * Directories
+ * Files
+ * Pipes
+
+2. **Applications**
+ * Processes (+threads/childs)
+ * Programs
+
+3. **Network**
+ * Hosts (+latency)
+ * Network interfaces
+
+### configuration
+
+Sample:
+
+```yaml
+local:
+ name : 'local'
+ url : 'http://localhost:2812'
+ user: : admin
+ pass: : monit
+```
+
+If no configuration is given, module will attempt to connect to monit as `http://localhost:2812`.
+
+---
diff --git a/collectors/python.d.plugin/monit/monit.chart.py b/collectors/python.d.plugin/monit/monit.chart.py
new file mode 100644
index 000000000..51943c0e1
--- /dev/null
+++ b/collectors/python.d.plugin/monit/monit.chart.py
@@ -0,0 +1,166 @@
+# -*- coding: utf-8 -*-
+# Description: monit netdata python.d module
+# Author: Evgeniy K. (n0guest)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import xml.etree.ElementTree as ET
+from bases.FrameworkServices.UrlService import UrlService
+
+# default module values (can be overridden per job in `config`)
+# update_every = 2
+priority = 60000
+retries = 60
+
+# see enum State_Type from monit.h (https://bitbucket.org/tildeslash/monit/src/master/src/monit.h)
+MONIT_SERVICE_NAMES = ['Filesystem', 'Directory', 'File', 'Process', 'Host', 'System', 'Fifo', 'Program', 'Net']
+DEFAULT_SERVICES_IDS = [0, 1, 2, 3, 4, 6, 7, 8]
+
+# charts order (can be overridden if you want less charts, or different order)
+ORDER = [
+ 'filesystem',
+ 'directory',
+ 'file',
+ 'process',
+ 'process_uptime',
+ 'process_threads',
+ 'process_children',
+ 'host',
+ 'host_latency',
+ 'system',
+ 'fifo',
+ 'program',
+ 'net'
+]
+CHARTS = {
+ 'filesystem': {
+ 'options': ['filesystems', 'Filesystems', 'filesystems', 'filesystem', 'monit.filesystems', 'line'],
+ 'lines': []
+ },
+ 'directory': {
+ 'options': ['directories', 'Directories', 'directories', 'filesystem', 'monit.directories', 'line'],
+ 'lines': []
+ },
+ 'file': {
+ 'options': ['files', 'Files', 'files', 'filesystem', 'monit.files', 'line'],
+ 'lines': []
+ },
+ 'fifo': {
+ 'options': ['fifos', 'Pipes (fifo)', 'pipes', 'filesystem', 'monit.fifos', 'line'],
+ 'lines': []
+ },
+ 'program': {
+ 'options': ['programs', 'Programs statuses', 'programs', 'applications', 'monit.programs', 'line'],
+ 'lines': []
+ },
+ 'process': {
+ 'options': ['processes', 'Processes statuses', 'processes', 'applications', 'monit.services', 'line'],
+ 'lines': []
+ },
+ 'process_uptime': {
+ 'options': ['processes uptime', 'Processes uptime', 'seconds', 'applications',
+ 'monit.process_uptime', 'line', 'hidden'],
+ 'lines': []
+ },
+ 'process_threads': {
+ 'options': ['processes threads', 'Processes threads', 'threads', 'applications',
+ 'monit.process_threads', 'line'],
+ 'lines': []
+ },
+ 'process_children': {
+ 'options': ['processes childrens', 'Child processes', 'childrens', 'applications',
+ 'monit.process_childrens', 'line'],
+ 'lines': []
+ },
+ 'host': {
+ 'options': ['hosts', 'Hosts', 'hosts', 'network', 'monit.hosts', 'line'],
+ 'lines': []
+ },
+ 'host_latency': {
+ 'options': ['hosts latency', 'Hosts latency', 'milliseconds/s', 'network', 'monit.host_latency', 'line'],
+ 'lines': []
+ },
+ 'net': {
+ 'options': ['interfaces', 'Network interfaces and addresses', 'interfaces', 'network',
+ 'monit.networks', 'line'],
+ 'lines': []
+ },
+}
+
+
+class Service(UrlService):
+ def __init__(self, configuration=None, name=None):
+ UrlService.__init__(self, configuration=configuration, name=name)
+ base_url = self.configuration.get('url', 'http://localhost:2812')
+ self.url = '{0}/_status?format=xml&level=full'.format(base_url)
+ self.order = ORDER
+ self.definitions = CHARTS
+
+ def parse(self, data):
+ try:
+ xml = ET.fromstring(data)
+ except ET.ParseError:
+ self.error("URL {0} didn't return a vaild XML page. Please check your settings.".format(self.url))
+ return None
+ return xml
+
+ def check(self):
+ self._manager = self._build_manager()
+ raw_data = self._get_raw_data()
+ if not raw_data:
+ return None
+ return bool(self.parse(raw_data))
+
+ def _get_data(self):
+ raw_data = self._get_raw_data()
+ if not raw_data:
+ return None
+ xml = self.parse(raw_data)
+ if not xml:
+ return None
+
+ data = {}
+ for service_id in DEFAULT_SERVICES_IDS:
+ service_category = MONIT_SERVICE_NAMES[service_id].lower()
+ if service_category == 'system':
+ self.debug("Skipping service from 'System' category, because it's useless in graphs")
+ continue
+
+ xpath_query = "./service[@type='{0}']".format(service_id)
+ self.debug('Searching for {0} as {1}'.format(service_category, xpath_query))
+ for service_node in xml.findall(xpath_query):
+
+ service_name = service_node.find('name').text
+ service_status = service_node.find('status').text
+ service_monitoring = service_node.find('monitor').text
+ self.debug('=> found {0} with type={1}, status={2}, monitoring={3}'.format(service_name,
+ service_id, service_status, service_monitoring))
+
+ dimension_key = service_category + '_' + service_name
+ if dimension_key not in self.charts[service_category]:
+ self.charts[service_category].add_dimension([dimension_key, service_name, 'absolute'])
+ data[dimension_key] = 1 if service_status == '0' and service_monitoring == '1' else 0
+
+ if service_category == 'process':
+ for subnode in ('uptime', 'threads', 'children'):
+ subnode_value = service_node.find(subnode)
+ if subnode_value is None:
+ continue
+ if subnode == 'uptime' and int(subnode_value.text) < 0:
+ self.debug('Skipping bugged metrics with negative uptime (monit before v5.16')
+ continue
+ dimension_key = 'process_{0}_{1}'.format(subnode, service_name)
+ if dimension_key not in self.charts['process_' + subnode]:
+ self.charts['process_' + subnode].add_dimension([dimension_key, service_name, 'absolute'])
+ data[dimension_key] = int(subnode_value.text)
+
+ if service_category == 'host':
+ subnode_value = service_node.find('./icmp/responsetime')
+ if subnode_value is None:
+ continue
+ dimension_key = 'host_latency_{0}'.format(service_name)
+ if dimension_key not in self.charts['host_latency']:
+ self.charts['host_latency'].add_dimension([dimension_key, service_name,
+ 'absolute', 1000, 1000000])
+ data[dimension_key] = float(subnode_value.text) * 1000000
+
+ return data or None
diff --git a/collectors/python.d.plugin/monit/monit.conf b/collectors/python.d.plugin/monit/monit.conf
new file mode 100644
index 000000000..f9c26dbc3
--- /dev/null
+++ b/collectors/python.d.plugin/monit/monit.conf
@@ -0,0 +1,88 @@
+# netdata python.d.plugin configuration for monit
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# Additionally to the above, this plugin also supports the following:
+#
+# url: 'URL' # the URL to fetch monit's status stats
+#
+# if the URL is password protected, the following are supported:
+#
+# user: 'username'
+# pass: 'password'
+#
+# Example
+#
+# local:
+# name : 'Local Monit'
+# url : 'http://localhost:2812'
+#
+# "local" will show up in Netdata logs. "Reverse Proxy" will show up in the menu
+# in the monit section.
+
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
+# only one of them will run (they have the same name)
+
+localhost:
+ name : 'local'
+ url : 'http://localhost:2812'
diff --git a/collectors/python.d.plugin/mysql/Makefile.inc b/collectors/python.d.plugin/mysql/Makefile.inc
new file mode 100644
index 000000000..03e8b65eb
--- /dev/null
+++ b/collectors/python.d.plugin/mysql/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += mysql/mysql.chart.py
+dist_pythonconfig_DATA += mysql/mysql.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += mysql/README.md mysql/Makefile.inc
+
diff --git a/collectors/python.d.plugin/mysql/README.md b/collectors/python.d.plugin/mysql/README.md
new file mode 100644
index 000000000..e38098e7e
--- /dev/null
+++ b/collectors/python.d.plugin/mysql/README.md
@@ -0,0 +1,90 @@
+# mysql
+
+Module monitors one or more mysql servers
+
+**Requirements:**
+ * python library [MySQLdb](https://github.com/PyMySQL/mysqlclient-python) (faster) or [PyMySQL](https://github.com/PyMySQL/PyMySQL) (slower)
+
+It will produce following charts (if data is available):
+
+1. **Bandwidth** in kbps
+ * in
+ * out
+
+2. **Queries** in queries/sec
+ * queries
+ * questions
+ * slow queries
+
+3. **Operations** in operations/sec
+ * opened tables
+ * flush
+ * commit
+ * delete
+ * prepare
+ * read first
+ * read key
+ * read next
+ * read prev
+ * read random
+ * read random next
+ * rollback
+ * save point
+ * update
+ * write
+
+4. **Table Locks** in locks/sec
+ * immediate
+ * waited
+
+5. **Select Issues** in issues/sec
+ * full join
+ * full range join
+ * range
+ * range check
+ * scan
+
+6. **Sort Issues** in issues/sec
+ * merge passes
+ * range
+ * scan
+
+### configuration
+
+You can provide, per server, the following:
+
+1. username which have access to database (defaults to 'root')
+2. password (defaults to none)
+3. mysql my.cnf configuration file
+4. mysql socket (optional)
+5. mysql host (ip or hostname)
+6. mysql port (defaults to 3306)
+
+Here is an example for 3 servers:
+
+```yaml
+update_every : 10
+priority : 90100
+retries : 5
+
+local:
+ 'my.cnf' : '/etc/mysql/my.cnf'
+ priority : 90000
+
+local_2:
+ user : 'root'
+ pass : 'blablablabla'
+ socket : '/var/run/mysqld/mysqld.sock'
+ update_every : 1
+
+remote:
+ user : 'admin'
+ pass : 'bla'
+ host : 'example.org'
+ port : 9000
+ retries : 20
+```
+
+If no configuration is given, module will attempt to connect to mysql server via unix socket at `/var/run/mysqld/mysqld.sock` without password and with username `root`
+
+---
diff --git a/python.d/mysql.chart.py b/collectors/python.d.plugin/mysql/mysql.chart.py
index 4c7058b26..c4d1e8b3a 100644
--- a/python.d/mysql.chart.py
+++ b/collectors/python.d.plugin/mysql/mysql.chart.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
# Description: MySQL netdata python.d module
# Author: Pawel Krupa (paulfantom)
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.FrameworkServices.MySQLService import MySQLService
@@ -12,118 +14,127 @@ retries = 60
# query executed on MySQL server
QUERY_GLOBAL = 'SHOW GLOBAL STATUS;'
QUERY_SLAVE = 'SHOW SLAVE STATUS;'
+QUERY_VARIABLES = 'SHOW GLOBAL VARIABLES LIKE \'max_connections\';'
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',
- 'wsrep_local_recv_queue',
- 'wsrep_local_send_queue',
- 'wsrep_received',
- 'wsrep_replicated',
- 'wsrep_received_bytes',
- 'wsrep_replicated_bytes',
- 'wsrep_local_bf_aborts',
- 'wsrep_local_cert_failures',
- 'wsrep_flow_control_paused_ns']
+ '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',
+ 'Max_used_connections',
+ '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',
+ 'wsrep_local_recv_queue',
+ 'wsrep_local_send_queue',
+ 'wsrep_received',
+ 'wsrep_replicated',
+ 'wsrep_received_bytes',
+ 'wsrep_replicated_bytes',
+ 'wsrep_local_bf_aborts',
+ 'wsrep_local_cert_failures',
+ 'wsrep_flow_control_paused_ns',
+ 'Com_delete',
+ 'Com_insert',
+ 'Com_select',
+ 'Com_update',
+ 'Com_replace'
+]
+
def slave_seconds(value):
try:
@@ -142,22 +153,56 @@ SLAVE_STATS = [
('Slave_IO_Running', slave_running)
]
-ORDER = ['net',
- 'queries',
- 'handlers',
- 'table_locks',
- 'join_issues', 'sort_issues',
- 'tmp',
- 'connections', 'connection_errors',
- 'binlog_cache', 'binlog_stmt_cache',
- 'threads', 'thread_cache_misses',
- 'innodb_io', 'innodb_io_ops', 'innodb_io_pending_ops', 'innodb_log', 'innodb_os_log', 'innodb_os_log_io',
- 'innodb_cur_row_lock', 'innodb_rows', 'innodb_buffer_pool_pages', 'innodb_buffer_pool_bytes',
- 'innodb_buffer_pool_read_ahead', 'innodb_buffer_pool_reqs', 'innodb_buffer_pool_ops',
- 'qcache_ops', 'qcache', 'qcache_freemem', 'qcache_memblocks',
- 'key_blocks', 'key_requests', 'key_disk_ops',
- 'files', 'files_rate', 'slave_behind', 'slave_status',
- 'galera_writesets', 'galera_bytes', 'galera_queue', 'galera_conflicts', 'galera_flow_control']
+VARIABLES = [
+ 'max_connections'
+]
+
+ORDER = [
+ 'net',
+ 'queries',
+ 'queries_type',
+ 'handlers',
+ 'table_locks',
+ 'join_issues',
+ 'sort_issues',
+ 'tmp',
+ 'connections',
+ 'connections_active',
+ 'connection_errors',
+ 'binlog_cache',
+ 'binlog_stmt_cache',
+ 'threads',
+ 'thread_cache_misses',
+ 'innodb_io',
+ 'innodb_io_ops',
+ 'innodb_io_pending_ops',
+ 'innodb_log',
+ 'innodb_os_log',
+ 'innodb_os_log_io',
+ 'innodb_cur_row_lock',
+ 'innodb_rows',
+ 'innodb_buffer_pool_pages',
+ 'innodb_buffer_pool_bytes',
+ 'innodb_buffer_pool_read_ahead',
+ 'innodb_buffer_pool_reqs',
+ 'innodb_buffer_pool_ops',
+ 'qcache_ops',
+ 'qcache',
+ 'qcache_freemem',
+ 'qcache_memblocks',
+ 'key_blocks',
+ 'key_requests',
+ 'key_disk_ops',
+ 'files',
+ 'files_rate',
+ 'slave_behind',
+ 'slave_status',
+ 'galera_writesets',
+ 'galera_bytes',
+ 'galera_queue',
+ 'galera_conflicts',
+ 'galera_flow_control'
+]
CHARTS = {
'net': {
@@ -165,14 +210,27 @@ CHARTS = {
'lines': [
['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_type': {
+ 'options': [None, 'mysql Query type', 'queries/s', 'query_types', 'mysql.queries_type', 'stacked'],
+ 'lines': [
+ ['Com_select', 'select', 'incremental'],
+ ['Com_delete', 'delete', 'incremental'],
+ ['Com_update', 'update', 'incremental'],
+ ['Com_insert', 'insert', 'incremental'],
+ ['Qcache_hits', 'cache_hits', 'incremental'],
+ ['Com_replace', 'replace', 'incremental']
+ ]
+ },
'handlers': {
'options': [None, 'mysql Handlers', 'handlers/s', 'handlers', 'mysql.handlers', 'line'],
'lines': [
@@ -190,13 +248,15 @@ CHARTS = {
['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]
- ]},
+ ]
+ },
'join_issues': {
'options': [None, 'mysql Select Join Issues', 'joins/s', 'issues', 'mysql.join_issues', 'line'],
'lines': [
@@ -205,33 +265,46 @@ CHARTS = {
['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']
- ]},
+ ]
+ },
'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']
- ]},
+ ]
+ },
'connections': {
'options': [None, 'mysql Connections', 'connections/s', 'connections', 'mysql.connections', 'line'],
'lines': [
['Connections', 'all', 'incremental'],
['Aborted_connects', 'aborted', 'incremental']
- ]},
+ ]
+ },
+ 'connections_active': {
+ 'options': [None, 'mysql Connections Active', 'connections', 'connections', 'mysql.connections_active', 'line'],
+ 'lines': [
+ ['Threads_connected', 'active', 'absolute'],
+ ['max_connections', 'limit', 'absolute'],
+ ['Max_used_connections', 'max_active', 'absolute']
+ ]
+ },
'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']
- ]},
+ ]
+ },
'threads': {
'options': [None, 'mysql Threads', 'threads', 'threads', 'mysql.threads', 'line'],
'lines': [
@@ -239,25 +312,29 @@ CHARTS = {
['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]
- ]},
+ ]
+ },
'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_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_io_pending_ops': {
'options': [None, 'mysql InnoDB Pending I/O Operations', 'operations', 'innodb',
'mysql.innodb_io_pending_ops', 'line'],
@@ -265,32 +342,37 @@ CHARTS = {
['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_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_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_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_rows': {
'options': [None, 'mysql InnoDB Row Operations', 'operations/s', 'innodb', 'mysql.innodb_rows', 'area'],
'lines': [
@@ -298,7 +380,8 @@ CHARTS = {
['Innodb_rows_read', 'read', 'incremental', 1, 1],
['Innodb_rows_updated', 'updated', 'incremental', 1, 1],
['Innodb_rows_deleted', 'deleted', 'incremental', -1, 1],
- ]},
+ ]
+ },
'innodb_buffer_pool_pages': {
'options': [None, 'mysql InnoDB Buffer Pool Pages', 'pages', 'innodb',
'mysql.innodb_buffer_pool_pages', 'line'],
@@ -309,13 +392,15 @@ CHARTS = {
['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_read_ahead': {
'options': [None, 'mysql InnoDB Buffer Pool Read Ahead', 'operations/s', 'innodb',
'mysql.innodb_buffer_pool_read_ahead', 'area'],
@@ -323,21 +408,24 @@ CHARTS = {
['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_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]
- ]},
+ ]
+ },
'qcache_ops': {
'options': [None, 'mysql QCache Operations', 'queries/s', 'qcache', 'mysql.qcache_ops', 'line'],
'lines': [
@@ -345,60 +433,70 @@ CHARTS = {
['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_freemem': {
'options': [None, 'mysql QCache Free Memory', 'MB', 'qcache', 'mysql.qcache_freemem', 'area'],
'lines': [
['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']
- ]},
+ ]
+ },
'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_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_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]
- ]},
+ ]
+ },
'files': {
'options': [None, 'mysql Open Files', 'files', 'files', 'mysql.files', 'line'],
'lines': [
['Open_files', 'files', 'absolute']
- ]},
+ ]
+ },
'files_rate': {
'options': [None, 'mysql Opened Files Rate', 'files/s', 'files', 'mysql.files_rate', 'line'],
'lines': [
['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']
- ]},
+ ]
+ },
'connection_errors': {
'options': [None, 'mysql Connection Errors', 'connections/s', 'connections',
'mysql.connection_errors', 'line'],
@@ -409,47 +507,55 @@ CHARTS = {
['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': [
['Seconds_Behind_Master', 'seconds', 'absolute']
- ]},
+ ]
+ },
'slave_status': {
'options': [None, 'Slave Status', 'status', 'slave', 'mysql.slave_status', 'line'],
'lines': [
['Slave_SQL_Running', 'sql_running', 'absolute'],
['Slave_IO_Running', 'io_running', 'absolute']
- ]},
+ ]
+ },
'galera_writesets': {
'options': [None, 'Replicated writesets', 'writesets/s', 'galera', 'mysql.galera_writesets', 'line'],
'lines': [
['wsrep_received', 'rx', 'incremental'],
['wsrep_replicated', 'tx', 'incremental', -1, 1],
- ]},
+ ]
+ },
'galera_bytes': {
'options': [None, 'Replicated bytes', 'KB/s', 'galera', 'mysql.galera_bytes', 'area'],
'lines': [
['wsrep_received_bytes', 'rx', 'incremental', 1, 1024],
['wsrep_replicated_bytes', 'tx', 'incremental', -1, 1024],
- ]},
+ ]
+ },
'galera_queue': {
'options': [None, 'Galera queue', 'writesets', 'galera', 'mysql.galera_queue', 'line'],
'lines': [
['wsrep_local_recv_queue', 'rx', 'absolute'],
['wsrep_local_send_queue', 'tx', 'absolute', -1, 1],
- ]},
+ ]
+ },
'galera_conflicts': {
'options': [None, 'Replication conflicts', 'transactions', 'galera', 'mysql.galera_conflicts', 'area'],
'lines': [
['wsrep_local_bf_aborts', 'bf_aborts', 'incremental'],
['wsrep_local_cert_failures', 'cert_fails', 'incremental', -1, 1],
- ]},
+ ]
+ },
'galera_flow_control': {
'options': [None, 'Flow control', 'millisec', 'galera', 'mysql.galera_flow_control', 'area'],
'lines': [
['wsrep_flow_control_paused_ns', 'paused', 'incremental', 1, 1000000],
- ]}
+ ]
+ }
}
@@ -458,7 +564,7 @@ class Service(MySQLService):
MySQLService.__init__(self, configuration=configuration, name=name)
self.order = ORDER
self.definitions = CHARTS
- self.queries = dict(global_status=QUERY_GLOBAL, slave_status=QUERY_SLAVE)
+ self.queries = dict(global_status=QUERY_GLOBAL, slave_status=QUERY_SLAVE, variables=QUERY_VARIABLES)
def _get_data(self):
@@ -487,5 +593,10 @@ class Service(MySQLService):
else:
self.queries.pop('slave_status')
- return to_netdata or None
+ if 'variables' in raw_data:
+ variables = dict(raw_data['variables'][0])
+ for key in VARIABLES:
+ if key in variables:
+ to_netdata[key] = variables[key]
+ return to_netdata or None
diff --git a/conf.d/python.d/mysql.conf b/collectors/python.d.plugin/mysql/mysql.conf
index b5956a2c6..b5956a2c6 100644
--- a/conf.d/python.d/mysql.conf
+++ b/collectors/python.d.plugin/mysql/mysql.conf
diff --git a/collectors/python.d.plugin/nginx/Makefile.inc b/collectors/python.d.plugin/nginx/Makefile.inc
new file mode 100644
index 000000000..4636aa830
--- /dev/null
+++ b/collectors/python.d.plugin/nginx/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += nginx/nginx.chart.py
+dist_pythonconfig_DATA += nginx/nginx.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += nginx/README.md nginx/Makefile.inc
+
diff --git a/collectors/python.d.plugin/nginx/README.md b/collectors/python.d.plugin/nginx/README.md
new file mode 100644
index 000000000..007f45c7c
--- /dev/null
+++ b/collectors/python.d.plugin/nginx/README.md
@@ -0,0 +1,45 @@
+# nginx
+
+This module will monitor one or more nginx servers depending on configuration. Servers can be either local or remote.
+
+**Requirements:**
+ * nginx with configured 'ngx_http_stub_status_module'
+ * 'location /stub_status'
+
+Example nginx configuration can be found in 'python.d/nginx.conf'
+
+It produces following charts:
+
+1. **Active Connections**
+ * active
+
+2. **Requests** in requests/s
+ * requests
+
+3. **Active Connections by Status**
+ * reading
+ * writing
+ * waiting
+
+4. **Connections Rate** in connections/s
+ * accepts
+ * handled
+
+### configuration
+
+Needs only `url` to server's `stub_status`
+
+Here is an example for local server:
+
+```yaml
+update_every : 10
+priority : 90100
+
+local:
+ url : 'http://localhost/stub_status'
+ retries : 10
+```
+
+Without configuration, module attempts to connect to `http://localhost/stub_status`
+
+---
diff --git a/python.d/nginx.chart.py b/collectors/python.d.plugin/nginx/nginx.chart.py
index 2e4f0d1b5..09c6bbd37 100644
--- a/python.d/nginx.chart.py
+++ b/collectors/python.d.plugin/nginx/nginx.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: nginx netdata python.d module
# Author: Pawel Krupa (paulfantom)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.FrameworkServices.UrlService import UrlService
@@ -25,28 +26,32 @@ CHARTS = {
'options': [None, 'nginx Active Connections', 'connections', 'active connections',
'nginx.connections', 'line'],
'lines': [
- ["active"]
- ]},
+ ['active']
+ ]
+ },
'requests': {
'options': [None, 'nginx Requests', 'requests/s', 'requests', 'nginx.requests', 'line'],
'lines': [
- ["requests", None, 'incremental']
- ]},
+ ['requests', None, 'incremental']
+ ]
+ },
'connection_status': {
'options': [None, 'nginx Active Connections by Status', 'connections', 'status',
'nginx.connection_status', 'line'],
'lines': [
- ["reading"],
- ["writing"],
- ["waiting", "idle"]
- ]},
+ ['reading'],
+ ['writing'],
+ ['waiting', 'idle']
+ ]
+ },
'connect_rate': {
'options': [None, 'nginx Connections Rate', 'connections/s', 'connections rate',
'nginx.connect_rate', 'line'],
'lines': [
- ["accepts", "accepted", "incremental"],
- ["handled", None, "incremental"]
- ]}
+ ['accepts', 'accepted', 'incremental'],
+ ['handled', None, 'incremental']
+ ]
+ }
}
diff --git a/conf.d/python.d/nginx.conf b/collectors/python.d.plugin/nginx/nginx.conf
index 71c521066..71c521066 100644
--- a/conf.d/python.d/nginx.conf
+++ b/collectors/python.d.plugin/nginx/nginx.conf
diff --git a/collectors/python.d.plugin/nginx_plus/Makefile.inc b/collectors/python.d.plugin/nginx_plus/Makefile.inc
new file mode 100644
index 000000000..d3fdeaf2b
--- /dev/null
+++ b/collectors/python.d.plugin/nginx_plus/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += nginx_plus/nginx_plus.chart.py
+dist_pythonconfig_DATA += nginx_plus/nginx_plus.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += nginx_plus/README.md nginx_plus/Makefile.inc
+
diff --git a/collectors/python.d.plugin/nginx_plus/README.md b/collectors/python.d.plugin/nginx_plus/README.md
new file mode 100644
index 000000000..43ec867a3
--- /dev/null
+++ b/collectors/python.d.plugin/nginx_plus/README.md
@@ -0,0 +1,125 @@
+# nginx_plus
+
+This module will monitor one or more nginx_plus servers depending on configuration.
+Servers can be either local or remote.
+
+Example nginx_plus configuration can be found in 'python.d/nginx_plus.conf'
+
+It produces following charts:
+
+1. **Requests total** in requests/s
+ * total
+
+2. **Requests current** in requests
+ * current
+
+3. **Connection Statistics** in connections/s
+ * accepted
+ * dropped
+
+4. **Workers Statistics** in workers
+ * idle
+ * active
+
+5. **SSL Handshakes** in handshakes/s
+ * successful
+ * failed
+
+6. **SSL Session Reuses** in sessions/s
+ * reused
+
+7. **SSL Memory Usage** in percent
+ * usage
+
+8. **Processes** in processes
+ * respawned
+
+For every server zone:
+
+1. **Processing** in requests
+ * processing
+
+2. **Requests** in requests/s
+ * requests
+
+3. **Responses** in requests/s
+ * 1xx
+ * 2xx
+ * 3xx
+ * 4xx
+ * 5xx
+
+4. **Traffic** in kilobits/s
+ * received
+ * sent
+
+For every upstream:
+
+1. **Peers Requests** in requests/s
+ * peer name (dimension per peer)
+
+2. **All Peers Responses** in responses/s
+ * 1xx
+ * 2xx
+ * 3xx
+ * 4xx
+ * 5xx
+
+3. **Peer Responses** in requests/s (for every peer)
+ * 1xx
+ * 2xx
+ * 3xx
+ * 4xx
+ * 5xx
+
+4. **Peers Connections** in active
+ * peer name (dimension per peer)
+
+5. **Peers Connections Usage** in percent
+ * peer name (dimension per peer)
+
+6. **All Peers Traffic** in KB
+ * received
+ * sent
+
+7. **Peer Traffic** in KB/s (for every peer)
+ * received
+ * sent
+
+8. **Peer Timings** in ms (for every peer)
+ * header
+ * response
+
+9. **Memory Usage** in percent
+ * usage
+
+10. **Peers Status** in state
+ * peer name (dimension per peer)
+
+11. **Peers Total Downtime** in seconds
+ * peer name (dimension per peer)
+
+For every cache:
+
+1. **Traffic** in KB
+ * served
+ * written
+ * bypass
+
+2. **Memory Usage** in percent
+ * usage
+
+### configuration
+
+Needs only `url` to server's `status`
+
+Here is an example for local server:
+
+```yaml
+local:
+ url : 'http://localhost/status'
+```
+
+Without configuration, module fail to start.
+
+---
diff --git a/python.d/nginx_plus.chart.py b/collectors/python.d.plugin/nginx_plus/nginx_plus.chart.py
index 509ddd380..1392f5a56 100644
--- a/python.d/nginx_plus.chart.py
+++ b/collectors/python.d.plugin/nginx_plus/nginx_plus.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: nginx_plus netdata python.d module
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
import re
@@ -21,63 +22,71 @@ priority = 60000
retries = 60
# charts order (can be overridden if you want less charts, or different order)
-ORDER = ['requests_total', 'requests_current',
- 'connections_statistics', 'connections_workers',
- 'ssl_handshakes', 'ssl_session_reuses', 'ssl_memory_usage',
- 'processes']
+ORDER = [
+ 'requests_total',
+ 'requests_current',
+ 'connections_statistics',
+ 'connections_workers',
+ 'ssl_handshakes',
+ 'ssl_session_reuses',
+ 'ssl_memory_usage',
+ 'processes'
+]
CHARTS = {
'requests_total': {
- 'options': [None, 'Requests Total', 'requests/s',
- 'requests', 'nginx_plus.requests_total', 'line'],
+ 'options': [None, 'Requests Total', 'requests/s', 'requests', 'nginx_plus.requests_total', 'line'],
'lines': [
['requests_total', 'total', 'incremental']
- ]},
+ ]
+ },
'requests_current': {
- 'options': [None, 'Requests Current', 'requests',
- 'requests', 'nginx_plus.requests_current', 'line'],
+ 'options': [None, 'Requests Current', 'requests', 'requests', 'nginx_plus.requests_current', 'line'],
'lines': [
['requests_current', 'current']
- ]},
+ ]
+ },
'connections_statistics': {
'options': [None, 'Connections Statistics', 'connections/s',
'connections', 'nginx_plus.connections_statistics', 'stacked'],
'lines': [
['connections_accepted', 'accepted', 'incremental'],
['connections_dropped', 'dropped', 'incremental']
- ]},
+ ]
+ },
'connections_workers': {
'options': [None, 'Workers Statistics', 'workers',
'connections', 'nginx_plus.connections_workers', 'stacked'],
'lines': [
['connections_idle', 'idle'],
['connections_active', 'active']
- ]},
+ ]
+ },
'ssl_handshakes': {
- 'options': [None, 'SSL Handshakes', 'handshakes/s',
- 'ssl', 'nginx_plus.ssl_handshakes', 'stacked'],
+ 'options': [None, 'SSL Handshakes', 'handshakes/s', 'ssl', 'nginx_plus.ssl_handshakes', 'stacked'],
'lines': [
['ssl_handshakes', 'successful', 'incremental'],
['ssl_handshakes_failed', 'failed', 'incremental']
- ]},
+ ]
+ },
'ssl_session_reuses': {
- 'options': [None, 'Session Reuses', 'sessions/s',
- 'ssl', 'nginx_plus.ssl_session_reuses', 'line'],
+ 'options': [None, 'Session Reuses', 'sessions/s', 'ssl', 'nginx_plus.ssl_session_reuses', 'line'],
'lines': [
['ssl_session_reuses', 'reused', 'incremental']
- ]},
+ ]
+ },
'ssl_memory_usage': {
- 'options': [None, 'Memory Usage', '%',
- 'ssl', 'nginx_plus.ssl_memory_usage', 'area'],
+ 'options': [None, 'Memory Usage', '%', 'ssl', 'nginx_plus.ssl_memory_usage', 'area'],
'lines': [
['ssl_memory_usage', 'usage', 'absolute', 1, 100]
- ]},
+ ]
+ },
'processes': {
- 'options': [None, 'Processes', 'processes',
- 'processes', 'nginx_plus.processes', 'line'],
+ 'options': [None, 'Processes', 'processes', 'processes', 'nginx_plus.processes', 'line'],
'lines': [
['processes_respawned', 'respawned']
- ]}
+ ]
+ }
}
@@ -86,17 +95,15 @@ def cache_charts(cache):
charts = OrderedDict()
charts['{0}_traffic'.format(cache.name)] = {
- 'options': [None, 'Traffic', 'KB', family,
- 'nginx_plus.cache_traffic', 'stacked'],
+ 'options': [None, 'Traffic', 'KB', family, 'nginx_plus.cache_traffic', 'stacked'],
'lines': [
['_'.join([cache.name, 'hit_bytes']), 'served', 'absolute', 1, 1024],
['_'.join([cache.name, 'miss_bytes_written']), 'written', 'absolute', 1, 1024],
['_'.join([cache.name, 'miss_bytes']), 'bypass', 'absolute', 1, 1024]
- ]
+ ]
}
charts['{0}_memory_usage'.format(cache.name)] = {
- 'options': [None, 'Memory Usage', '%', family,
- 'nginx_plus.cache_memory_usage', 'area'],
+ 'options': [None, 'Memory Usage', '%', family, 'nginx_plus.cache_memory_usage', 'area'],
'lines': [
['_'.join([cache.name, 'memory_usage']), 'usage', 'absolute', 1, 100],
]
@@ -160,8 +167,7 @@ def web_upstream_charts(wu):
# Requests
charts['web_upstream_{name}_requests'.format(name=wu.name)] = {
- 'options': [None, 'Peers Requests', 'requests/s', family,
- 'nginx_plus.web_upstream_requests', 'line'],
+ 'options': [None, 'Peers Requests', 'requests/s', family, 'nginx_plus.web_upstream_requests', 'line'],
'lines': dimensions('requests', 'incremental')
}
# Responses Codes
@@ -177,7 +183,7 @@ def web_upstream_charts(wu):
]
}
for peer in wu:
- charts['web_upstream_{0}_{1}_responses'.format(wu.name, peer.id)] = {
+ charts['web_upstream_{0}_{1}_responses'.format(wu.name, peer.server)] = {
'options': [None, 'Peer "{0}" Responses'.format(peer.real_server), 'responses/s', family,
'nginx_plus.web_upstream_peer_responses', 'stacked'],
'lines': [
@@ -190,26 +196,23 @@ def web_upstream_charts(wu):
}
# Connections
charts['web_upstream_{name}_connections'.format(name=wu.name)] = {
- 'options': [None, 'Peers Connections', 'active', family,
- 'nginx_plus.web_upstream_connections', 'line'],
+ 'options': [None, 'Peers Connections', 'active', family, 'nginx_plus.web_upstream_connections', 'line'],
'lines': dimensions('active')
}
charts['web_upstream_{name}_connections_usage'.format(name=wu.name)] = {
- 'options': [None, 'Peers Connections Usage', '%', family,
- 'nginx_plus.web_upstream_connections_usage', 'line'],
+ 'options': [None, 'Peers Connections Usage', '%', family, 'nginx_plus.web_upstream_connections_usage', 'line'],
'lines': dimensions('connections_usage', d=100)
}
# Traffic
charts['web_upstream_{0}_all_net'.format(wu.name)] = {
- 'options': [None, 'All Peers Traffic', 'kilobits/s', family,
- 'nginx_plus.web_upstream_all_net', 'area'],
+ 'options': [None, 'All Peers Traffic', 'kilobits/s', family, 'nginx_plus.web_upstream_all_net', 'area'],
'lines': [
['{0}_received'.format(wu.name), 'received', 'incremental', 1, 1000],
['{0}_sent'.format(wu.name), 'sent', 'incremental', -1, 1000]
]
}
for peer in wu:
- charts['web_upstream_{0}_{1}_net'.format(wu.name, peer.id)] = {
+ charts['web_upstream_{0}_{1}_net'.format(wu.name, peer.server)] = {
'options': [None, 'Peer "{0}" Traffic'.format(peer.real_server), 'kilobits/s', family,
'nginx_plus.web_upstream_peer_traffic', 'area'],
'lines': [
@@ -219,7 +222,7 @@ def web_upstream_charts(wu):
}
# Response Time
for peer in wu:
- charts['web_upstream_{0}_{1}_timings'.format(wu.name, peer.id)] = {
+ charts['web_upstream_{0}_{1}_timings'.format(wu.name, peer.server)] = {
'options': [None, 'Peer "{0}" Timings'.format(peer.real_server), 'ms', family,
'nginx_plus.web_upstream_peer_timings', 'line'],
'lines': [
@@ -229,30 +232,27 @@ def web_upstream_charts(wu):
}
# Memory Usage
charts['web_upstream_{name}_memory_usage'.format(name=wu.name)] = {
- 'options': [None, 'Memory Usage', '%', family,
- 'nginx_plus.web_upstream_memory_usage', 'area'],
+ 'options': [None, 'Memory Usage', '%', family, 'nginx_plus.web_upstream_memory_usage', 'area'],
'lines': [
['_'.join([wu.name, 'memory_usage']), 'usage', 'absolute', 1, 100]
]
}
# State
charts['web_upstream_{name}_status'.format(name=wu.name)] = {
- 'options': [None, 'Peers Status', 'state', family,
- 'nginx_plus.web_upstream_status', 'line'],
+ 'options': [None, 'Peers Status', 'state', family, 'nginx_plus.web_upstream_status', 'line'],
'lines': dimensions('state')
}
# Downtime
charts['web_upstream_{name}_downtime'.format(name=wu.name)] = {
- 'options': [None, 'Peers Downtime', 'seconds', family,
- 'nginx_plus.web_upstream_peer_downtime', 'line'],
+ 'options': [None, 'Peers Downtime', 'seconds', family, 'nginx_plus.web_upstream_peer_downtime', 'line'],
'lines': dimensions('downtime', d=1000)
}
return charts
-METRICS = dict(
- SERVER=[
+METRICS = {
+ 'SERVER': [
'processes.respawned',
'connections.accepted',
'connections.dropped',
@@ -266,7 +266,7 @@ METRICS = dict(
'slabs.SSL.pages.free',
'slabs.SSL.pages.used'
],
- WEB_ZONE=[
+ 'WEB_ZONE': [
'processing',
'requests',
'responses.1xx',
@@ -278,7 +278,7 @@ METRICS = dict(
'received',
'sent'
],
- WEB_UPSTREAM_PEER=[
+ 'WEB_UPSTREAM_PEER': [
'id',
'server',
'name',
@@ -297,7 +297,7 @@ METRICS = dict(
'received',
'downtime'
],
- WEB_UPSTREAM_SUMMARY=[
+ 'WEB_UPSTREAM_SUMMARY': [
'responses.1xx',
'responses.2xx',
'responses.3xx',
@@ -306,13 +306,13 @@ METRICS = dict(
'sent',
'received'
],
- CACHE=[
+ 'CACHE': [
'hit.bytes', # served
'miss.bytes_written', # written
'miss.bytes' # bypass
]
-)
+}
BAD_SYMBOLS = re.compile(r'[:/.-]+')
@@ -373,6 +373,7 @@ class WebUpstream:
return peer
def peers_stats(self, peers):
+ peers = {int(peer['id']): peer for peer in peers}
data = dict()
for peer in self.peers.values():
if not peer.active:
diff --git a/conf.d/python.d/nginx_plus.conf b/collectors/python.d.plugin/nginx_plus/nginx_plus.conf
index 7b5c8f43f..7b5c8f43f 100644
--- a/conf.d/python.d/nginx_plus.conf
+++ b/collectors/python.d.plugin/nginx_plus/nginx_plus.conf
diff --git a/collectors/python.d.plugin/nsd/Makefile.inc b/collectors/python.d.plugin/nsd/Makefile.inc
new file mode 100644
index 000000000..58e9fd67d
--- /dev/null
+++ b/collectors/python.d.plugin/nsd/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += nsd/nsd.chart.py
+dist_pythonconfig_DATA += nsd/nsd.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += nsd/README.md nsd/Makefile.inc
+
diff --git a/collectors/python.d.plugin/nsd/README.md b/collectors/python.d.plugin/nsd/README.md
new file mode 100644
index 000000000..02c302f41
--- /dev/null
+++ b/collectors/python.d.plugin/nsd/README.md
@@ -0,0 +1,54 @@
+# nsd
+
+Module uses the `nsd-control stats_noreset` command to provide `nsd` statistics.
+
+**Requirements:**
+ * Version of `nsd` must be 4.0+
+ * Netdata must have permissions to run `nsd-control stats_noreset`
+
+It produces:
+
+1. **Queries**
+ * queries
+
+2. **Zones**
+ * master
+ * slave
+
+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
+
+
+Configuration is not needed.
+
+---
diff --git a/python.d/nsd.chart.py b/collectors/python.d.plugin/nsd/nsd.chart.py
index 499dfda2e..d713f46bd 100644
--- a/python.d/nsd.chart.py
+++ b/collectors/python.d.plugin/nsd/nsd.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: NSD `nsd-control stats_noreset` netdata python.d module
# Author: <383c57 at gmail.com>
+# SPDX-License-Identifier: GPL-3.0-or-later
import re
@@ -16,27 +17,29 @@ ORDER = ['queries', 'zones', 'protocol', 'type', 'transfer', 'rcode']
CHARTS = {
'queries': {
- 'options': [
- None, "queries", 'queries/s', 'queries', 'nsd.queries', 'line'],
+ 'options': [None, 'queries', 'queries/s', 'queries', 'nsd.queries', 'line'],
'lines': [
- ['num_queries', 'queries', 'incremental'],]},
+ ['num_queries', 'queries', 'incremental']
+ ]
+ },
'zones': {
- 'options': [
- None, "zones", 'zones', 'zones', 'nsd.zones', 'stacked'],
+ 'options': [None, 'zones', 'zones', 'zones', 'nsd.zones', 'stacked'],
'lines': [
['zone_master', 'master', 'absolute'],
- ['zone_slave', 'slave', 'absolute'],]},
+ ['zone_slave', 'slave', 'absolute']
+ ]
+ },
'protocol': {
- 'options': [
- None, "protocol", 'queries/s', 'protocol', 'nsd.protocols', 'stacked'],
+ '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'],]},
+ ['num_tcp6', 'tcp6', 'incremental']
+ ]
+ },
'type': {
- 'options': [
- None, "query type", 'queries/s', 'query type', 'nsd.type', 'stacked'],
+ 'options': [None, 'query type', 'queries/s', 'query type', 'nsd.type', 'stacked'],
'lines': [
['num_type_A', 'A', 'incremental'],
['num_type_NS', 'NS', 'incremental'],
@@ -49,16 +52,18 @@ CHARTS = {
['num_type_TXT', 'TXT', 'incremental'],
['num_type_AAAA', 'AAAA', 'incremental'],
['num_type_SRV', 'SRV', 'incremental'],
- ['num_type_TYPE255', 'ANY', 'incremental'],]},
+ ['num_type_TYPE255', 'ANY', 'incremental']
+ ]
+ },
'transfer': {
- 'options': [
- None, "transfer", 'queries/s', 'transfer', 'nsd.transfer', 'stacked'],
+ 'options': [None, 'transfer', 'queries/s', 'transfer', 'nsd.transfer', 'stacked'],
'lines': [
['num_opcode_NOTIFY', 'NOTIFY', 'incremental'],
- ['num_type_TYPE252', 'AXFR', 'incremental'],]},
+ ['num_type_TYPE252', 'AXFR', 'incremental']
+ ]
+ },
'rcode': {
- 'options': [
- None, "return code", 'queries/s', 'return code', 'nsd.rcode', 'stacked'],
+ 'options': [None, 'return code', 'queries/s', 'return code', 'nsd.rcode', 'stacked'],
'lines': [
['num_rcode_NOERROR', 'NOERROR', 'incremental'],
['num_rcode_FORMERR', 'FORMERR', 'incremental'],
@@ -66,7 +71,9 @@ CHARTS = {
['num_rcode_NXDOMAIN', 'NXDOMAIN', 'incremental'],
['num_rcode_NOTIMP', 'NOTIMP', 'incremental'],
['num_rcode_REFUSED', 'REFUSED', 'incremental'],
- ['num_rcode_YXDOMAIN', 'YXDOMAIN', 'incremental'],]}
+ ['num_rcode_YXDOMAIN', 'YXDOMAIN', 'incremental']
+ ]
+ }
}
@@ -74,7 +81,7 @@ class Service(ExecutableService):
def __init__(self, configuration=None, name=None):
ExecutableService.__init__(
self, configuration=configuration, name=name)
- self.command = "nsd-control stats_noreset"
+ self.command = 'nsd-control stats_noreset'
self.order = ORDER
self.definitions = CHARTS
self.regex = re.compile(r'([A-Za-z0-9.]+)=(\d+)')
diff --git a/conf.d/python.d/nsd.conf b/collectors/python.d.plugin/nsd/nsd.conf
index 078e97216..078e97216 100644
--- a/conf.d/python.d/nsd.conf
+++ b/collectors/python.d.plugin/nsd/nsd.conf
diff --git a/collectors/python.d.plugin/ntpd/Makefile.inc b/collectors/python.d.plugin/ntpd/Makefile.inc
new file mode 100644
index 000000000..81210ebab
--- /dev/null
+++ b/collectors/python.d.plugin/ntpd/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += ntpd/ntpd.chart.py
+dist_pythonconfig_DATA += ntpd/ntpd.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += ntpd/README.md ntpd/Makefile.inc
+
diff --git a/collectors/python.d.plugin/ntpd/README.md b/collectors/python.d.plugin/ntpd/README.md
new file mode 100644
index 000000000..b0fa17fde
--- /dev/null
+++ b/collectors/python.d.plugin/ntpd/README.md
@@ -0,0 +1,71 @@
+# ntpd
+
+Module monitors the system variables of the local `ntpd` daemon (optional incl. variables of the polled peers) using the NTP Control Message Protocol via UDP socket, similar to `ntpq`, the [standard NTP query program](http://doc.ntp.org/current-stable/ntpq.html).
+
+**Requirements:**
+ * Version: `NTPv4`
+ * Local interrogation allowed in `/etc/ntp.conf` (default):
+
+```
+# Local users may interrogate the ntp server more closely.
+restrict 127.0.0.1
+restrict ::1
+```
+
+It produces:
+
+1. system
+ * offset
+ * jitter
+ * frequency
+ * delay
+ * dispersion
+ * stratum
+ * tc
+ * precision
+
+2. peers
+ * offset
+ * delay
+ * dispersion
+ * jitter
+ * rootdelay
+ * rootdispersion
+ * stratum
+ * hmode
+ * pmode
+ * hpoll
+ * ppoll
+ * precision
+
+**configuration**
+
+Sample:
+
+```yaml
+update_every: 10
+
+host: 'localhost'
+port: '123'
+show_peers: yes
+# hide peers with source address in ranges 127.0.0.0/8 and 192.168.0.0/16
+peer_filter: '(127\..*)|(192\.168\..*)'
+# check for new/changed peers every 60 updates
+peer_rescan: 60
+```
+
+Sample (multiple jobs):
+
+Note: `ntp.conf` on the host `otherhost` must be configured to allow queries from our local host by including a line like `restrict <IP> nomodify notrap nopeer`.
+
+```yaml
+local:
+ host: 'localhost'
+
+otherhost:
+ host: 'otherhost'
+```
+
+If no configuration is given, module will attempt to connect to `ntpd` on `::1:123` or `127.0.0.1:123` and show charts for the systemvars. Use `show_peers: yes` to also show the charts for configured peers. Local peers in the range `127.0.0.0/8` are hidden by default, use `peer_filter: ''` to show all peers.
+
+---
diff --git a/python.d/ntpd.chart.py b/collectors/python.d.plugin/ntpd/ntpd.chart.py
index 05209da87..79d557c80 100644
--- a/python.d/ntpd.chart.py
+++ b/collectors/python.d.plugin/ntpd/ntpd.chart.py
@@ -2,6 +2,7 @@
# Description: ntpd netdata python.d module
# Author: Sven Mäder (rda0)
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
import struct
import re
@@ -56,108 +57,117 @@ CHARTS = {
'options': [None, 'Combined offset of server relative to this host', 'ms', 'system', 'ntpd.sys_offset', 'area'],
'lines': [
['offset', 'offset', 'absolute', 1, PRECISION]
- ]},
+ ]
+ },
'sys_jitter': {
'options': [None, 'Combined system jitter and clock jitter', 'ms', 'system', 'ntpd.sys_jitter', 'line'],
'lines': [
['sys_jitter', 'system', 'absolute', 1, PRECISION],
['clk_jitter', 'clock', 'absolute', 1, PRECISION]
- ]},
+ ]
+ },
'sys_frequency': {
'options': [None, 'Frequency offset relative to hardware clock', 'ppm', 'system', 'ntpd.sys_frequency', 'area'],
'lines': [
['frequency', 'frequency', 'absolute', 1, PRECISION]
- ]},
+ ]
+ },
'sys_wander': {
'options': [None, 'Clock frequency wander', 'ppm', 'system', 'ntpd.sys_wander', 'area'],
'lines': [
['clk_wander', 'clock', 'absolute', 1, PRECISION]
- ]},
+ ]
+ },
'sys_rootdelay': {
'options': [None, 'Total roundtrip delay to the primary reference clock', 'ms', 'system',
'ntpd.sys_rootdelay', 'area'],
'lines': [
['rootdelay', 'delay', 'absolute', 1, PRECISION]
- ]},
+ ]
+ },
'sys_rootdisp': {
'options': [None, 'Total root dispersion to the primary reference clock', 'ms', 'system',
'ntpd.sys_rootdisp', 'area'],
'lines': [
['rootdisp', 'dispersion', 'absolute', 1, PRECISION]
- ]},
+ ]
+ },
'sys_stratum': {
'options': [None, 'Stratum (1-15)', 'stratum', 'system', 'ntpd.sys_stratum', 'line'],
'lines': [
['stratum', 'stratum', 'absolute', 1, PRECISION]
- ]},
+ ]
+ },
'sys_tc': {
'options': [None, 'Time constant and poll exponent (3-17)', 'log2 s', 'system', 'ntpd.sys_tc', 'line'],
'lines': [
['tc', 'current', 'absolute', 1, PRECISION],
['mintc', 'minimum', 'absolute', 1, PRECISION]
- ]},
+ ]
+ },
'sys_precision': {
'options': [None, 'Precision', 'log2 s', 'system', 'ntpd.sys_precision', 'line'],
'lines': [
['precision', 'precision', 'absolute', 1, PRECISION]
- ]}
+ ]
+ }
}
PEER_CHARTS = {
'peer_offset': {
'options': [None, 'Filter offset', 'ms', 'peers', 'ntpd.peer_offset', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_delay': {
'options': [None, 'Filter delay', 'ms', 'peers', 'ntpd.peer_delay', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_dispersion': {
'options': [None, 'Filter dispersion', 'ms', 'peers', 'ntpd.peer_dispersion', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_jitter': {
'options': [None, 'Filter jitter', 'ms', 'peers', 'ntpd.peer_jitter', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_xleave': {
'options': [None, 'Interleave delay', 'ms', 'peers', 'ntpd.peer_xleave', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_rootdelay': {
'options': [None, 'Total roundtrip delay to the primary reference clock', 'ms', 'peers',
'ntpd.peer_rootdelay', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_rootdisp': {
'options': [None, 'Total root dispersion to the primary reference clock', 'ms', 'peers',
'ntpd.peer_rootdisp', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_stratum': {
'options': [None, 'Stratum (1-15)', 'stratum', 'peers', 'ntpd.peer_stratum', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_hmode': {
'options': [None, 'Host mode (1-6)', 'hmode', 'peers', 'ntpd.peer_hmode', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_pmode': {
'options': [None, 'Peer mode (1-5)', 'pmode', 'peers', 'ntpd.peer_pmode', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_hpoll': {
'options': [None, 'Host poll exponent', 'log2 s', 'peers', 'ntpd.peer_hpoll', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_ppoll': {
'options': [None, 'Peer poll exponent', 'log2 s', 'peers', 'ntpd.peer_ppoll', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'peer_precision': {
'options': [None, 'Precision', 'log2 s', 'peers', 'ntpd.peer_precision', 'line'],
- 'lines': [
- ]}
+ 'lines': []
+ }
}
diff --git a/conf.d/python.d/ntpd.conf b/collectors/python.d.plugin/ntpd/ntpd.conf
index 7adc4074b..7adc4074b 100644
--- a/conf.d/python.d/ntpd.conf
+++ b/collectors/python.d.plugin/ntpd/ntpd.conf
diff --git a/collectors/python.d.plugin/ovpn_status_log/Makefile.inc b/collectors/python.d.plugin/ovpn_status_log/Makefile.inc
new file mode 100644
index 000000000..1fbc506d6
--- /dev/null
+++ b/collectors/python.d.plugin/ovpn_status_log/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += ovpn_status_log/ovpn_status_log.chart.py
+dist_pythonconfig_DATA += ovpn_status_log/ovpn_status_log.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += ovpn_status_log/README.md ovpn_status_log/Makefile.inc
+
diff --git a/collectors/python.d.plugin/ovpn_status_log/README.md b/collectors/python.d.plugin/ovpn_status_log/README.md
new file mode 100644
index 000000000..be1ea279e
--- /dev/null
+++ b/collectors/python.d.plugin/ovpn_status_log/README.md
@@ -0,0 +1,32 @@
+# ovpn_status_log
+
+Module monitor openvpn-status log file.
+
+**Requirements:**
+
+ * If you are running multiple OpenVPN instances out of the same directory, MAKE SURE TO EDIT DIRECTIVES which create output files
+ so that multiple instances do not overwrite each other's output files.
+
+ * Make sure NETDATA USER CAN READ openvpn-status.log
+
+ * Update_every interval MUST MATCH interval on which OpenVPN writes operational status to log file.
+
+It produces:
+
+1. **Users** OpenVPN active users
+ * users
+
+2. **Traffic** OpenVPN overall bandwidth usage in kilobit/s
+ * in
+ * out
+
+### configuration
+
+Sample:
+
+```yaml
+default
+ log_path : '/var/log/openvpn-status.log'
+```
+
+---
diff --git a/python.d/ovpn_status_log.chart.py b/collectors/python.d.plugin/ovpn_status_log/ovpn_status_log.chart.py
index 519c77fa3..64d7062d9 100644
--- a/python.d/ovpn_status_log.chart.py
+++ b/collectors/python.d.plugin/ovpn_status_log/ovpn_status_log.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: openvpn status log netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
from re import compile as r_compile
@@ -16,15 +17,19 @@ CHARTS = {
'options': [None, 'OpenVPN Active Users', 'active users', 'users', 'openvpn_status.users', 'line'],
'lines': [
['users', None, 'absolute'],
- ]},
+ ]
+ },
'traffic': {
'options': [None, 'OpenVPN Traffic', 'KB/s', 'traffic', 'openvpn_status.traffic', 'area'],
'lines': [
['bytes_in', 'in', 'incremental', 1, 1 << 10], ['bytes_out', 'out', 'incremental', 1, -1 << 10]
- ]},
-
+ ]
+ }
}
+TLS_REGEX = r_compile(r'(?:[0-9a-f:]+|(?:\d{1,3}(?:\.\d{1,3}){3}(?::\d+)?)) (?P<bytes_in>\d+) (?P<bytes_out>\d+)')
+STATIC_KEY_REGEX = r_compile(r'TCP/[A-Z]+ (?P<direction>(?:read|write)) bytes,(?P<bytes>\d+)')
+
class Service(SimpleService):
def __init__(self, configuration=None, name=None):
@@ -32,8 +37,10 @@ class Service(SimpleService):
self.order = ORDER
self.definitions = CHARTS
self.log_path = self.configuration.get('log_path')
- self.regex = dict(tls=r_compile(r'\d{1,3}(?:\.\d{1,3}){3}(?::\d+)? (?P<bytes_in>\d+) (?P<bytes_out>\d+)'),
- static_key=r_compile(r'TCP/[A-Z]+ (?P<direction>(?:read|write)) bytes,(?P<bytes>\d+)'))
+ self.regex = {
+ 'tls': TLS_REGEX,
+ 'static_key': STATIC_KEY_REGEX
+ }
def check(self):
if not (self.log_path and isinstance(self.log_path, str)):
@@ -57,7 +64,7 @@ class Service(SimpleService):
break
if found:
return True
- self.error("Failed to parse ovpenvpn log file")
+ self.error('Failed to parse ovpenvpn log file')
return False
def _get_raw_data(self):
@@ -107,8 +114,12 @@ class Service(SimpleService):
data = dict(users=0, bytes_in=0, bytes_out=0)
for row in raw_data:
- row = ' '.join(row.split(',')) if ',' in row else ' '.join(row.split())
- match = self.regex['tls'].search(row)
+ columns = row.split(',') if ',' in row else row.split()
+ if 'UNDEF' in columns:
+ # see https://openvpn.net/archive/openvpn-users/2004-08/msg00116.html
+ continue
+
+ match = self.regex['tls'].search(' '.join(columns))
if match:
match = match.groupdict()
data['users'] += 1
diff --git a/conf.d/python.d/ovpn_status_log.conf b/collectors/python.d.plugin/ovpn_status_log/ovpn_status_log.conf
index 907f014f5..6fb35a530 100644
--- a/conf.d/python.d/ovpn_status_log.conf
+++ b/collectors/python.d.plugin/ovpn_status_log/ovpn_status_log.conf
@@ -88,8 +88,12 @@
# # ps -C openvpn -o command=
# /usr/sbin/openvpn --daemon ovpn-server --status /run/openvpn/server.status 10 --cd /etc/openvpn --config /etc/openvpn/server.conf
#
+# 4. Confirm status is configured in your OpenVPN configuration.
+# * Open OpenVPN config in an editor (e.g. sudo nano /etc/openvpn/default.conf)
+# * Confirm status is enabled with below:
+# status /var/log/openvpn-status.log
#
#default:
# log_path: '/var/log/openvpn-status.log'
#
-# ---------------------------------------------------------------------- \ No newline at end of file
+# ----------------------------------------------------------------------
diff --git a/collectors/python.d.plugin/phpfpm/Makefile.inc b/collectors/python.d.plugin/phpfpm/Makefile.inc
new file mode 100644
index 000000000..ff312fe18
--- /dev/null
+++ b/collectors/python.d.plugin/phpfpm/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += phpfpm/phpfpm.chart.py
+dist_pythonconfig_DATA += phpfpm/phpfpm.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += phpfpm/README.md phpfpm/Makefile.inc
+
diff --git a/collectors/python.d.plugin/phpfpm/README.md b/collectors/python.d.plugin/phpfpm/README.md
new file mode 100644
index 000000000..66930463f
--- /dev/null
+++ b/collectors/python.d.plugin/phpfpm/README.md
@@ -0,0 +1,40 @@
+# phpfpm
+
+This module will monitor one or more php-fpm instances depending on configuration.
+
+**Requirements:**
+ * php-fpm with enabled `status` page
+ * access to `status` page via web server
+
+It produces following charts:
+
+1. **Active Connections**
+ * active
+ * maxActive
+ * idle
+
+2. **Requests** in requests/s
+ * requests
+
+3. **Performance**
+ * reached
+ * slow
+
+### configuration
+
+Needs only `url` to server's `status`
+
+Here is an example for local instance:
+
+```yaml
+update_every : 3
+priority : 90100
+
+local:
+ url : 'http://localhost/status'
+ retries : 10
+```
+
+Without configuration, module attempts to connect to `http://localhost/status`
+
+---
diff --git a/python.d/phpfpm.chart.py b/collectors/python.d.plugin/phpfpm/phpfpm.chart.py
index ea7a9a7e6..a3f0963fc 100644
--- a/python.d/phpfpm.chart.py
+++ b/collectors/python.d.plugin/phpfpm/phpfpm.chart.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
# Description: PHP-FPM netdata python.d module
# Author: Pawel Krupa (paulfantom)
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
import json
import re
@@ -58,18 +60,21 @@ CHARTS = {
['active'],
['maxActive', 'max active'],
['idle']
- ]},
+ ]
+ },
'requests': {
'options': [None, 'PHP-FPM Requests', 'requests/s', 'requests', 'phpfpm.requests', 'line'],
'lines': [
['requests', None, 'incremental']
- ]},
+ ]
+ },
'performance': {
'options': [None, 'PHP-FPM Performance', 'status', 'performance', 'phpfpm.performance', 'line'],
'lines': [
['reached', 'max children reached'],
['slow', 'slow requests']
- ]},
+ ]
+ },
'request_duration': {
'options': [None, 'PHP-FPM Request Duration', 'milliseconds', 'request duration', 'phpfpm.request_duration',
'line'],
@@ -77,21 +82,24 @@ CHARTS = {
['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': [
['minReqCpu', 'min'],
['maxReqCpu', 'max'],
['avgReqCpu', 'avg']
- ]},
+ ]
+ },
'request_mem': {
'options': [None, 'PHP-FPM Request Memory', 'kilobytes', 'request memory', 'phpfpm.request_mem', 'line'],
'lines': [
['minReqMem', 'min', 'absolute', 1, 1024],
['maxReqMem', 'max', 'absolute', 1, 1024],
['avgReqMem', 'avg', 'absolute', 1, 1024]
- ]}
+ ]
+ }
}
diff --git a/conf.d/python.d/phpfpm.conf b/collectors/python.d.plugin/phpfpm/phpfpm.conf
index 08688e2fa..571eb9156 100644
--- a/conf.d/python.d/phpfpm.conf
+++ b/collectors/python.d.plugin/phpfpm/phpfpm.conf
@@ -86,5 +86,5 @@ localipv4:
localipv6:
name : 'local'
- url : "http://::1/status?full&json"
+ url : "http://[::1]/status?full&json"
diff --git a/collectors/python.d.plugin/portcheck/Makefile.inc b/collectors/python.d.plugin/portcheck/Makefile.inc
new file mode 100644
index 000000000..76763f02f
--- /dev/null
+++ b/collectors/python.d.plugin/portcheck/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += portcheck/portcheck.chart.py
+dist_pythonconfig_DATA += portcheck/portcheck.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += portcheck/README.md portcheck/Makefile.inc
+
diff --git a/collectors/python.d.plugin/portcheck/README.md b/collectors/python.d.plugin/portcheck/README.md
new file mode 100644
index 000000000..f1338d576
--- /dev/null
+++ b/collectors/python.d.plugin/portcheck/README.md
@@ -0,0 +1,35 @@
+# portcheck
+
+Module monitors a remote TCP service.
+
+Following charts are drawn per host:
+
+1. **Latency** ms
+ * Time required to connect to a TCP port.
+ Displays latency in 0.1 ms resolution. If the connection failed, the value is missing.
+
+2. **Status** boolean
+ * Connection successful
+ * Could not create socket: possible DNS problems
+ * Connection refused: port not listening or blocked
+ * Connection timed out: host or port unreachable
+
+
+### configuration
+
+```yaml
+server:
+ host: 'dns or ip' # required
+ port: 22 # required
+ timeout: 1 # optional
+ update_every: 1 # optional
+```
+
+### notes
+
+ * The error chart is intended for alarms, badges or for access via API.
+ * A system/service/firewall might block netdata's access if a portscan or
+ similar is detected.
+ * Currently, the accuracy of the latency is low and should be used as reference only.
+
+---
diff --git a/python.d/portcheck.chart.py b/collectors/python.d.plugin/portcheck/portcheck.chart.py
index 0a312210d..e86f82544 100644
--- a/python.d/portcheck.chart.py
+++ b/collectors/python.d.plugin/portcheck/portcheck.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: simple port check netdata python.d module
# Original Author: ccremer (github.com/ccremer)
+# SPDX-License-Identifier: GPL-3.0-or-later
import socket
@@ -36,7 +37,8 @@ CHARTS = {
[PORT_SUCCESS, 'success', 'absolute'],
[PORT_TIMEOUT, 'timeout', 'absolute'],
[PORT_FAILED, 'no connection', 'absolute']
- ]}
+ ]
+ }
}
@@ -56,13 +58,13 @@ class Service(SimpleService):
:return: boolean
"""
if self.host is None or self.port is None:
- self.error("Host or port missing")
+ self.error('Host or port missing')
return False
if not isinstance(self.port, int):
self.error('"port" is not an integer. Specify a numerical value, not service name.')
return False
- self.debug("Enabled portcheck: {host}:{port}, update every {update}s, timeout: {timeout}s".format(
+ self.debug('Enabled portcheck: {host}:{port}, update every {update}s, timeout: {timeout}s'.format(
host=self.host, port=self.port, update=self.update_every, timeout=self.timeout
))
# We will accept any (valid-ish) configuration, even if initial connection fails (a service might be down from
@@ -101,7 +103,7 @@ class Service(SimpleService):
return data
def _create_socket(self, socket_config):
- af, sock_type, proto, canon_name, sa = socket_config
+ af, sock_type, proto, _, sa = socket_config
try:
self.debug('Creating socket to "{address}", port {port}'.format(address=sa[0], port=sa[1]))
sock = socket.socket(af, sock_type, proto)
@@ -119,7 +121,7 @@ class Service(SimpleService):
:return: dict
"""
- af, sock_type, proto, canon_name, sa = socket_config
+ af, _, proto, _, sa = socket_config
port = str(sa[1])
try:
self.debug('Connecting socket to "{address}", port {port}'.format(address=sa[0], port=port))
diff --git a/conf.d/python.d/portcheck.conf b/collectors/python.d.plugin/portcheck/portcheck.conf
index b3dd8bd3f..b3dd8bd3f 100644
--- a/conf.d/python.d/portcheck.conf
+++ b/collectors/python.d.plugin/portcheck/portcheck.conf
diff --git a/collectors/python.d.plugin/postfix/Makefile.inc b/collectors/python.d.plugin/postfix/Makefile.inc
new file mode 100644
index 000000000..f4091b217
--- /dev/null
+++ b/collectors/python.d.plugin/postfix/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += postfix/postfix.chart.py
+dist_pythonconfig_DATA += postfix/postfix.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += postfix/README.md postfix/Makefile.inc
+
diff --git a/collectors/python.d.plugin/postfix/README.md b/collectors/python.d.plugin/postfix/README.md
new file mode 100644
index 000000000..77c95ff44
--- /dev/null
+++ b/collectors/python.d.plugin/postfix/README.md
@@ -0,0 +1,15 @@
+# postfix
+
+Simple module executing `postfix -p` to grab postfix queue.
+
+It produces only two charts:
+
+1. **Postfix Queue Emails**
+ * emails
+
+2. **Postfix Queue Emails Size** in KB
+ * size
+
+Configuration is not needed.
+
+---
diff --git a/python.d/postfix.chart.py b/collectors/python.d.plugin/postfix/postfix.chart.py
index a2129e4be..bdbd0feea 100644
--- a/python.d/postfix.chart.py
+++ b/collectors/python.d.plugin/postfix/postfix.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: postfix netdata python.d module
# Author: Pawel Krupa (paulfantom)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.FrameworkServices.ExecutableService import ExecutableService
@@ -14,22 +15,24 @@ ORDER = ['qemails', 'qsize']
CHARTS = {
'qemails': {
- 'options': [None, "Postfix Queue Emails", "emails", 'queue', 'postfix.qemails', 'line'],
+ 'options': [None, 'Postfix Queue Emails', 'emails', 'queue', 'postfix.qemails', 'line'],
'lines': [
['emails', None, 'absolute']
- ]},
+ ]
+ },
'qsize': {
- 'options': [None, "Postfix Queue Emails Size", "emails size in KB", 'queue', 'postfix.qsize', 'area'],
+ 'options': [None, 'Postfix Queue Emails Size', 'emails size in KB', 'queue', 'postfix.qsize', 'area'],
'lines': [
- ["size", None, 'absolute']
- ]}
+ ['size', None, 'absolute']
+ ]
+ }
}
class Service(ExecutableService):
def __init__(self, configuration=None, name=None):
ExecutableService.__init__(self, configuration=configuration, name=name)
- self.command = "postqueue -p"
+ self.command = 'postqueue -p'
self.order = ORDER
self.definitions = CHARTS
diff --git a/conf.d/python.d/postfix.conf b/collectors/python.d.plugin/postfix/postfix.conf
index e0d5a5f83..e0d5a5f83 100644
--- a/conf.d/python.d/postfix.conf
+++ b/collectors/python.d.plugin/postfix/postfix.conf
diff --git a/collectors/python.d.plugin/postgres/Makefile.inc b/collectors/python.d.plugin/postgres/Makefile.inc
new file mode 100644
index 000000000..91a185cb9
--- /dev/null
+++ b/collectors/python.d.plugin/postgres/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += postgres/postgres.chart.py
+dist_pythonconfig_DATA += postgres/postgres.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += postgres/README.md postgres/Makefile.inc
+
diff --git a/collectors/python.d.plugin/postgres/README.md b/collectors/python.d.plugin/postgres/README.md
new file mode 100644
index 000000000..e7b108d36
--- /dev/null
+++ b/collectors/python.d.plugin/postgres/README.md
@@ -0,0 +1,68 @@
+# postgres
+
+Module monitors one or more postgres servers.
+
+**Requirements:**
+
+ * `python-psycopg2` package. You have to install it 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
+ * committed
+ * 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`.
+
+---
diff --git a/python.d/postgres.chart.py b/collectors/python.d.plugin/postgres/postgres.chart.py
index 0522b1938..7f43877c3 100644
--- a/python.d/postgres.chart.py
+++ b/collectors/python.d.plugin/postgres/postgres.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: example netdata python.d module
# Authors: facetoe, dangtranhoang
+# SPDX-License-Identifier: GPL-3.0-or-later
from copy import deepcopy
@@ -20,221 +21,310 @@ update_every = 1
priority = 60000
retries = 60
-METRICS = dict(
- DATABASE=['connections',
- 'xact_commit',
- 'xact_rollback',
- 'blks_read',
- 'blks_hit',
- 'tup_returned',
- 'tup_fetched',
- 'tup_inserted',
- 'tup_updated',
- 'tup_deleted',
- 'conflicts',
- 'temp_files',
- 'temp_bytes',
- 'size'],
- BACKENDS=['backends_active',
- 'backends_idle'],
- INDEX_STATS=['index_count',
- 'index_size'],
- TABLE_STATS=['table_size',
- 'table_count'],
- WAL=['written_wal',
- 'recycled_wal',
- 'total_wal'],
- WAL_WRITES=['wal_writes'],
- ARCHIVE=['ready_count',
- 'done_count',
- 'file_count'],
- BGWRITER=['checkpoint_scheduled',
- 'checkpoint_requested',
- 'buffers_checkpoint',
- 'buffers_clean',
- 'maxwritten_clean',
- 'buffers_backend',
- 'buffers_alloc',
- 'buffers_backend_fsync'],
- LOCKS=['ExclusiveLock',
- 'RowShareLock',
- 'SIReadLock',
- 'ShareUpdateExclusiveLock',
- 'AccessExclusiveLock',
- 'AccessShareLock',
- 'ShareRowExclusiveLock',
- 'ShareLock',
- 'RowExclusiveLock'],
- AUTOVACUUM=['analyze',
- 'vacuum_analyze',
- 'vacuum',
- 'vacuum_freeze',
- 'brin_summarize'],
- STANDBY_DELTA=['sent_delta',
- 'write_delta',
- 'flush_delta',
- 'replay_delta'],
- REPSLOT_FILES=['replslot_wal_keep',
- 'replslot_files']
-
-)
-
-QUERIES = dict(
- WAL="""
+METRICS = {
+ 'DATABASE': [
+ 'connections',
+ 'xact_commit',
+ 'xact_rollback',
+ 'blks_read',
+ 'blks_hit',
+ 'tup_returned',
+ 'tup_fetched',
+ 'tup_inserted',
+ 'tup_updated',
+ 'tup_deleted',
+ 'conflicts',
+ 'temp_files',
+ 'temp_bytes',
+ 'size'
+ ],
+ 'BACKENDS': [
+ 'backends_active',
+ 'backends_idle'
+ ],
+ 'INDEX_STATS': [
+ 'index_count',
+ 'index_size'
+ ],
+ 'TABLE_STATS': [
+ 'table_size',
+ 'table_count'
+ ],
+ 'WAL': [
+ 'written_wal',
+ 'recycled_wal',
+ 'total_wal'
+ ],
+ 'WAL_WRITES': [
+ 'wal_writes'
+ ],
+ 'ARCHIVE': [
+ 'ready_count',
+ 'done_count',
+ 'file_count'
+ ],
+ 'BGWRITER': [
+ 'checkpoint_scheduled',
+ 'checkpoint_requested',
+ 'buffers_checkpoint',
+ 'buffers_clean',
+ 'maxwritten_clean',
+ 'buffers_backend',
+ 'buffers_alloc',
+ 'buffers_backend_fsync'
+ ],
+ 'LOCKS': [
+ 'ExclusiveLock',
+ 'RowShareLock',
+ 'SIReadLock',
+ 'ShareUpdateExclusiveLock',
+ 'AccessExclusiveLock',
+ 'AccessShareLock',
+ 'ShareRowExclusiveLock',
+ 'ShareLock',
+ 'RowExclusiveLock'
+ ],
+ 'AUTOVACUUM': [
+ 'analyze',
+ 'vacuum_analyze',
+ 'vacuum',
+ 'vacuum_freeze',
+ 'brin_summarize'
+ ],
+ 'STANDBY_DELTA': [
+ 'sent_delta',
+ 'write_delta',
+ 'flush_delta',
+ 'replay_delta'
+ ],
+ 'REPSLOT_FILES': [
+ 'replslot_wal_keep',
+ 'replslot_files'
+ ]
+}
+
+QUERIES = {
+ 'WAL': """
SELECT
- count(*) as total_wal,
- count(*) FILTER (WHERE type = 'recycled') AS recycled_wal,
- count(*) FILTER (WHERE type = 'written') AS written_wal
+ count(*) as total_wal,
+ count(*) FILTER (WHERE type = 'recycled') AS recycled_wal,
+ count(*) FILTER (WHERE type = 'written') AS written_wal
FROM
- (SELECT wal.name,
- pg_{0}file_name(CASE pg_is_in_recovery() WHEN true THEN NULL ELSE pg_current_{0}_{1}() END ),
- CASE WHEN wal.name > pg_{0}file_name(CASE pg_is_in_recovery() WHEN true THEN NULL ELSE pg_current_{0}_{1}() END ) THEN 'recycled'
- ELSE 'written'
- END AS type
- FROM pg_catalog.pg_ls_dir('pg_{0}') AS wal(name)
- WHERE name ~ '^[0-9A-F]{{24}}$'
- ORDER BY (pg_stat_file('pg_{0}/'||name)).modification, wal.name DESC) sub;
+ (SELECT
+ wal.name,
+ pg_{0}file_name(
+ CASE pg_is_in_recovery()
+ WHEN true THEN NULL
+ ELSE pg_current_{0}_{1}()
+ END ),
+ CASE
+ WHEN wal.name > pg_{0}file_name(
+ CASE pg_is_in_recovery()
+ WHEN true THEN NULL
+ ELSE pg_current_{0}_{1}()
+ END ) THEN 'recycled'
+ ELSE 'written'
+ END AS type
+ FROM pg_catalog.pg_ls_dir('pg_{0}') AS wal(name)
+ WHERE name ~ '^[0-9A-F]{{24}}$'
+ ORDER BY
+ (pg_stat_file('pg_{0}/'||name)).modification,
+ wal.name DESC) sub;
""",
- ARCHIVE="""
+ '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
+ 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_{0}/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;
+ 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="""
+ 'TABLE_STATS': """
SELECT
- ((sum(relpages) * 8) * 1024) AS table_size,
- count(1) AS table_count
+ ((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 index_size,
- count(1) AS index_count
+ ((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,
- numbackends AS connections,
- xact_commit AS xact_commit,
- xact_rollback AS xact_rollback,
- blks_read AS blks_read,
- blks_hit AS blks_hit,
- tup_returned AS tup_returned,
- tup_fetched AS tup_fetched,
- tup_inserted AS tup_inserted,
- tup_updated AS tup_updated,
- tup_deleted AS tup_deleted,
- conflicts AS conflicts,
- pg_database_size(datname) AS size,
- temp_files AS temp_files,
- temp_bytes AS temp_bytes
+ datname AS database_name,
+ numbackends AS connections,
+ xact_commit AS xact_commit,
+ xact_rollback AS xact_rollback,
+ blks_read AS blks_read,
+ blks_hit AS blks_hit,
+ tup_returned AS tup_returned,
+ tup_fetched AS tup_fetched,
+ tup_inserted AS tup_inserted,
+ tup_updated AS tup_updated,
+ tup_deleted AS tup_deleted,
+ conflicts AS conflicts,
+ pg_database_size(datname) AS size,
+ temp_files AS temp_files,
+ temp_bytes AS temp_bytes
FROM pg_stat_database
-WHERE datname IN %(databases)s
-;
+WHERE datname IN %(databases)s ;
""",
- BGWRITER="""
+ 'BGWRITER': """
SELECT
- checkpoints_timed AS checkpoint_scheduled,
- checkpoints_req AS checkpoint_requested,
- buffers_checkpoint * current_setting('block_size')::numeric buffers_checkpoint,
- buffers_clean * current_setting('block_size')::numeric buffers_clean,
- maxwritten_clean,
- buffers_backend * current_setting('block_size')::numeric buffers_backend,
- buffers_alloc * current_setting('block_size')::numeric buffers_alloc,
- buffers_backend_fsync
+ checkpoints_timed AS checkpoint_scheduled,
+ checkpoints_req AS checkpoint_requested,
+ buffers_checkpoint * current_setting('block_size')::numeric buffers_checkpoint,
+ buffers_clean * current_setting('block_size')::numeric buffers_clean,
+ maxwritten_clean,
+ buffers_backend * current_setting('block_size')::numeric buffers_backend,
+ buffers_alloc * current_setting('block_size')::numeric buffers_alloc,
+ buffers_backend_fsync
FROM pg_stat_bgwriter;
""",
- LOCKS="""
+ 'LOCKS': """
SELECT
- pg_database.datname as database_name,
- mode,
- count(mode) AS locks_count
+ pg_database.datname as database_name,
+ mode,
+ count(mode) AS locks_count
FROM pg_locks
- INNER JOIN pg_database ON pg_database.oid = pg_locks.database
+INNER JOIN pg_database
+ ON pg_database.oid = pg_locks.database
GROUP BY datname, mode
ORDER BY datname, mode;
""",
- FIND_DATABASES="""
-SELECT datname
+ 'FIND_DATABASES': """
+SELECT
+ datname
FROM pg_stat_database
-WHERE has_database_privilege((SELECT current_user), datname, 'connect')
-AND NOT datname ~* '^template\d+';
+WHERE
+ has_database_privilege(
+ (SELECT current_user), datname, 'connect')
+ AND NOT datname ~* '^template\d ';
""",
- FIND_STANDBY="""
-SELECT application_name
+ 'FIND_STANDBY': """
+SELECT
+ application_name
FROM pg_stat_replication
WHERE application_name IS NOT NULL
GROUP BY application_name;
""",
- FIND_REPLICATION_SLOT="""
+ 'FIND_REPLICATION_SLOT': """
SELECT slot_name
FROM pg_replication_slots;
""",
- STANDBY_DELTA="""
-SELECT application_name,
- pg_{0}_{1}_diff(CASE pg_is_in_recovery() WHEN true THEN pg_last_{0}_receive_{1}() ELSE pg_current_{0}_{1}() END , sent_{1}) AS sent_delta,
- pg_{0}_{1}_diff(CASE pg_is_in_recovery() WHEN true THEN pg_last_{0}_receive_{1}() ELSE pg_current_{0}_{1}() END , write_{1}) AS write_delta,
- pg_{0}_{1}_diff(CASE pg_is_in_recovery() WHEN true THEN pg_last_{0}_receive_{1}() ELSE pg_current_{0}_{1}() END , flush_{1}) AS flush_delta,
- pg_{0}_{1}_diff(CASE pg_is_in_recovery() WHEN true THEN pg_last_{0}_receive_{1}() ELSE pg_current_{0}_{1}() END , replay_{1}) AS replay_delta
+ 'STANDBY_DELTA': """
+SELECT
+ application_name,
+ pg_{0}_{1}_diff(
+ CASE pg_is_in_recovery()
+ WHEN true THEN pg_last_{0}_receive_{1}()
+ ELSE pg_current_{0}_{1}()
+ END,
+ sent_{1}) AS sent_delta,
+ pg_{0}_{1}_diff(
+ CASE pg_is_in_recovery()
+ WHEN true THEN pg_last_{0}_receive_{1}()
+ ELSE pg_current_{0}_{1}()
+ END,
+ write_{1}) AS write_delta,
+ pg_{0}_{1}_diff(
+ CASE pg_is_in_recovery()
+ WHEN true THEN pg_last_{0}_receive_{1}()
+ ELSE pg_current_{0}_{1}()
+ END,
+ flush_{1}) AS flush_delta,
+ pg_{0}_{1}_diff(
+ CASE pg_is_in_recovery()
+ WHEN true THEN pg_last_{0}_receive_{1}()
+ ELSE pg_current_{0}_{1}()
+ END,
+ replay_{1}) AS replay_delta
FROM pg_stat_replication
WHERE application_name IS NOT NULL;
""",
- REPSLOT_FILES="""
+ 'REPSLOT_FILES': """
WITH wal_size AS (
- SELECT current_setting('wal_block_size')::INT * setting::INT AS val
- FROM pg_settings
- WHERE name = 'wal_segment_size'
-)
-SELECT slot_name, slot_type, replslot_wal_keep, count(slot_file) AS replslot_files
-FROM (
- SELECT slot.slot_name, CASE WHEN slot_file <> 'state' THEN 1 END AS slot_file , slot_type,
- COALESCE (floor((pg_wal_lsn_diff (pg_current_wal_lsn (),
- slot.restart_lsn) - (pg_walfile_name_offset (restart_lsn)).file_offset) / (s.val)),
- 0) AS replslot_wal_keep
- FROM pg_replication_slots slot
- LEFT JOIN (
- SELECT slot2.slot_name,
- pg_ls_dir('pg_replslot/' || slot2.slot_name) AS slot_file
- FROM pg_replication_slots slot2
- ) files (slot_name, slot_file)
- ON slot.slot_name = files.slot_name
- CROSS JOIN wal_size s) AS d
-GROUP BY slot_name, slot_type, replslot_wal_keep;
+ SELECT
+ current_setting('wal_block_size')::INT * setting::INT AS val
+ FROM pg_settings
+ WHERE name = 'wal_segment_size'
+ )
+SELECT
+ slot_name,
+ slot_type,
+ replslot_wal_keep,
+ count(slot_file) AS replslot_files
+FROM
+ (SELECT
+ slot.slot_name,
+ CASE
+ WHEN slot_file <> 'state' THEN 1
+ END AS slot_file ,
+ slot_type,
+ COALESCE (
+ floor(
+ (pg_wal_lsn_diff(pg_current_wal_lsn (),slot.restart_lsn)
+ - (pg_walfile_name_offset (restart_lsn)).file_offset) / (s.val)
+ ),0) AS replslot_wal_keep
+ FROM pg_replication_slots slot
+ LEFT JOIN (
+ SELECT
+ slot2.slot_name,
+ pg_ls_dir('pg_replslot/' || slot2.slot_name) AS slot_file
+ FROM pg_replication_slots slot2
+ ) files (slot_name, slot_file)
+ ON slot.slot_name = files.slot_name
+ CROSS JOIN wal_size s
+ ) AS d
+GROUP BY
+ slot_name,
+ slot_type,
+ replslot_wal_keep;
""",
- IF_SUPERUSER="""
+ 'IF_SUPERUSER': """
SELECT current_setting('is_superuser') = 'on' AS is_superuser;
""",
- DETECT_SERVER_VERSION="""
+ 'DETECT_SERVER_VERSION': """
SHOW server_version_num;
""",
- AUTOVACUUM="""
+ 'AUTOVACUUM': """
SELECT
- count(*) FILTER (WHERE query LIKE 'autovacuum: ANALYZE%%') AS analyze,
- count(*) FILTER (WHERE query LIKE 'autovacuum: VACUUM ANALYZE%%') AS vacuum_analyze,
- count(*) FILTER (WHERE query LIKE 'autovacuum: VACUUM%%'
- AND query NOT LIKE 'autovacuum: VACUUM ANALYZE%%'
- AND query NOT LIKE '%%to prevent wraparound%%') AS vacuum,
- count(*) FILTER (WHERE query LIKE '%%to prevent wraparound%%') AS vacuum_freeze,
- count(*) FILTER (WHERE query LIKE 'autovacuum: BRIN summarize%%') AS brin_summarize
+ count(*) FILTER (WHERE query LIKE 'autovacuum: ANALYZE%%') AS analyze,
+ count(*) FILTER (WHERE query LIKE 'autovacuum: VACUUM ANALYZE%%') AS vacuum_analyze,
+ count(*) FILTER (WHERE query LIKE 'autovacuum: VACUUM%%'
+ AND query NOT LIKE 'autovacuum: VACUUM ANALYZE%%'
+ AND query NOT LIKE '%%to prevent wraparound%%') AS vacuum,
+ count(*) FILTER (WHERE query LIKE '%%to prevent wraparound%%') AS vacuum_freeze,
+ count(*) FILTER (WHERE query LIKE 'autovacuum: BRIN summarize%%') AS brin_summarize
FROM pg_stat_activity
WHERE query NOT LIKE '%%pg_stat_activity%%';
""",
- DIFF_LSN="""
-SELECT pg_{0}_{1}_diff(CASE pg_is_in_recovery() WHEN true THEN pg_last_{0}_receive_{1}() ELSE pg_current_{0}_{1}() END, '0/0') as wal_writes ;
+ 'DIFF_LSN': """
+SELECT
+ pg_{0}_{1}_diff(
+ CASE pg_is_in_recovery()
+ WHEN true THEN pg_last_{0}_receive_{1}()
+ ELSE pg_current_{0}_{1}()
+ END,
+ '0/0') as wal_writes ;
"""
-
-)
+}
QUERY_STATS = {
@@ -243,11 +333,34 @@ QUERY_STATS = {
QUERIES['LOCKS']: METRICS['LOCKS']
}
-ORDER = ['db_stat_temp_files', 'db_stat_temp_bytes', 'db_stat_blks', 'db_stat_tuple_returned', 'db_stat_tuple_write',
- 'db_stat_transactions','db_stat_connections', 'database_size', 'backend_process', 'index_count', 'index_size',
- 'table_count', 'table_size', 'wal', 'wal_writes', 'archive_wal', 'checkpointer', 'stat_bgwriter_alloc', 'stat_bgwriter_checkpoint',
- 'stat_bgwriter_backend', 'stat_bgwriter_backend_fsync' , 'stat_bgwriter_bgwriter', 'stat_bgwriter_maxwritten',
- 'replication_slot', 'standby_delta', 'autovacuum']
+ORDER = [
+ 'db_stat_temp_files',
+ 'db_stat_temp_bytes',
+ 'db_stat_blks',
+ 'db_stat_tuple_returned',
+ 'db_stat_tuple_write',
+ 'db_stat_transactions',
+ 'db_stat_connections',
+ 'database_size',
+ 'backend_process',
+ 'index_count',
+ 'index_size',
+ 'table_count',
+ 'table_size',
+ 'wal',
+ 'wal_writes',
+ 'archive_wal',
+ 'checkpointer',
+ 'stat_bgwriter_alloc',
+ 'stat_bgwriter_checkpoint',
+ 'stat_bgwriter_backend',
+ 'stat_bgwriter_backend_fsync',
+ 'stat_bgwriter_bgwriter',
+ 'stat_bgwriter_maxwritten',
+ 'replication_slot',
+ 'standby_delta',
+ 'autovacuum'
+]
CHARTS = {
'db_stat_transactions': {
@@ -256,26 +369,30 @@ CHARTS = {
'lines': [
['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'],
'lines': [
['connections', 'connections', 'absolute']
- ]},
+ ]
+ },
'db_stat_blks': {
'options': [None, 'Disk blocks reads from db', 'reads/s', 'db statistics', 'postgres.db_stat_blks', 'line'],
'lines': [
['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'],
'lines': [
['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': [
@@ -283,103 +400,128 @@ CHARTS = {
['tup_updated', 'updated', 'incremental'],
['tup_deleted', 'deleted', 'incremental'],
['conflicts', 'conflicts', 'incremental']
- ]},
+ ]
+ },
'db_stat_temp_bytes': {
- 'options': [None, 'Temp files written to disk', 'KB/s', 'db statistics', 'postgres.db_stat_temp_bytes', 'line'],
+ 'options': [None, 'Temp files written to disk', 'KB/s', 'db statistics', 'postgres.db_stat_temp_bytes',
+ 'line'],
'lines': [
['temp_bytes', 'size', 'incremental', 1, 1024]
- ]},
+ ]
+ },
'db_stat_temp_files': {
- 'options': [None, 'Temp files written to disk', 'files', 'db statistics', 'postgres.db_stat_temp_files', 'line'],
+ 'options': [None, 'Temp files written to disk', 'files', 'db statistics', 'postgres.db_stat_temp_files',
+ 'line'],
'lines': [
['temp_files', 'files', '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'],
'lines': [
['backends_active', 'active', 'absolute'],
['backends_idle', 'idle', 'absolute']
- ]},
+ ]
+ },
'index_count': {
'options': [None, 'Total indexes', 'index', 'indexes', 'postgres.index_count', 'line'],
'lines': [
['index_count', 'total', 'absolute']
- ]},
+ ]
+ },
'index_size': {
'options': [None, 'Indexes size', 'MB', 'indexes', 'postgres.index_size', 'line'],
'lines': [
['index_size', 'size', 'absolute', 1, 1024 * 1024]
- ]},
+ ]
+ },
'table_count': {
'options': [None, 'Total Tables', 'tables', 'tables', 'postgres.table_count', 'line'],
'lines': [
['table_count', 'total', 'absolute']
- ]},
+ ]
+ },
'table_size': {
'options': [None, 'Tables size', 'MB', 'tables', 'postgres.table_size', 'line'],
'lines': [
['table_size', 'size', 'absolute', 1, 1024 * 1024]
- ]},
+ ]
+ },
'wal': {
'options': [None, 'Write-Ahead Logs', 'files', 'wal', 'postgres.wal', 'line'],
'lines': [
['written_wal', 'written', 'absolute'],
['recycled_wal', 'recycled', 'absolute'],
['total_wal', 'total', 'absolute']
- ]},
+ ]
+ },
'wal_writes': {
'options': [None, 'Write-Ahead Logs', 'kilobytes/s', 'wal_writes', 'postgres.wal_writes', 'line'],
'lines': [
['wal_writes', 'writes', 'incremental', 1, 1024]
- ]},
+ ]
+ },
'archive_wal': {
'options': [None, 'Archive Write-Ahead Logs', 'files/s', 'archive wal', 'postgres.archive_wal', 'line'],
'lines': [
['file_count', 'total', 'incremental'],
['ready_count', 'ready', 'incremental'],
['done_count', 'done', 'incremental']
- ]},
+ ]
+ },
'checkpointer': {
'options': [None, 'Checkpoints', 'writes', 'checkpointer', 'postgres.checkpointer', 'line'],
'lines': [
['checkpoint_scheduled', 'scheduled', 'incremental'],
['checkpoint_requested', 'requested', 'incremental']
- ]},
+ ]
+ },
'stat_bgwriter_alloc': {
'options': [None, 'Buffers allocated', 'kilobytes/s', 'bgwriter', 'postgres.stat_bgwriter_alloc', 'line'],
'lines': [
['buffers_alloc', 'alloc', 'incremental', 1, 1024]
- ]},
+ ]
+ },
'stat_bgwriter_checkpoint': {
- 'options': [None, 'Buffers written during checkpoints', 'kilobytes/s', 'bgwriter', 'postgres.stat_bgwriter_checkpoint', 'line'],
+ 'options': [None, 'Buffers written during checkpoints', 'kilobytes/s', 'bgwriter',
+ 'postgres.stat_bgwriter_checkpoint', 'line'],
'lines': [
['buffers_checkpoint', 'checkpoint', 'incremental', 1, 1024]
- ]},
+ ]
+ },
'stat_bgwriter_backend': {
- 'options': [None, 'Buffers written directly by a backend', 'kilobytes/s', 'bgwriter', 'postgres.stat_bgwriter_backend', 'line'],
+ 'options': [None, 'Buffers written directly by a backend', 'kilobytes/s', 'bgwriter',
+ 'postgres.stat_bgwriter_backend', 'line'],
'lines': [
['buffers_backend', 'backend', 'incremental', 1, 1024]
- ]},
+ ]
+ },
'stat_bgwriter_backend_fsync': {
'options': [None, 'Fsync by backend', 'times', 'bgwriter', 'postgres.stat_bgwriter_backend_fsync', 'line'],
'lines': [
['buffers_backend_fsync', 'backend fsync', 'incremental']
- ]},
+ ]
+ },
'stat_bgwriter_bgwriter': {
- 'options': [None, 'Buffers written by the background writer', 'kilobytes/s', 'bgwriter', 'postgres.bgwriter_bgwriter', 'line'],
+ 'options': [None, 'Buffers written by the background writer', 'kilobytes/s', 'bgwriter',
+ 'postgres.bgwriter_bgwriter', 'line'],
'lines': [
['buffers_clean', 'clean', 'incremental', 1, 1024]
- ]},
+ ]
+ },
'stat_bgwriter_maxwritten': {
- 'options': [None, 'Too many buffers written', 'times', 'bgwriter', 'postgres.stat_bgwriter_maxwritten', 'line'],
+ 'options': [None, 'Too many buffers written', 'times', 'bgwriter', 'postgres.stat_bgwriter_maxwritten',
+ 'line'],
'lines': [
['maxwritten_clean', 'maxwritten', 'incremental']
- ]},
+ ]
+ },
'autovacuum': {
'options': [None, 'Autovacuum workers', 'workers', 'autovacuum', 'postgres.autovacuum', 'line'],
'lines': [
@@ -388,7 +530,8 @@ CHARTS = {
['vacuum_analyze', 'vacuum analyze', 'absolute'],
['vacuum_freeze', 'vacuum freeze', 'absolute'],
['brin_summarize', 'brin summarize', 'absolute']
- ]},
+ ]
+ },
'standby_delta': {
'options': [None, 'Standby delta', 'kilobytes', 'replication delta', 'postgres.standby_delta', 'line'],
'lines': [
@@ -396,13 +539,15 @@ CHARTS = {
['write_delta', 'write delta', 'absolute', 1, 1024],
['flush_delta', 'flush delta', 'absolute', 1, 1024],
['replay_delta', 'replay delta', 'absolute', 1, 1024]
- ]},
- 'replication_slot': {
+ ]
+ },
+ 'replication_slot': {
'options': [None, 'Replication slot files', 'files', 'replication slot', 'postgres.replication_slot', 'line'],
'lines': [
['replslot_wal_keep', 'wal keeped', 'absolute'],
['replslot_files', 'pg_replslot files', 'absolute']
- ]}
+ ]
+ }
}
@@ -462,7 +607,7 @@ class Service(SimpleService):
cursor.close()
if self.database_poll and isinstance(self.database_poll, str):
- self.databases = [dbase for dbase in self.databases if dbase in self.database_poll.split()]\
+ self.databases = [dbase for dbase in self.databases if dbase in self.database_poll.split()] \
or self.databases
self.locks_zeroed = populate_lock_types(self.databases)
@@ -482,8 +627,8 @@ class Service(SimpleService):
wal = 'xlog'
lsn = 'location'
self.queries[QUERIES['BGWRITER']] = METRICS['BGWRITER']
- self.queries[QUERIES['DIFF_LSN'].format(wal,lsn)] = METRICS['WAL_WRITES']
- self.queries[QUERIES['STANDBY_DELTA'].format(wal,lsn)] = METRICS['STANDBY_DELTA']
+ self.queries[QUERIES['DIFF_LSN'].format(wal, lsn)] = METRICS['WAL_WRITES']
+ self.queries[QUERIES['STANDBY_DELTA'].format(wal, lsn)] = METRICS['STANDBY_DELTA']
if self.index_stats:
self.queries[QUERIES['INDEX_STATS']] = METRICS['INDEX_STATS']
@@ -492,7 +637,7 @@ class Service(SimpleService):
if is_superuser:
self.queries[QUERIES['ARCHIVE'].format(wal)] = METRICS['ARCHIVE']
if self.server_version >= 90400:
- self.queries[QUERIES['WAL'].format(wal,lsn)] = METRICS['WAL']
+ self.queries[QUERIES['WAL'].format(wal, lsn)] = METRICS['WAL']
if self.server_version >= 100000:
self.queries[QUERIES['REPSLOT_FILES']] = METRICS['REPSLOT_FILES']
if self.server_version >= 90400:
@@ -501,8 +646,8 @@ class Service(SimpleService):
def create_dynamic_charts_(self):
for database_name in self.databases[::-1]:
- self.definitions['database_size']['lines'].append([database_name + '_size',
- database_name, 'absolute', 1, 1024 * 1024])
+ self.definitions['database_size']['lines'].append(
+ [database_name + '_size', database_name, 'absolute', 1, 1024 * 1024])
for chart_name in [name for name in self.order if name.startswith('db_stat')]:
add_database_stat_chart_(order=self.order, definitions=self.definitions,
name=chart_name, database_name=database_name)
@@ -510,17 +655,21 @@ class Service(SimpleService):
add_database_lock_chart_(order=self.order, definitions=self.definitions, database_name=database_name)
for application_name in self.secondaries[::-1]:
- add_replication_delta_chart_(order=self.order, definitions=self.definitions,
- name='standby_delta', application_name=application_name)
+ add_replication_delta_chart_(
+ order=self.order,
+ definitions=self.definitions,
+ name='standby_delta',
+ application_name=application_name)
for slot_name in self.replication_slots[::-1]:
- add_replication_slot_chart_(order=self.order, definitions=self.definitions,
- name='replication_slot', slot_name=slot_name)
-
-
+ add_replication_slot_chart_(
+ order=self.order,
+ definitions=self.definitions,
+ name='replication_slot',
+ slot_name=slot_name)
def _get_data(self):
- result, error = self._connect()
+ result, _ = self._connect()
if result:
cursor = self.connection.cursor(cursor_factory=DictCursor)
try:
@@ -551,7 +700,8 @@ class Service(SimpleService):
else:
dimension_id = metric
if metric in row:
- self.data[dimension_id] = int(row[metric])
+ if row[metric] is not None:
+ 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
@@ -564,6 +714,7 @@ def discover_databases_(cursor, query):
result.append(db)
return result
+
def discover_secondaries_(cursor, query):
cursor.execute(query)
result = list()
@@ -572,6 +723,7 @@ def discover_secondaries_(cursor, query):
result.append(sc)
return result
+
def discover_replication_slots_(cursor, query):
cursor.execute(query)
result = list()
@@ -580,14 +732,17 @@ def discover_replication_slots_(cursor, query):
result.append(slot)
return result
+
def check_if_superuser_(cursor, query):
cursor.execute(query)
return cursor.fetchone()[0]
+
def detect_server_version(cursor, query):
cursor.execute(query)
return int(cursor.fetchone()[0])
+
def populate_lock_types(databases):
result = dict()
for database in databases:
@@ -626,11 +781,12 @@ def add_database_stat_chart_(order, definitions, name, database_name):
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']
+ name, title, units, _, 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_delta_chart_(order, definitions, name, application_name):
def create_lines(standby, lines):
result = list()
@@ -648,6 +804,7 @@ def add_replication_delta_chart_(order, definitions, name, application_name):
'options': [name, title + ': ' + application_name, units, 'replication delta', context, chart_type],
'lines': create_lines(application_name, chart_template['lines'])}
+
def add_replication_slot_chart_(order, definitions, name, slot_name):
def create_lines(slot, lines):
result = list()
diff --git a/conf.d/python.d/postgres.conf b/collectors/python.d.plugin/postgres/postgres.conf
index b69ca3717..b69ca3717 100644
--- a/conf.d/python.d/postgres.conf
+++ b/collectors/python.d.plugin/postgres/postgres.conf
diff --git a/collectors/python.d.plugin/powerdns/Makefile.inc b/collectors/python.d.plugin/powerdns/Makefile.inc
new file mode 100644
index 000000000..256d32a40
--- /dev/null
+++ b/collectors/python.d.plugin/powerdns/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += powerdns/powerdns.chart.py
+dist_pythonconfig_DATA += powerdns/powerdns.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += powerdns/README.md powerdns/Makefile.inc
+
diff --git a/collectors/python.d.plugin/powerdns/README.md b/collectors/python.d.plugin/powerdns/README.md
new file mode 100644
index 000000000..3c4b145e0
--- /dev/null
+++ b/collectors/python.d.plugin/powerdns/README.md
@@ -0,0 +1,77 @@
+# powerdns
+
+Module monitor powerdns performance and health metrics.
+
+Powerdns charts:
+
+1. **Queries and Answers**
+ * udp-queries
+ * udp-answers
+ * tcp-queries
+ * tcp-answers
+
+2. **Cache Usage**
+ * query-cache-hit
+ * query-cache-miss
+ * packetcache-hit
+ * packetcache-miss
+
+3. **Cache Size**
+ * query-cache-size
+ * packetcache-size
+ * key-cache-size
+ * meta-cache-size
+
+4. **Latency**
+ * latency
+
+ Powerdns Recursor charts:
+
+ 1. **Questions In**
+ * questions
+ * ipv6-questions
+ * tcp-queries
+
+2. **Questions Out**
+ * all-outqueries
+ * ipv6-outqueries
+ * tcp-outqueries
+ * throttled-outqueries
+
+3. **Answer Times**
+ * answers-slow
+ * answers0-1
+ * answers1-10
+ * answers10-100
+ * answers100-1000
+
+4. **Timeouts**
+ * outgoing-timeouts
+ * outgoing4-timeouts
+ * outgoing6-timeouts
+
+5. **Drops**
+ * over-capacity-drops
+
+6. **Cache Usage**
+ * cache-hits
+ * cache-misses
+ * packetcache-hits
+ * packetcache-misses
+
+7. **Cache Size**
+ * cache-entries
+ * packetcache-entries
+ * negcache-entries
+
+### configuration
+
+```yaml
+local:
+ name : 'local'
+ url : 'http://127.0.0.1:8081/api/v1/servers/localhost/statistics'
+ header :
+ X-API-Key: 'change_me'
+```
+
+---
diff --git a/collectors/python.d.plugin/powerdns/powerdns.chart.py b/collectors/python.d.plugin/powerdns/powerdns.chart.py
new file mode 100644
index 000000000..4264621b2
--- /dev/null
+++ b/collectors/python.d.plugin/powerdns/powerdns.chart.py
@@ -0,0 +1,150 @@
+# -*- coding: utf-8 -*-
+# Description: powerdns netdata python.d module
+# Author: Ilya Mashchenko (l2isbad)
+# Author: Luke Whitworth
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from json import loads
+
+from bases.FrameworkServices.UrlService import UrlService
+
+priority = 60000
+retries = 60
+# update_every = 3
+
+ORDER = ['questions', 'cache_usage', 'cache_size', 'latency']
+CHARTS = {
+ 'questions': {
+ 'options': [None, 'PowerDNS Queries and Answers', 'count', 'questions', 'powerdns.questions', 'line'],
+ 'lines': [
+ ['udp-queries', None, 'incremental'],
+ ['udp-answers', None, 'incremental'],
+ ['tcp-queries', None, 'incremental'],
+ ['tcp-answers', None, 'incremental']
+ ]
+ },
+ 'cache_usage': {
+ 'options': [None, 'PowerDNS Cache Usage', 'count', 'cache', 'powerdns.cache_usage', 'line'],
+ 'lines': [
+ ['query-cache-hit', None, 'incremental'],
+ ['query-cache-miss', None, 'incremental'],
+ ['packetcache-hit', 'packet-cache-hit', 'incremental'],
+ ['packetcache-miss', 'packet-cache-miss', 'incremental']
+ ]
+ },
+ 'cache_size': {
+ 'options': [None, 'PowerDNS Cache Size', 'count', 'cache', 'powerdns.cache_size', 'line'],
+ 'lines': [
+ ['query-cache-size', None, 'absolute'],
+ ['packetcache-size', 'packet-cache-size', 'absolute'],
+ ['key-cache-size', None, 'absolute'],
+ ['meta-cache-size', None, 'absolute']
+ ]
+ },
+ 'latency': {
+ 'options': [None, 'PowerDNS Latency', 'microseconds', 'latency', 'powerdns.latency', 'line'],
+ 'lines': [
+ ['latency', None, 'absolute']
+ ]
+ }
+}
+
+RECURSOR_ORDER = ['questions-in', 'questions-out', 'answer-times', 'timeouts', 'drops', 'cache_usage', 'cache_size']
+
+RECURSOR_CHARTS = {
+ 'questions-in': {
+ 'options': [None, 'PowerDNS Recursor Questions In', 'count', 'questions', 'powerdns_recursor.questions-in',
+ 'line'],
+ 'lines': [
+ ['questions', None, 'incremental'],
+ ['ipv6-questions', None, 'incremental'],
+ ['tcp-questions', None, 'incremental']
+ ]
+ },
+ 'questions-out': {
+ 'options': [None, 'PowerDNS Recursor Questions Out', 'count', 'questions', 'powerdns_recursor.questions-out',
+ 'line'],
+ 'lines': [
+ ['all-outqueries', None, 'incremental'],
+ ['ipv6-outqueries', None, 'incremental'],
+ ['tcp-outqueries', None, 'incremental'],
+ ['throttled-outqueries', None, 'incremental']
+ ]
+ },
+ 'answer-times': {
+ 'options': [None, 'PowerDNS Recursor Answer Times', 'count', 'performance', 'powerdns_recursor.answer-times',
+ 'line'],
+ 'lines': [
+ ['answers-slow', None, 'incremental'],
+ ['answers0-1', None, 'incremental'],
+ ['answers1-10', None, 'incremental'],
+ ['answers10-100', None, 'incremental'],
+ ['answers100-1000', None, 'incremental']
+ ]
+ },
+ 'timeouts': {
+ 'options': [None, 'PowerDNS Recursor Questions Time', 'count', 'performance', 'powerdns_recursor.timeouts',
+ 'line'],
+ 'lines': [
+ ['outgoing-timeouts', None, 'incremental'],
+ ['outgoing4-timeouts', None, 'incremental'],
+ ['outgoing6-timeouts', None, 'incremental']
+ ]
+ },
+ 'drops': {
+ 'options': [None, 'PowerDNS Recursor Drops', 'count', 'performance', 'powerdns_recursor.drops', 'line'],
+ 'lines': [
+ ['over-capacity-drops', None, 'incremental']
+ ]
+ },
+ 'cache_usage': {
+ 'options': [None, 'PowerDNS Recursor Cache Usage', 'count', 'cache', 'powerdns_recursor.cache_usage', 'line'],
+ 'lines': [
+ ['cache-hits', None, 'incremental'],
+ ['cache-misses', None, 'incremental'],
+ ['packetcache-hits', 'packet-cache-hit', 'incremental'],
+ ['packetcache-misses', 'packet-cache-miss', 'incremental']
+ ]
+ },
+ 'cache_size': {
+ 'options': [None, 'PowerDNS Recursor Cache Size', 'count', 'cache', 'powerdns_recursor.cache_size', 'line'],
+ 'lines': [
+ ['cache-entries', None, 'absolute'],
+ ['packetcache-entries', None, 'absolute'],
+ ['negcache-entries', None, 'absolute']
+ ]
+ }
+}
+
+
+class Service(UrlService):
+ def __init__(self, configuration=None, name=None):
+ UrlService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+
+ def check(self):
+ self._manager = self._build_manager()
+ if not self._manager:
+ return None
+
+ d = self._get_data()
+ if not d:
+ return False
+
+ if is_recursor(d):
+ self.order = RECURSOR_ORDER
+ self.definitions = RECURSOR_CHARTS
+ self.module_name = 'powerdns_recursor'
+
+ return True
+
+ def _get_data(self):
+ data = self._get_raw_data()
+ if not data:
+ return None
+ return dict((d['name'], d['value']) for d in loads(data))
+
+
+def is_recursor(d):
+ return 'over-capacity-drops' in d and 'tcp-questions' in d
diff --git a/conf.d/python.d/powerdns.conf b/collectors/python.d.plugin/powerdns/powerdns.conf
index ca6200df1..ca6200df1 100644
--- a/conf.d/python.d/powerdns.conf
+++ b/collectors/python.d.plugin/powerdns/powerdns.conf
diff --git a/collectors/python.d.plugin/proxysql/Makefile.inc b/collectors/python.d.plugin/proxysql/Makefile.inc
new file mode 100644
index 000000000..66be372ce
--- /dev/null
+++ b/collectors/python.d.plugin/proxysql/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += proxysql/proxysql.chart.py
+dist_pythonconfig_DATA += proxysql/proxysql.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += proxysql/README.md proxysql/Makefile.inc
+
diff --git a/collectors/python.d.plugin/proxysql/README.md b/collectors/python.d.plugin/proxysql/README.md
new file mode 100644
index 000000000..02388276e
--- /dev/null
+++ b/collectors/python.d.plugin/proxysql/README.md
@@ -0,0 +1,62 @@
+# proxysql
+
+This module monitors proxysql backend and frontend performance metrics.
+
+It produces:
+
+1. **Connections (frontend)**
+ * connected: number of frontend connections currently connected
+ * aborted: number of frontend connections aborted due to invalid credential or max_connections reached
+ * non_idle: number of frontend connections that are not currently idle
+ * created: number of frontend connections created
+2. **Questions (frontend)**
+ * questions: total number of queries sent from frontends
+ * slow_queries: number of queries that ran for longer than the threshold in milliseconds defined in global variable `mysql-long_query_time`
+3. **Overall Bandwith (backends)**
+ * in
+ * out
+4. **Status (backends)**
+ * Backends
+ * `1=ONLINE`: backend server is fully operational
+ * `2=SHUNNED`: backend sever is temporarily taken out of use because of either too many connection errors in a time that was too short, or replication lag exceeded the allowed threshold
+ * `3=OFFLINE_SOFT`: when a server is put into OFFLINE_SOFT mode, new incoming connections aren't accepted anymore, while the existing connections are kept until they became inactive. In other words, connections are kept in use until the current transaction is completed. This allows to gracefully detach a backend
+ * `4=OFFLINE_HARD`: when a server is put into OFFLINE_HARD mode, the existing connections are dropped, while new incoming connections aren't accepted either. This is equivalent to deleting the server from a hostgroup, or temporarily taking it out of the hostgroup for maintenance work
+ * `-1`: Unknown status
+5. **Bandwith (backends)**
+ * Backends
+ * in
+ * out
+6. **Queries (backends)**
+ * Backends
+ * queries
+7. **Latency (backends)**
+ * Backends
+ * ping time
+8. **Pool connections (backends)**
+ * Backends
+ * Used: The number of connections are currently used by ProxySQL for sending queries to the backend server.
+ * Free: The number of connections are currently free.
+ * Established/OK: The number of connections were established successfully.
+ * Error: The number of connections weren't established successfully.
+9. **Commands**
+ * Commands
+ * Count
+ * Duration (Total duration for each command)
+10. **Commands Histogram**
+ * Commands
+ * 100us, 500us, ..., 10s, inf: the total number of commands of the given type which executed within the specified time limit and the previous one.
+
+### configuration
+
+```yaml
+tcpipv4:
+ name : 'local'
+ user : 'stats'
+ pass : 'stats'
+ host : '127.0.0.1'
+ port : '6032'
+```
+
+If no configuration is given, module will fail to run.
+
+---
diff --git a/collectors/python.d.plugin/proxysql/proxysql.chart.py b/collectors/python.d.plugin/proxysql/proxysql.chart.py
new file mode 100644
index 000000000..f7e3d49f9
--- /dev/null
+++ b/collectors/python.d.plugin/proxysql/proxysql.chart.py
@@ -0,0 +1,356 @@
+# -*- coding: utf-8 -*-
+# Description: Proxysql netdata python.d module
+# Author: Ali Borhani (alibo)
+# SPDX-License-Identifier: GPL-3.0+
+
+from bases.FrameworkServices.MySQLService import MySQLService
+
+# default module values (can be overridden per job in `config`)
+# update_every = 3
+priority = 60000
+retries = 60
+
+
+def query(table, *params):
+ return 'SELECT {params} FROM {table}'.format(table=table, params=', '.join(params))
+
+
+# https://github.com/sysown/proxysql/blob/master/doc/admin_tables.md#stats_mysql_global
+QUERY_GLOBAL = query(
+ "stats_mysql_global",
+ "Variable_Name",
+ "Variable_Value"
+)
+
+# https://github.com/sysown/proxysql/blob/master/doc/admin_tables.md#stats_mysql_connection_pool
+QUERY_CONNECTION_POOL = query(
+ "stats_mysql_connection_pool",
+ "hostgroup",
+ "srv_host",
+ "srv_port",
+ "status",
+ "ConnUsed",
+ "ConnFree",
+ "ConnOK",
+ "ConnERR",
+ "Queries",
+ "Bytes_data_sent",
+ "Bytes_data_recv",
+ "Latency_us"
+)
+
+# https://github.com/sysown/proxysql/blob/master/doc/admin_tables.md#stats_mysql_commands_counters
+QUERY_COMMANDS = query(
+ "stats_mysql_commands_counters",
+ "Command",
+ "Total_Time_us",
+ "Total_cnt",
+ "cnt_100us",
+ "cnt_500us",
+ "cnt_1ms",
+ "cnt_5ms",
+ "cnt_10ms",
+ "cnt_50ms",
+ "cnt_100ms",
+ "cnt_500ms",
+ "cnt_1s",
+ "cnt_5s",
+ "cnt_10s",
+ "cnt_INFs"
+)
+
+GLOBAL_STATS = [
+ 'client_connections_aborted',
+ 'client_connections_connected',
+ 'client_connections_created',
+ 'client_connections_non_idle',
+ 'proxysql_uptime',
+ 'questions',
+ 'slow_queries'
+]
+
+CONNECTION_POOL_STATS = [
+ 'status',
+ 'connused',
+ 'connfree',
+ 'connok',
+ 'connerr',
+ 'queries',
+ 'bytes_data_sent',
+ 'bytes_data_recv',
+ 'latency_us'
+]
+
+ORDER = [
+ 'connections',
+ 'active_transactions',
+ 'questions',
+ 'pool_overall_net',
+ 'commands_count',
+ 'commands_duration',
+ 'pool_status',
+ 'pool_net',
+ 'pool_queries',
+ 'pool_latency',
+ 'pool_connection_used',
+ 'pool_connection_free',
+ 'pool_connection_ok',
+ 'pool_connection_error'
+]
+
+HISTOGRAM_ORDER = [
+ '100us',
+ '500us',
+ '1ms',
+ '5ms',
+ '10ms',
+ '50ms',
+ '100ms',
+ '500ms',
+ '1s',
+ '5s',
+ '10s',
+ 'inf'
+]
+
+STATUS = {
+ "ONLINE": 1,
+ "SHUNNED": 2,
+ "OFFLINE_SOFT": 3,
+ "OFFLINE_HARD": 4
+}
+
+CHARTS = {
+ 'pool_status': {
+ 'options': [None, 'ProxySQL Backend Status', 'status', 'status', 'proxysql.pool_status', 'line'],
+ 'lines': []
+ },
+ 'pool_net': {
+ 'options': [None, 'ProxySQL Backend Bandwidth', 'kilobits/s', 'bandwidth', 'proxysql.pool_net', 'area'],
+ 'lines': []
+ },
+ 'pool_overall_net': {
+ 'options': [None, 'ProxySQL Backend Overall Bandwidth', 'kilobits/s', 'overall_bandwidth',
+ 'proxysql.pool_overall_net', 'area'],
+ 'lines': [
+ ['bytes_data_recv', 'in', 'incremental', 8, 1024],
+ ['bytes_data_sent', 'out', 'incremental', -8, 1024]
+ ]
+ },
+ 'questions': {
+ 'options': [None, 'ProxySQL Frontend Questions', 'questions/s', 'questions', 'proxysql.questions', 'line'],
+ 'lines': [
+ ['questions', 'questions', 'incremental'],
+ ['slow_queries', 'slow_queries', 'incremental']
+ ]
+ },
+ 'pool_queries': {
+ 'options': [None, 'ProxySQL Backend Queries', 'queries/s', 'queries', 'proxysql.queries', 'line'],
+ 'lines': []
+ },
+ 'active_transactions': {
+ 'options': [None, 'ProxySQL Frontend Active Transactions', 'transactions/s', 'active_transactions',
+ 'proxysql.active_transactions', 'line'],
+ 'lines': [
+ ['active_transactions', 'active_transactions', 'absolute']
+ ]
+ },
+ 'pool_latency': {
+ 'options': [None, 'ProxySQL Backend Latency', 'ms', 'latency', 'proxysql.latency', 'line'],
+ 'lines': []
+ },
+ 'connections': {
+ 'options': [None, 'ProxySQL Frontend Connections', 'connections/s', 'connections', 'proxysql.connections',
+ 'line'],
+ 'lines': [
+ ['client_connections_connected', 'connected', 'absolute'],
+ ['client_connections_created', 'created', 'incremental'],
+ ['client_connections_aborted', 'aborted', 'incremental'],
+ ['client_connections_non_idle', 'non_idle', 'absolute']
+ ]
+ },
+ 'pool_connection_used': {
+ 'options': [None, 'ProxySQL Used Connections', 'connections', 'pool_connections',
+ 'proxysql.pool_used_connections', 'line'],
+ 'lines': []
+ },
+ 'pool_connection_free': {
+ 'options': [None, 'ProxySQL Free Connections', 'connections', 'pool_connections',
+ 'proxysql.pool_free_connections', 'line'],
+ 'lines': []
+ },
+ 'pool_connection_ok': {
+ 'options': [None, 'ProxySQL Established Connections', 'connections', 'pool_connections',
+ 'proxysql.pool_ok_connections', 'line'],
+ 'lines': []
+ },
+ 'pool_connection_error': {
+ 'options': [None, 'ProxySQL Error Connections', 'connections', 'pool_connections',
+ 'proxysql.pool_error_connections', 'line'],
+ 'lines': []
+ },
+ 'commands_count': {
+ 'options': [None, 'ProxySQL Commands', 'commands', 'commands', 'proxysql.commands_count', 'line'],
+ 'lines': []
+ },
+ 'commands_duration': {
+ 'options': [None, 'ProxySQL Commands Duration', 'ms', 'commands', 'proxysql.commands_duration', 'line'],
+ 'lines': []
+ }
+}
+
+
+class Service(MySQLService):
+ def __init__(self, configuration=None, name=None):
+ MySQLService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+ self.queries = dict(
+ global_status=QUERY_GLOBAL,
+ connection_pool_status=QUERY_CONNECTION_POOL,
+ commands_status=QUERY_COMMANDS
+ )
+
+ def _get_data(self):
+ raw_data = self._get_raw_data(description=True)
+
+ if not raw_data:
+ return None
+
+ to_netdata = dict()
+
+ if 'global_status' in raw_data:
+ global_status = dict(raw_data['global_status'][0])
+ for key in global_status:
+ if key.lower() in GLOBAL_STATS:
+ to_netdata[key.lower()] = global_status[key]
+
+ if 'connection_pool_status' in raw_data:
+
+ to_netdata['bytes_data_recv'] = 0
+ to_netdata['bytes_data_sent'] = 0
+
+ for record in raw_data['connection_pool_status'][0]:
+ backend = self.generate_backend(record)
+ name = self.generate_backend_name(backend)
+
+ for key in backend:
+ if key in CONNECTION_POOL_STATS:
+ if key == 'status':
+ backend[key] = self.convert_status(backend[key])
+
+ if len(self.charts) > 0:
+ if (name + '_status') not in self.charts['pool_status']:
+ self.add_backend_dimensions(name)
+
+ to_netdata["{0}_{1}".format(name, key)] = backend[key]
+
+ if key == 'bytes_data_recv':
+ to_netdata['bytes_data_recv'] += int(backend[key])
+
+ if key == 'bytes_data_sent':
+ to_netdata['bytes_data_sent'] += int(backend[key])
+
+ if 'commands_status' in raw_data:
+ for record in raw_data['commands_status'][0]:
+ cmd = self.generate_command_stats(record)
+ name = cmd['name']
+
+ if len(self.charts) > 0:
+ if (name + '_count') not in self.charts['commands_count']:
+ self.add_command_dimensions(name)
+ self.add_histogram_chart(cmd)
+
+ to_netdata[name + '_count'] = cmd['count']
+ to_netdata[name + '_duration'] = cmd['duration']
+ for histogram in cmd['histogram']:
+ dimId = 'commands_histogram_{0}_{1}'.format(name, histogram)
+ to_netdata[dimId] = cmd['histogram'][histogram]
+
+ return to_netdata or None
+
+ def add_backend_dimensions(self, name):
+ self.charts['pool_status'].add_dimension([name + '_status', name, 'absolute'])
+ self.charts['pool_net'].add_dimension([name + '_bytes_data_recv', 'from_' + name, 'incremental', 8, 1024])
+ self.charts['pool_net'].add_dimension([name + '_bytes_data_sent', 'to_' + name, 'incremental', -8, 1024])
+ self.charts['pool_queries'].add_dimension([name + '_queries', name, 'incremental'])
+ self.charts['pool_latency'].add_dimension([name + '_latency_us', name, 'absolute', 1, 1000])
+ self.charts['pool_connection_used'].add_dimension([name + '_connused', name, 'absolute'])
+ self.charts['pool_connection_free'].add_dimension([name + '_connfree', name, 'absolute'])
+ self.charts['pool_connection_ok'].add_dimension([name + '_connok', name, 'incremental'])
+ self.charts['pool_connection_error'].add_dimension([name + '_connerr', name, 'incremental'])
+
+ def add_command_dimensions(self, cmd):
+ self.charts['commands_count'].add_dimension([cmd + '_count', cmd, 'incremental'])
+ self.charts['commands_duration'].add_dimension([cmd + '_duration', cmd, 'incremental', 1, 1000])
+
+ def add_histogram_chart(self, cmd):
+ chart = self.charts.add_chart(self.histogram_chart(cmd))
+
+ for histogram in HISTOGRAM_ORDER:
+ dimId = 'commands_histogram_{0}_{1}'.format(cmd['name'], histogram)
+ chart.add_dimension([dimId, histogram, 'incremental'])
+
+ @staticmethod
+ def histogram_chart(cmd):
+ return [
+ 'commands_historgram_' + cmd['name'],
+ None,
+ 'ProxySQL {0} Command Histogram'.format(cmd['name'].title()),
+ 'commands',
+ 'commands_histogram',
+ 'proxysql.commands_histogram_' + cmd['name'],
+ 'stacked'
+ ]
+
+ @staticmethod
+ def generate_backend(data):
+ return {
+ 'hostgroup': data[0],
+ 'srv_host': data[1],
+ 'srv_port': data[2],
+ 'status': data[3],
+ 'connused': data[4],
+ 'connfree': data[5],
+ 'connok': data[6],
+ 'connerr': data[7],
+ 'queries': data[8],
+ 'bytes_data_sent': data[9],
+ 'bytes_data_recv': data[10],
+ 'latency_us': data[11]
+ }
+
+ @staticmethod
+ def generate_command_stats(data):
+ return {
+ 'name': data[0].lower(),
+ 'duration': data[1],
+ 'count': data[2],
+ 'histogram': {
+ '100us': data[3],
+ '500us': data[4],
+ '1ms': data[5],
+ '5ms': data[6],
+ '10ms': data[7],
+ '50ms': data[8],
+ '100ms': data[9],
+ '500ms': data[10],
+ '1s': data[11],
+ '5s': data[12],
+ '10s': data[13],
+ 'inf': data[14]
+ }
+ }
+
+ @staticmethod
+ def generate_backend_name(backend):
+ hostgroup = backend['hostgroup'].replace(' ', '_').lower()
+ host = backend['srv_host'].replace('.', '_')
+
+ return "{0}_{1}_{2}".format(hostgroup, host, backend['srv_port'])
+
+ @staticmethod
+ def convert_status(status):
+ if status in STATUS:
+ return STATUS[status]
+ return -1
diff --git a/collectors/python.d.plugin/proxysql/proxysql.conf b/collectors/python.d.plugin/proxysql/proxysql.conf
new file mode 100644
index 000000000..d29c2e5be
--- /dev/null
+++ b/collectors/python.d.plugin/proxysql/proxysql.conf
@@ -0,0 +1,118 @@
+# netdata python.d.plugin configuration for ProxySQL
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# Additionally to the above, proxysql also supports the following:
+#
+# host: 'IP or HOSTNAME' # the host to connect to
+# port: PORT # the port to connect to
+#
+# in all cases, the following can also be set:
+#
+# user: 'username' # the proxysql username to use
+# pass: 'password' # the proxysql password to use
+#
+
+# AUTO-DETECTION JOBS
+# only one of them will run (they have the same name)
+
+tcp:
+ name : 'local'
+ user : 'stats'
+ pass : 'stats'
+ host : 'localhost'
+ port : '6032'
+
+tcpipv4:
+ name : 'local'
+ user : 'stats'
+ pass : 'stats'
+ host : '127.0.0.1'
+ port : '6032'
+
+tcpipv6:
+ name : 'local'
+ user : 'stats'
+ pass : 'stats'
+ host : '::1'
+ port : '6032'
+
+tcp_admin:
+ name : 'local'
+ user : 'admin'
+ pass : 'admin'
+ host : 'localhost'
+ port : '6032'
+
+tcpipv4_admin:
+ name : 'local'
+ user : 'admin'
+ pass : 'admin'
+ host : '127.0.0.1'
+ port : '6032'
+
+tcpipv6_admin:
+ name : 'local'
+ user : 'admin'
+ pass : 'admin'
+ host : '::1'
+ port : '6032'
diff --git a/collectors/python.d.plugin/puppet/Makefile.inc b/collectors/python.d.plugin/puppet/Makefile.inc
new file mode 100644
index 000000000..fe94b9254
--- /dev/null
+++ b/collectors/python.d.plugin/puppet/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += puppet/puppet.chart.py
+dist_pythonconfig_DATA += puppet/puppet.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += puppet/README.md puppet/Makefile.inc
+
diff --git a/collectors/python.d.plugin/puppet/README.md b/collectors/python.d.plugin/puppet/README.md
new file mode 100644
index 000000000..8304c831e
--- /dev/null
+++ b/collectors/python.d.plugin/puppet/README.md
@@ -0,0 +1,48 @@
+# puppet
+
+Monitor status of Puppet Server and Puppet DB.
+
+Following charts are drawn:
+
+1. **JVM Heap**
+ * committed (allocated from OS)
+ * used (actual use)
+2. **JVM Non-Heap**
+ * committed (allocated from OS)
+ * used (actual use)
+3. **CPU Usage**
+ * execution
+ * GC (taken by garbage collection)
+4. **File Descriptors**
+ * max
+ * used
+
+
+### configuration
+
+```yaml
+puppetdb:
+ url: 'https://fqdn.example.com:8081'
+ tls_cert_file: /path/to/client.crt
+ tls_key_file: /path/to/client.key
+ autodetection_retry: 1
+ retries: 3600
+
+puppetserver:
+ url: 'https://fqdn.example.com:8140'
+ autodetection_retry: 1
+ retries: 3600
+```
+
+When no configuration is given then `https://fqdn.example.com:8140` is
+tried without any retries.
+
+### notes
+
+* Exact Fully Qualified Domain Name of the node should be used.
+* Usually Puppet Server/DB startup time is VERY long. So, there should
+ be quite reasonable retry count.
+* Secure PuppetDB config may require client certificate. Not applies
+ to default PuppetDB configuration though.
+
+---
diff --git a/collectors/python.d.plugin/puppet/puppet.chart.py b/collectors/python.d.plugin/puppet/puppet.chart.py
new file mode 100644
index 000000000..5c8e48bd9
--- /dev/null
+++ b/collectors/python.d.plugin/puppet/puppet.chart.py
@@ -0,0 +1,121 @@
+# -*- coding: utf-8 -*-
+# Description: puppet netdata python.d module
+# Author: Andrey Galkin <andrey@futoin.org> (andvgal)
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This module should work both with OpenSource and PE versions
+# of PuppetServer and PuppetDB.
+#
+# NOTE: PuppetDB may be configured to require proper TLS
+# client certificate for security reasons. Use tls_key_file
+# and tls_cert_file options then.
+#
+
+from bases.FrameworkServices.UrlService import UrlService
+from json import loads
+import socket
+
+update_every = 5
+priority = 60000
+# very long clojure-based service startup time
+retries = 180
+
+MB = 1048576
+CPU_SCALE = 1000
+ORDER = [
+ 'jvm_heap',
+ 'jvm_nonheap',
+ 'cpu',
+ 'fd_open',
+]
+CHARTS = {
+ 'jvm_heap': {
+ 'options': [None, 'JVM Heap', 'MB', 'resources', 'puppet.jvm', 'area'],
+ 'lines': [
+ ['jvm_heap_committed', 'committed', 'absolute', 1, MB],
+ ['jvm_heap_used', 'used', 'absolute', 1, MB],
+ ],
+ 'variables': [
+ ['jvm_heap_max'],
+ ['jvm_heap_init'],
+ ],
+ },
+ 'jvm_nonheap': {
+ 'options': [None, 'JVM Non-Heap', 'MB', 'resources', 'puppet.jvm', 'area'],
+ 'lines': [
+ ['jvm_nonheap_committed', 'committed', 'absolute', 1, MB],
+ ['jvm_nonheap_used', 'used', 'absolute', 1, MB],
+ ],
+ 'variables': [
+ ['jvm_nonheap_max'],
+ ['jvm_nonheap_init'],
+ ],
+ },
+ 'cpu': {
+ 'options': [None, 'CPU usage', 'percentage', 'resources', 'puppet.cpu', 'stacked'],
+ 'lines': [
+ ['cpu_time', 'execution', 'absolute', 1, CPU_SCALE],
+ ['gc_time', 'GC', 'absolute', 1, CPU_SCALE],
+ ]
+ },
+ 'fd_open': {
+ 'options': [None, 'File Descriptors', 'descriptors', 'resources', 'puppet.fdopen', 'line'],
+ 'lines': [
+ ['fd_used', 'used', 'absolute'],
+ ],
+ 'variables': [
+ ['fd_max'],
+ ],
+ },
+}
+
+
+class Service(UrlService):
+ def __init__(self, configuration=None, name=None):
+ UrlService.__init__(self, configuration=configuration, name=name)
+ self.url = 'https://{0}:8140'.format(socket.getfqdn())
+ self.order = ORDER
+ self.definitions = CHARTS
+
+ def _get_data(self):
+ # NOTE: there are several ways to retrieve data
+ # 1. Only PE versions:
+ # https://puppet.com/docs/pe/2018.1/api_status/status_api_metrics_endpoints.html
+ # 2. Inidividual Metrics API (JMX):
+ # https://puppet.com/docs/pe/2018.1/api_status/metrics_api.html
+ # 3. Extended status at debug level:
+ # https://puppet.com/docs/pe/2018.1/api_status/status_api_json_endpoints.html
+ #
+ # For sake of simplicity and efficiency the status one is used..
+
+ raw_data = self._get_raw_data(self.url + '/status/v1/services?level=debug')
+
+ if raw_data is None:
+ return None
+
+ raw_data = loads(raw_data)
+ data = {}
+
+ try:
+ try:
+ jvm_metrics = raw_data['status-service']['status']['experimental']['jvm-metrics']
+ except KeyError:
+ jvm_metrics = raw_data['status-service']['status']['jvm-metrics']
+
+ heap_mem = jvm_metrics['heap-memory']
+ non_heap_mem = jvm_metrics['non-heap-memory']
+
+ for k in ['max', 'committed', 'used', 'init']:
+ data['jvm_heap_'+k] = heap_mem[k]
+ data['jvm_nonheap_'+k] = non_heap_mem[k]
+
+ fd_open = jvm_metrics['file-descriptors']
+ data['fd_max'] = fd_open['max']
+ data['fd_used'] = fd_open['used']
+
+ data['cpu_time'] = int(jvm_metrics['cpu-usage'] * CPU_SCALE)
+ data['gc_time'] = int(jvm_metrics['gc-cpu-usage'] * CPU_SCALE)
+ except KeyError:
+ pass
+
+ return data or None
diff --git a/collectors/python.d.plugin/puppet/puppet.conf b/collectors/python.d.plugin/puppet/puppet.conf
new file mode 100644
index 000000000..991bfabed
--- /dev/null
+++ b/collectors/python.d.plugin/puppet/puppet.conf
@@ -0,0 +1,98 @@
+# netdata python.d.plugin configuration for Puppet Server and Puppet DB
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# These configuration comes from UrlService base:
+# url: # HTTP or HTTPS URL
+# tls_verify: False # Control HTTPS server certificate verification
+# tls_ca_file: # Optional CA (bundle) file to use
+# tls_cert_file: # Optional client certificate file
+# tls_key_file: # Optional client key file
+#
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
+# only one of them will run (they have the same name)
+# puppet:
+# url: 'https://<FQDN>:8140'
+#
+
+#
+# Production configuration should look like below.
+#
+# NOTE: usually Puppet Server/DB startup time is VERY long. So, there should
+# be quite reasonable retry count.
+#
+# NOTE: secure PuppetDB config may require client certificate.
+# Not applies to default PuppetDB configuration though.
+#
+# puppetdb:
+# url: 'https://fqdn.example.com:8081'
+# tls_cert_file: /path/to/client.crt
+# tls_key_file: /path/to/client.key
+# autodetection_retry: 1
+# retries: 3600
+#
+# puppetserver:
+# url: 'https://fqdn.example.com:8140'
+# autodetection_retry: 1
+# retries: 3600
+#
diff --git a/conf.d/python.d.conf b/collectors/python.d.plugin/python.d.conf
index bb57738bb..97f4cb8d5 100644
--- a/conf.d/python.d.conf
+++ b/collectors/python.d.plugin/python.d.conf
@@ -19,11 +19,19 @@ enabled: yes
# If "default_run" = "no" the default for all modules is disabled (no).
# Setting any of these to "yes" will enable it.
+# Enable / Disable explicit garbage collection (full collection run). Default is enabled.
+gc_run: yes
+
+# Garbage collection interval in seconds. Default is 300.
+gc_interval: 300
+
+# apache: yes
+
# apache_cache has been replaced by web_log
apache_cache: no
-# apache: yes
# beanstalk: yes
# bind_rndc: yes
+# boinc: yes
# ceph: yes
chrony: no
# couchdb: yes
@@ -40,40 +48,50 @@ example: no
# exim: yes
# fail2ban: yes
# freeradius: yes
+go_expvar: no
# gunicorn_log has been replaced by web_log
gunicorn_log: no
-go_expvar: no
# haproxy: yes
# hddtemp: yes
# icecast: yes
# ipfs: yes
# isc_dhcpd: yes
+# linux_power_supply: yes
+# litespeed: yes
+logind: no
# mdstat: yes
# memcached: yes
# mongodb: yes
+# monit: yes
# mysql: yes
# nginx: yes
# nginx_plus: yes
-# nsd: yes
-# ntpd: yes
# nginx_log has been replaced by web_log
nginx_log: no
+# nsd: yes
# ntpd: yes
# ovpn_status_log: yes
# phpfpm: yes
# postfix: yes
# postgres: yes
# powerdns: yes
+# proxysql: yes
+# puppet: yes
# rabbitmq: yes
# redis: yes
+# rethinkdbs: yes
# retroshare: yes
-# sensors: yes
# samba: yes
+# sensors: yes
# smartd_log: yes
-# squid: yes
+# spigotmc: yes
# springboot: yes
+# squid: yes
# tomcat: yes
+unbound: no
+# uwsgi: yes
# varnish: yes
+# w1sensor: yes
# web_log: yes
diff --git a/plugins.d/python.d.plugin b/collectors/python.d.plugin/python.d.plugin
index c9b260164..264c3383d 100755..100644
--- a/plugins.d/python.d.plugin
+++ b/collectors/python.d.plugin/python.d.plugin
@@ -6,7 +6,9 @@ echo "ERROR python IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@" # '''
# Description:
# Author: Pawel Krupa (paulfantom)
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
+import gc
import os
import sys
import threading
@@ -15,22 +17,30 @@ from re import sub
from sys import version_info, argv
from time import sleep
-try:
- from time import monotonic as time
-except ImportError:
- from time import time
+GC_RUN = True
+GC_COLLECT_EVERY = 300
PY_VERSION = version_info[:2]
-PLUGIN_CONFIG_DIR = os.getenv('NETDATA_CONFIG_DIR', os.path.dirname(__file__) + '/../../../../etc/netdata') + '/'
-CHARTS_PY_DIR = os.path.abspath(os.getenv('NETDATA_PLUGINS_DIR', os.path.dirname(__file__)) + '/../python.d') + '/'
-CHARTS_PY_CONFIG_DIR = PLUGIN_CONFIG_DIR + 'python.d/'
-PYTHON_MODULES_DIR = CHARTS_PY_DIR + 'python_modules'
+
+USER_CONFIG_DIR = os.getenv('NETDATA_USER_CONFIG_DIR', '/usr/local/etc/netdata')
+STOCK_CONFIG_DIR = os.getenv('NETDATA_STOCK_CONFIG_DIR', '/usr/local/lib/netdata/conf.d')
+
+PLUGINS_USER_CONFIG_DIR = os.path.join(USER_CONFIG_DIR, 'python.d')
+PLUGINS_STOCK_CONFIG_DIR = os.path.join(STOCK_CONFIG_DIR, 'python.d')
+
+
+PLUGINS_DIR = os.path.abspath(os.getenv(
+ 'NETDATA_PLUGINS_DIR',
+ os.path.dirname(__file__)) + '/../python.d')
+
+
+PYTHON_MODULES_DIR = os.path.join(PLUGINS_DIR, 'python_modules')
sys.path.append(PYTHON_MODULES_DIR)
-from bases.loaders import ModuleAndConfigLoader
-from bases.loggers import PythonDLogger
-from bases.collection import setdefault_values, run_and_exit
+from bases.loaders import ModuleAndConfigLoader # noqa: E402
+from bases.loggers import PythonDLogger # noqa: E402
+from bases.collection import setdefault_values, run_and_exit # noqa: E402
try:
from collections import OrderedDict
@@ -53,7 +63,7 @@ def module_ok(m):
return m.endswith(MODULE_EXTENSION) and m[:-len(MODULE_EXTENSION)] not in OBSOLETE_MODULES
-ALL_MODULES = [m for m in sorted(os.listdir(CHARTS_PY_DIR)) if module_ok(m)]
+ALL_MODULES = [m for m in sorted(os.listdir(PLUGINS_DIR)) if module_ok(m)]
def parse_cmd():
@@ -68,6 +78,13 @@ def multi_job_check(config):
return next((True for key in config if isinstance(config[key], dict)), False)
+class RawModule:
+ def __init__(self, name, path, explicitly_enabled=True):
+ self.name = name
+ self.path = path
+ self.explicitly_enabled = explicitly_enabled
+
+
class Job(object):
def __init__(self, initialized_job, job_id):
"""
@@ -80,7 +97,7 @@ class Job(object):
self.recheck_every = self.job.configuration.pop('autodetection_retry')
self.checked = False # used in Plugin.check_job()
self.created = False # used in Plugin.create_job_charts()
- if OVERRIDE_UPDATE_EVERY:
+ if self.job.update_every < int(OVERRIDE_UPDATE_EVERY):
self.job.update_every = int(OVERRIDE_UPDATE_EVERY)
def __getattr__(self, item):
@@ -194,9 +211,22 @@ class Plugin(object):
self.modules = OrderedDict()
self.sleep_time = 1
self.runs_counter = 0
- self.config, error = self.loader.load_config_from_file(PLUGIN_CONFIG_DIR + 'python.d.conf')
+
+ user_config = os.path.join(USER_CONFIG_DIR, 'python.d.conf')
+ stock_config = os.path.join(STOCK_CONFIG_DIR, 'python.d.conf')
+
+ Logger.debug("loading '{0}'".format(user_config))
+ self.config, error = self.loader.load_config_from_file(user_config)
+
+ if error:
+ Logger.error("cannot load '{0}': {1}. Will try stock version.".format(user_config, error))
+ Logger.debug("loading '{0}'".format(stock_config))
+ self.config, error = self.loader.load_config_from_file(stock_config)
if error:
- Logger.error('"python.d.conf" configuration file not found. Using defaults.')
+ Logger.error("cannot load '{0}': {1}".format(stock_config, error))
+
+ self.do_gc = self.config.get("gc_run", GC_RUN)
+ self.gc_interval = self.config.get("gc_interval", GC_COLLECT_EVERY)
if not self.config.get('enabled', True):
run_and_exit(Logger.info)('DISABLED in configuration file.')
@@ -223,47 +253,57 @@ class Plugin(object):
def enabled_modules(self):
for mod in MODULES_TO_RUN:
mod_name = mod[:-len(MODULE_EXTENSION)]
- mod_path = CHARTS_PY_DIR + mod
- conf_path = ''.join([CHARTS_PY_CONFIG_DIR, mod_name, '.conf'])
-
- if DEBUG:
- yield mod, mod_name, mod_path, conf_path
- else:
- if all([self.config.get('default_run', True),
- self.config.get(mod_name, True)]):
- yield mod, mod_name, mod_path, conf_path
-
- elif all([not self.config.get('default_run'),
- self.config.get(mod_name)]):
- yield mod, mod_name, mod_path, conf_path
+ mod_path = os.path.join(PLUGINS_DIR, mod)
+ if any(
+ [
+ self.config.get('default_run', True) and self.config.get(mod_name, True),
+ (not self.config.get('default_run')) and self.config.get(mod_name),
+ ]
+ ):
+ yield RawModule(
+ name=mod_name,
+ path=mod_path,
+ explicitly_enabled=self.config.get(mod_name),
+ )
def load_and_initialize_modules(self):
- for mod, mod_name, mod_path, conf_path in self.enabled_modules():
+ for mod in self.enabled_modules():
# Load module from file ------------------------------------------------------------
- loaded_module, error = self.loader.load_module_from_file(mod_name, mod_path)
+ loaded_module, error = self.loader.load_module_from_file(mod.name, mod.path)
log = Logger.error if error else Logger.debug
log("module load source: '{module_name}' => [{status}]".format(status='FAILED' if error else 'OK',
- module_name=mod_name))
+ module_name=mod.name))
if error:
Logger.error("load source error : {0}".format(error))
continue
# Load module config from file ------------------------------------------------------
- loaded_config, error = self.loader.load_config_from_file(conf_path)
- log = Logger.error if error else Logger.debug
- log("module load config: '{module_name}' => [{status}]".format(status='FAILED' if error else 'OK',
- module_name=mod_name))
+ user_config = os.path.join(PLUGINS_USER_CONFIG_DIR, mod.name + '.conf')
+ stock_config = os.path.join(PLUGINS_STOCK_CONFIG_DIR, mod.name + '.conf')
+
+ Logger.debug("loading '{0}'".format(user_config))
+ loaded_config, error = self.loader.load_config_from_file(user_config)
if error:
- Logger.error('load config error : {0}'.format(error))
+ Logger.error("cannot load '{0}' : {1}. Will try stock version.".format(user_config, error))
+ Logger.debug("loading '{0}'".format(stock_config))
+ loaded_config, error = self.loader.load_config_from_file(stock_config)
+
+ if error:
+ Logger.error("cannot load '{0}': {1}".format(stock_config, error))
+
+ # Skip disabled modules
+ if getattr(loaded_module, 'disabled_by_default', False) and not mod.explicitly_enabled:
+ Logger.info("module '{0}' disabled by default".format(loaded_module.__name__))
+ continue
+
+ # Module initialization ---------------------------------------------------
- # Service instance initialization ---------------------------------------------------
initialized_module = Module(service=loaded_module, config=loaded_config)
Logger.debug("module status: '{module_name}' => [{status}] "
"(jobs: {jobs_number})".format(status='OK' if initialized_module else 'FAILED',
module_name=initialized_module.name,
jobs_number=len(initialized_module)))
-
if initialized_module:
self.modules[initialized_module.name] = initialized_module
@@ -349,6 +389,11 @@ class Plugin(object):
self.cleanup()
self.autodetect_retry()
+ # FIXME: https://github.com/netdata/netdata/issues/3817
+ if self.do_gc and self.runs_counter % self.gc_interval == 0:
+ v = gc.collect()
+ Logger.debug("GC full collection run result: {0}".format(v))
+
def cleanup(self):
for job in self.dead_jobs:
self.delete_job(job)
diff --git a/collectors/python.d.plugin/python.d.plugin.in b/collectors/python.d.plugin/python.d.plugin.in
new file mode 100755
index 000000000..7ac03fd99
--- /dev/null
+++ b/collectors/python.d.plugin/python.d.plugin.in
@@ -0,0 +1,427 @@
+#!/usr/bin/env bash
+'''':; exec "$(command -v python || command -v python3 || command -v python2 ||
+echo "ERROR python IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@" # '''
+
+# -*- coding: utf-8 -*-
+# Description:
+# Author: Pawel Krupa (paulfantom)
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import gc
+import os
+import sys
+import threading
+
+from re import sub
+from sys import version_info, argv
+from time import sleep
+
+GC_RUN = True
+GC_COLLECT_EVERY = 300
+
+PY_VERSION = version_info[:2]
+
+USER_CONFIG_DIR = os.getenv('NETDATA_USER_CONFIG_DIR', '@configdir_POST@')
+STOCK_CONFIG_DIR = os.getenv('NETDATA_STOCK_CONFIG_DIR', '@libconfigdir_POST@')
+
+PLUGINS_USER_CONFIG_DIR = os.path.join(USER_CONFIG_DIR, 'python.d')
+PLUGINS_STOCK_CONFIG_DIR = os.path.join(STOCK_CONFIG_DIR, 'python.d')
+
+
+PLUGINS_DIR = os.path.abspath(os.getenv(
+ 'NETDATA_PLUGINS_DIR',
+ os.path.dirname(__file__)) + '/../python.d')
+
+
+PYTHON_MODULES_DIR = os.path.join(PLUGINS_DIR, 'python_modules')
+
+sys.path.append(PYTHON_MODULES_DIR)
+
+from bases.loaders import ModuleAndConfigLoader # noqa: E402
+from bases.loggers import PythonDLogger # noqa: E402
+from bases.collection import setdefault_values, run_and_exit # noqa: E402
+
+try:
+ from collections import OrderedDict
+except ImportError:
+ from third_party.ordereddict import OrderedDict
+
+BASE_CONFIG = {'update_every': os.getenv('NETDATA_UPDATE_EVERY', 1),
+ 'retries': 60,
+ 'priority': 60000,
+ 'autodetection_retry': 0,
+ 'chart_cleanup': 10,
+ 'name': str()}
+
+
+MODULE_EXTENSION = '.chart.py'
+OBSOLETE_MODULES = ['apache_cache', 'gunicorn_log', 'nginx_log']
+
+
+def module_ok(m):
+ return m.endswith(MODULE_EXTENSION) and m[:-len(MODULE_EXTENSION)] not in OBSOLETE_MODULES
+
+
+ALL_MODULES = [m for m in sorted(os.listdir(PLUGINS_DIR)) if module_ok(m)]
+
+
+def parse_cmd():
+ debug = 'debug' in argv[1:]
+ trace = 'trace' in argv[1:]
+ override_update_every = next((arg for arg in argv[1:] if arg.isdigit() and int(arg) > 1), False)
+ modules = [''.join([m, MODULE_EXTENSION]) for m in argv[1:] if ''.join([m, MODULE_EXTENSION]) in ALL_MODULES]
+ return debug, trace, override_update_every, modules or ALL_MODULES
+
+
+def multi_job_check(config):
+ return next((True for key in config if isinstance(config[key], dict)), False)
+
+
+class RawModule:
+ def __init__(self, name, path, explicitly_enabled=True):
+ self.name = name
+ self.path = path
+ self.explicitly_enabled = explicitly_enabled
+
+
+class Job(object):
+ def __init__(self, initialized_job, job_id):
+ """
+ :param initialized_job: instance of <Class Service>
+ :param job_id: <str>
+ """
+ self.job = initialized_job
+ self.id = job_id # key in Modules.jobs()
+ self.module_name = self.job.__module__ # used in Plugin.delete_job()
+ self.recheck_every = self.job.configuration.pop('autodetection_retry')
+ self.checked = False # used in Plugin.check_job()
+ self.created = False # used in Plugin.create_job_charts()
+ if self.job.update_every < int(OVERRIDE_UPDATE_EVERY):
+ self.job.update_every = int(OVERRIDE_UPDATE_EVERY)
+
+ def __getattr__(self, item):
+ return getattr(self.job, item)
+
+ def __repr__(self):
+ return self.job.__repr__()
+
+ def is_dead(self):
+ return bool(self.ident) and not self.is_alive()
+
+ def not_launched(self):
+ return not bool(self.ident)
+
+ def is_autodetect(self):
+ return self.recheck_every
+
+
+class Module(object):
+ def __init__(self, service, config):
+ """
+ :param service: <Module>
+ :param config: <dict>
+ """
+ self.service = service
+ self.name = service.__name__
+ self.config = self.jobs_configurations_builder(config)
+ self.jobs = OrderedDict()
+ self.counter = 1
+
+ self.initialize_jobs()
+
+ def __repr__(self):
+ return "<Class Module '{name}'>".format(name=self.name)
+
+ def __iter__(self):
+ return iter(OrderedDict(self.jobs).values())
+
+ def __getitem__(self, item):
+ return self.jobs[item]
+
+ def __delitem__(self, key):
+ del self.jobs[key]
+
+ def __len__(self):
+ return len(self.jobs)
+
+ def __bool__(self):
+ return bool(self.jobs)
+
+ def __nonzero__(self):
+ return self.__bool__()
+
+ def jobs_configurations_builder(self, config):
+ """
+ :param config: <dict>
+ :return:
+ """
+ counter = 0
+ job_base_config = dict()
+
+ for attr in BASE_CONFIG:
+ job_base_config[attr] = config.pop(attr, getattr(self.service, attr, BASE_CONFIG[attr]))
+
+ if not config:
+ config = {str(): dict()}
+ elif not multi_job_check(config):
+ config = {str(): config}
+
+ for job_name in config:
+ if not isinstance(config[job_name], dict):
+ continue
+
+ job_config = setdefault_values(config[job_name], base_dict=job_base_config)
+ job_name = sub(r'\s+', '_', job_name)
+ config[job_name]['name'] = sub(r'\s+', '_', config[job_name]['name'])
+ counter += 1
+ job_id = 'job' + str(counter).zfill(3)
+
+ yield job_id, job_name, job_config
+
+ def initialize_jobs(self):
+ """
+ :return:
+ """
+ for job_id, job_name, job_config in self.config:
+ job_config['job_name'] = job_name
+ job_config['override_name'] = job_config.pop('name')
+
+ try:
+ initialized_job = self.service.Service(configuration=job_config)
+ except Exception as error:
+ Logger.error("job initialization: '{module_name} {job_name}' "
+ "=> ['FAILED'] ({error})".format(module_name=self.name,
+ job_name=job_name,
+ error=error))
+ continue
+ else:
+ Logger.debug("job initialization: '{module_name} {job_name}' "
+ "=> ['OK']".format(module_name=self.name,
+ job_name=job_name or self.name))
+ self.jobs[job_id] = Job(initialized_job=initialized_job,
+ job_id=job_id)
+ del self.config
+ del self.service
+
+
+class Plugin(object):
+ def __init__(self):
+ self.loader = ModuleAndConfigLoader()
+ self.modules = OrderedDict()
+ self.sleep_time = 1
+ self.runs_counter = 0
+
+ user_config = os.path.join(USER_CONFIG_DIR, 'python.d.conf')
+ stock_config = os.path.join(STOCK_CONFIG_DIR, 'python.d.conf')
+
+ Logger.debug("loading '{0}'".format(user_config))
+ self.config, error = self.loader.load_config_from_file(user_config)
+
+ if error:
+ Logger.error("cannot load '{0}': {1}. Will try stock version.".format(user_config, error))
+ Logger.debug("loading '{0}'".format(stock_config))
+ self.config, error = self.loader.load_config_from_file(stock_config)
+ if error:
+ Logger.error("cannot load '{0}': {1}".format(stock_config, error))
+
+ self.do_gc = self.config.get("gc_run", GC_RUN)
+ self.gc_interval = self.config.get("gc_interval", GC_COLLECT_EVERY)
+
+ if not self.config.get('enabled', True):
+ run_and_exit(Logger.info)('DISABLED in configuration file.')
+
+ self.load_and_initialize_modules()
+ if not self.modules:
+ run_and_exit(Logger.info)('No modules to run. Exit...')
+
+ def __iter__(self):
+ return iter(OrderedDict(self.modules).values())
+
+ @property
+ def jobs(self):
+ return (job for mod in self for job in mod)
+
+ @property
+ def dead_jobs(self):
+ return (job for job in self.jobs if job.is_dead())
+
+ @property
+ def autodetect_jobs(self):
+ return [job for job in self.jobs if job.not_launched()]
+
+ def enabled_modules(self):
+ for mod in MODULES_TO_RUN:
+ mod_name = mod[:-len(MODULE_EXTENSION)]
+ mod_path = os.path.join(PLUGINS_DIR, mod)
+ if any(
+ [
+ self.config.get('default_run', True) and self.config.get(mod_name, True),
+ (not self.config.get('default_run')) and self.config.get(mod_name),
+ ]
+ ):
+ yield RawModule(
+ name=mod_name,
+ path=mod_path,
+ explicitly_enabled=self.config.get(mod_name),
+ )
+
+ def load_and_initialize_modules(self):
+ for mod in self.enabled_modules():
+
+ # Load module from file ------------------------------------------------------------
+ loaded_module, error = self.loader.load_module_from_file(mod.name, mod.path)
+ log = Logger.error if error else Logger.debug
+ log("module load source: '{module_name}' => [{status}]".format(status='FAILED' if error else 'OK',
+ module_name=mod.name))
+ if error:
+ Logger.error("load source error : {0}".format(error))
+ continue
+
+ # Load module config from file ------------------------------------------------------
+ user_config = os.path.join(PLUGINS_USER_CONFIG_DIR, mod.name + '.conf')
+ stock_config = os.path.join(PLUGINS_STOCK_CONFIG_DIR, mod.name + '.conf')
+
+ Logger.debug("loading '{0}'".format(user_config))
+ loaded_config, error = self.loader.load_config_from_file(user_config)
+ if error:
+ Logger.error("cannot load '{0}' : {1}. Will try stock version.".format(user_config, error))
+ Logger.debug("loading '{0}'".format(stock_config))
+ loaded_config, error = self.loader.load_config_from_file(stock_config)
+
+ if error:
+ Logger.error("cannot load '{0}': {1}".format(stock_config, error))
+
+ # Skip disabled modules
+ if getattr(loaded_module, 'disabled_by_default', False) and not mod.explicitly_enabled:
+ Logger.info("module '{0}' disabled by default".format(loaded_module.__name__))
+ continue
+
+ # Module initialization ---------------------------------------------------
+
+ initialized_module = Module(service=loaded_module, config=loaded_config)
+ Logger.debug("module status: '{module_name}' => [{status}] "
+ "(jobs: {jobs_number})".format(status='OK' if initialized_module else 'FAILED',
+ module_name=initialized_module.name,
+ jobs_number=len(initialized_module)))
+ if initialized_module:
+ self.modules[initialized_module.name] = initialized_module
+
+ @staticmethod
+ def check_job(job):
+ """
+ :param job: <Job>
+ :return:
+ """
+ try:
+ check_ok = bool(job.check())
+ except Exception as error:
+ job.error('check() unhandled exception: {error}'.format(error=error))
+ return None
+ else:
+ return check_ok
+
+ @staticmethod
+ def create_job_charts(job):
+ """
+ :param job: <Job>
+ :return:
+ """
+ try:
+ create_ok = job.create()
+ except Exception as error:
+ job.error('create() unhandled exception: {error}'.format(error=error))
+ return False
+ else:
+ return create_ok
+
+ def delete_job(self, job):
+ """
+ :param job: <Job>
+ :return:
+ """
+ del self.modules[job.module_name][job.id]
+
+ def run_check(self):
+ checked = list()
+ for job in self.jobs:
+ if job.name in checked:
+ job.info('check() => [DROPPED] (already served by another job)')
+ self.delete_job(job)
+ continue
+ ok = self.check_job(job)
+ if ok:
+ job.info('check() => [OK]')
+ checked.append(job.name)
+ job.checked = True
+ continue
+ if not job.is_autodetect() or ok is None:
+ job.info('check() => [FAILED]')
+ self.delete_job(job)
+ else:
+ job.info('check() => [RECHECK] (autodetection_retry: {0})'.format(job.recheck_every))
+
+ def run_create(self):
+ for job in self.jobs:
+ if not job.checked:
+ # skip autodetection_retry jobs
+ continue
+ ok = self.create_job_charts(job)
+ if ok:
+ job.debug('create() => [OK] (charts: {0})'.format(len(job.charts)))
+ job.created = True
+ continue
+ job.error('create() => [FAILED] (charts: {0})'.format(len(job.charts)))
+ self.delete_job(job)
+
+ def start(self):
+ self.run_check()
+ self.run_create()
+ for job in self.jobs:
+ if job.created:
+ job.start()
+
+ while True:
+ if threading.active_count() <= 1 and not self.autodetect_jobs:
+ run_and_exit(Logger.info)('FINISHED')
+
+ sleep(self.sleep_time)
+ self.cleanup()
+ self.autodetect_retry()
+
+ # FIXME: https://github.com/netdata/netdata/issues/3817
+ if self.do_gc and self.runs_counter % self.gc_interval == 0:
+ v = gc.collect()
+ Logger.debug("GC full collection run result: {0}".format(v))
+
+ def cleanup(self):
+ for job in self.dead_jobs:
+ self.delete_job(job)
+ for mod in self:
+ if not mod:
+ del self.modules[mod.name]
+
+ def autodetect_retry(self):
+ self.runs_counter += self.sleep_time
+ for job in self.autodetect_jobs:
+ if self.runs_counter % job.recheck_every == 0:
+ checked = self.check_job(job)
+ if checked:
+ created = self.create_job_charts(job)
+ if not created:
+ self.delete_job(job)
+ continue
+ job.start()
+
+
+if __name__ == '__main__':
+ DEBUG, TRACE, OVERRIDE_UPDATE_EVERY, MODULES_TO_RUN = parse_cmd()
+ Logger = PythonDLogger()
+ if DEBUG:
+ Logger.logger.severity = 'DEBUG'
+ if TRACE:
+ Logger.log_traceback = True
+ Logger.info('Using python {version}'.format(version=PY_VERSION[0]))
+
+ plugin = Plugin()
+ plugin.start()
diff --git a/python.d/python_modules/third_party/__init__.py b/collectors/python.d.plugin/python_modules/__init__.py
index e69de29bb..e69de29bb 100644
--- a/python.d/python_modules/third_party/__init__.py
+++ b/collectors/python.d.plugin/python_modules/__init__.py
diff --git a/python.d/python_modules/bases/FrameworkServices/ExecutableService.py b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/ExecutableService.py
index a71f2bfd2..72f9ff714 100644
--- a/python.d/python_modules/bases/FrameworkServices/ExecutableService.py
+++ b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/ExecutableService.py
@@ -2,6 +2,7 @@
# Description:
# Author: Pawel Krupa (paulfantom)
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
import os
@@ -16,15 +17,15 @@ class ExecutableService(SimpleService):
SimpleService.__init__(self, configuration=configuration, name=name)
self.command = None
- def _get_raw_data(self, stderr=False):
+ def _get_raw_data(self, stderr=False, command=None):
"""
Get raw data from executed command
:return: <list>
"""
try:
- p = Popen(self.command, stdout=PIPE, stderr=PIPE)
+ p = Popen(command if command else self.command, stdout=PIPE, stderr=PIPE)
except Exception as error:
- self.error('Executing command {command} resulted in error: {error}'.format(command=self.command,
+ self.error('Executing command {command} resulted in error: {error}'.format(command=command or self.command,
error=error))
return None
data = list()
@@ -35,7 +36,7 @@ class ExecutableService(SimpleService):
except TypeError:
continue
- return data or None
+ return data
def check(self):
"""
diff --git a/python.d/python_modules/bases/FrameworkServices/LogService.py b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/LogService.py
index 45daa2446..5acfd73f8 100644
--- a/python.d/python_modules/bases/FrameworkServices/LogService.py
+++ b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/LogService.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
# Description:
# Author: Pawel Krupa (paulfantom)
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
from glob import glob
import os
diff --git a/python.d/python_modules/bases/FrameworkServices/MySQLService.py b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/MySQLService.py
index 3acc5b109..53807e2c4 100644
--- a/python.d/python_modules/bases/FrameworkServices/MySQLService.py
+++ b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/MySQLService.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description:
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
from sys import exc_info
diff --git a/python.d/python_modules/bases/FrameworkServices/SimpleService.py b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/SimpleService.py
index 177332c1f..dd53fbc14 100644
--- a/python.d/python_modules/bases/FrameworkServices/SimpleService.py
+++ b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/SimpleService.py
@@ -2,13 +2,12 @@
# Description:
# Author: Pawel Krupa (paulfantom)
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
from threading import Thread
+from time import sleep
-try:
- from time import sleep, monotonic as time
-except ImportError:
- from time import sleep, time
+from third_party.monotonic import monotonic
from bases.charts import Charts, ChartError, create_runtime_chart
from bases.collection import OldVersionCompatibility, safe_print
@@ -168,7 +167,7 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
'retries: {retries}'.format(freq=job.FREQ, retries=job.RETRIES_MAX - job.RETRIES))
while True:
- job.START_RUN = time()
+ job.START_RUN = monotonic()
job.NEXT_RUN = job.START_RUN - (job.START_RUN % job.FREQ) + job.FREQ + job.PENALTY
@@ -189,7 +188,7 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
if not self.manage_retries():
return
else:
- job.ELAPSED = int((time() - job.START_RUN) * 1e3)
+ job.ELAPSED = int((monotonic() - job.START_RUN) * 1e3)
job.PREV_UPDATE = job.START_RUN
job.RETRIES, job.PENALTY = 0, 0
safe_print(RUNTIME_CHART_UPDATE.format(job_name=self.name,
@@ -253,7 +252,7 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
self.debug('sleeping for {sleep_time} to reach frequency of {freq} sec'.format(sleep_time=sleep_time,
freq=job.FREQ + job.PENALTY))
sleep(sleep_time)
- job.START_RUN = time()
+ job.START_RUN = monotonic()
def get_data(self):
return self._get_data()
diff --git a/python.d/python_modules/bases/FrameworkServices/SocketService.py b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/SocketService.py
index 8d27ae660..e85455307 100644
--- a/python.d/python_modules/bases/FrameworkServices/SocketService.py
+++ b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/SocketService.py
@@ -1,9 +1,18 @@
# -*- coding: utf-8 -*-
# Description:
# Author: Pawel Krupa (paulfantom)
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
import socket
+try:
+ import ssl
+except ImportError:
+ _TLS_SUPPORT = False
+else:
+ _TLS_SUPPORT = True
+
from bases.FrameworkServices.SimpleService import SimpleService
@@ -16,6 +25,9 @@ class SocketService(SimpleService):
self.unix_socket = None
self.dgram_socket = False
self.request = ''
+ self.tls = False
+ self.cert = None
+ self.key = None
self.__socket_config = None
self.__empty_request = "".encode()
SimpleService.__init__(self, configuration=configuration, name=name)
@@ -26,7 +38,7 @@ class SocketService(SimpleService):
message=message))
else:
if self.__socket_config is not None:
- af, sock_type, proto, canon_name, sa = self.__socket_config
+ _, _, _, _, sa = self.__socket_config
self.error('socket to "{address}" port {port}: {message}'.format(address=sa[0],
port=sa[1],
message=message))
@@ -44,7 +56,7 @@ class SocketService(SimpleService):
self.error("Cannot create socket to 'None':")
return False
- af, sock_type, proto, canon_name, sa = res
+ af, sock_type, proto, _, sa = res
try:
self.debug('Creating socket to "{address}", port {port}'.format(address=sa[0], port=sa[1]))
self._sock = socket.socket(af, sock_type, proto)
@@ -56,10 +68,24 @@ class SocketService(SimpleService):
self.__socket_config = None
return False
+ if self.tls:
+ try:
+ self.debug('Encapsulating socket with TLS')
+ self._sock = ssl.wrap_socket(self._sock,
+ keyfile=self.key,
+ certfile=self.cert,
+ server_side=False,
+ cert_reqs=ssl.CERT_NONE)
+ except (socket.error, ssl.SSLError) as error:
+ self.error('Failed to wrap socket.')
+ self._disconnect()
+ self.__socket_config = None
+ return False
+
try:
self.debug('connecting socket to "{address}", port {port}'.format(address=sa[0], port=sa[1]))
self._sock.connect(sa)
- except socket.error as error:
+ except (socket.error, ssl.SSLError) as error:
self.error('Failed to connect to "{address}", port {port}, error: {error}'.format(address=sa[0],
port=sa[1],
error=error))
@@ -147,7 +173,7 @@ class SocketService(SimpleService):
pass
self._sock = None
- def _send(self):
+ def _send(self, request=None):
"""
Send request.
:return: boolean
@@ -155,8 +181,8 @@ class SocketService(SimpleService):
# Send request if it is needed
if self.request != self.__empty_request:
try:
- self.debug('sending request: {0}'.format(self.request))
- self._sock.send(self.request)
+ self.debug('sending request: {0}'.format(request or self.request))
+ self._sock.send(request or self.request)
except Exception as error:
self._socket_error('error sending request: {0}'.format(error))
self._disconnect()
@@ -197,7 +223,7 @@ class SocketService(SimpleService):
self.debug('final response: {0}'.format(data))
return data
- def _get_raw_data(self, raw=False):
+ def _get_raw_data(self, raw=False, request=None):
"""
Get raw data with low-level "socket" module.
:param raw: set `True` to return bytes
@@ -211,7 +237,7 @@ class SocketService(SimpleService):
return None
# Send request if it is needed
- if not self._send():
+ if not self._send(request):
return None
data = self._receive(raw)
@@ -249,6 +275,28 @@ class SocketService(SimpleService):
except (KeyError, TypeError):
self.debug('No port specified. Using: "{0}"'.format(self.port))
+ self.tls = bool(self.configuration.get('tls', self.tls))
+ if self.tls and not _TLS_SUPPORT:
+ self.warning('TLS requested but no TLS module found, disabling TLS support.')
+ self.tls = False
+ if _TLS_SUPPORT and not self.tls:
+ self.debug('No TLS preference specified, not using TLS.')
+
+ if self.tls and _TLS_SUPPORT:
+ self.key = self.configuration.get('tls_key_file')
+ self.cert = self.configuration.get('tls_cert_file')
+ if not self.cert:
+ # If there's not a valid certificate, clear the key too.
+ self.debug('No valid TLS client certificate configuration found.')
+ self.key = None
+ self.cert = None
+ elif not self.key:
+ # If a key isn't listed, the config may still be
+ # valid, because there may be a key attached to the
+ # certificate.
+ self.info('No TLS client key specified, assuming it\'s attached to the certificate.')
+ self.key = None
+
try:
self.request = str(self.configuration['request'])
except (KeyError, TypeError):
diff --git a/python.d/python_modules/bases/FrameworkServices/UrlService.py b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/UrlService.py
index bb340ba3b..856f38851 100644
--- a/python.d/python_modules/bases/FrameworkServices/UrlService.py
+++ b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/UrlService.py
@@ -2,6 +2,7 @@
# Description:
# Author: Pawel Krupa (paulfantom)
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
import urllib3
@@ -22,8 +23,13 @@ class UrlService(SimpleService):
self.proxy_user = self.configuration.get('proxy_user')
self.proxy_password = self.configuration.get('proxy_pass')
self.proxy_url = self.configuration.get('proxy_url')
+ self.method = self.configuration.get('method', 'GET')
self.header = self.configuration.get('header')
self.request_timeout = self.configuration.get('timeout', 1)
+ self.tls_verify = self.configuration.get('tls_verify')
+ self.tls_ca_file = self.configuration.get('tls_ca_file')
+ self.tls_key_file = self.configuration.get('tls_key_file')
+ self.tls_cert_file = self.configuration.get('tls_cert_file')
self._manager = None
def __make_headers(self, **header_kw):
@@ -60,9 +66,21 @@ class UrlService(SimpleService):
else:
manager = urllib3.PoolManager
params = dict(headers=header)
+ tls_cert_file = self.tls_cert_file
+ if tls_cert_file:
+ params['cert_file'] = tls_cert_file
+ # NOTE: key_file is useless without cert_file, but
+ # cert_file may include the key as well.
+ tls_key_file = self.tls_key_file
+ if tls_key_file:
+ params['key_file'] = tls_key_file
+ tls_ca_file = self.tls_ca_file
+ if tls_ca_file:
+ params['ca_certs'] = tls_ca_file
try:
url = header_kw.get('url') or self.url
- if url.startswith('https'):
+ if url.startswith('https') and not self.tls_verify and not tls_ca_file:
+ params['ca_certs'] = None
return manager(assert_hostname=False, cert_reqs='CERT_NONE', **params)
return manager(**params)
except (urllib3.exceptions.ProxySchemeUnknown, TypeError) as error:
@@ -77,13 +95,13 @@ class UrlService(SimpleService):
try:
status, data = self._get_raw_data_with_status(url, manager)
except (urllib3.exceptions.HTTPError, TypeError, AttributeError) as error:
- self.error('Url: {url}. Error: {error}'.format(url=url, error=error))
+ self.error('Url: {url}. Error: {error}'.format(url=url or self.url, error=error))
return None
if status == 200:
- return data.decode()
+ return data
else:
- self.debug('Url: {url}. Http response status code: {code}'.format(url=url, code=status))
+ self.debug('Url: {url}. Http response status code: {code}'.format(url=url or self.url, code=status))
return None
def _get_raw_data_with_status(self, url=None, manager=None, retries=1, redirect=True):
@@ -93,13 +111,15 @@ class UrlService(SimpleService):
"""
url = url or self.url
manager = manager or self._manager
- response = manager.request(method='GET',
+ response = manager.request(method=self.method,
url=url,
timeout=self.request_timeout,
retries=retries,
headers=manager.headers,
redirect=redirect)
- return response.status, response.data
+ if isinstance(response.data, str):
+ return response.status, response.data
+ return response.status, response.data.decode()
def check(self):
"""
diff --git a/python.d/python_modules/urllib3/contrib/__init__.py b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/__init__.py
index e69de29bb..e69de29bb 100644
--- a/python.d/python_modules/urllib3/contrib/__init__.py
+++ b/collectors/python.d.plugin/python_modules/bases/FrameworkServices/__init__.py
diff --git a/python.d/python_modules/urllib3/contrib/_securetransport/__init__.py b/collectors/python.d.plugin/python_modules/bases/__init__.py
index e69de29bb..e69de29bb 100644
--- a/python.d/python_modules/urllib3/contrib/_securetransport/__init__.py
+++ b/collectors/python.d.plugin/python_modules/bases/__init__.py
diff --git a/python.d/python_modules/bases/charts.py b/collectors/python.d.plugin/python_modules/bases/charts.py
index 5394fbf64..2963739ec 100644
--- a/python.d/python_modules/bases/charts.py
+++ b/collectors/python.d.plugin/python_modules/bases/charts.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
# Description:
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.collection import safe_print
-CHART_PARAMS = ['type', 'id', 'name', 'title', 'units', 'family', 'context', 'chart_type']
+CHART_PARAMS = ['type', 'id', 'name', 'title', 'units', 'family', 'context', 'chart_type', 'hidden']
DIMENSION_PARAMS = ['id', 'name', 'algorithm', 'multiplier', 'divisor', 'hidden']
VARIABLE_PARAMS = ['id', 'value']
@@ -13,9 +14,9 @@ DIMENSION_ALGORITHMS = ['absolute', 'incremental', 'percentage-of-absolute-row',
CHART_BEGIN = 'BEGIN {type}.{id} {since_last}\n'
CHART_CREATE = "CHART {type}.{id} '{name}' '{title}' '{units}' '{family}' '{context}' " \
- "{chart_type} {priority} {update_every} '' 'python.d.plugin' '{module_name}'\n"
+ "{chart_type} {priority} {update_every} '{hidden}' 'python.d.plugin' '{module_name}'\n"
CHART_OBSOLETE = "CHART {type}.{id} '{name}' '{title}' '{units}' '{family}' '{context}' " \
- "{chart_type} {priority} {update_every} 'obsolete'\n"
+ "{chart_type} {priority} {update_every} '{hidden} obsolete'\n"
DIMENSION_CREATE = "DIMENSION '{id}' '{name}' {algorithm} {multiplier} {divisor} '{hidden}'\n"
@@ -151,6 +152,8 @@ class Chart:
id=self.params['id'])
if self.params.get('chart_type') not in CHART_TYPES:
self.params['chart_type'] = 'absolute'
+ hidden = str(self.params.get('hidden', ''))
+ self.params['hidden'] = 'hidden' if hidden == 'hidden' else ''
self.dimensions = list()
self.variables = set()
@@ -304,6 +307,12 @@ class Dimension:
return self.id == other
return self.id == other.id
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(repr(self))
+
def create(self):
return DIMENSION_CREATE.format(**self.params)
@@ -360,6 +369,9 @@ class ChartVariable:
return self.id == other.id
return False
+ def __ne__(self, other):
+ return not self == other
+
def __hash__(self):
return hash(repr(self))
diff --git a/python.d/python_modules/bases/collection.py b/collectors/python.d.plugin/python_modules/bases/collection.py
index e03b4f58e..479a3b610 100644
--- a/python.d/python_modules/bases/collection.py
+++ b/collectors/python.d.plugin/python_modules/bases/collection.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description:
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
import os
diff --git a/python.d/python_modules/bases/loaders.py b/collectors/python.d.plugin/python_modules/bases/loaders.py
index d18b9dcd0..9eb268ce7 100644
--- a/python.d/python_modules/bases/loaders.py
+++ b/collectors/python.d.plugin/python_modules/bases/loaders.py
@@ -1,18 +1,27 @@
# -*- coding: utf-8 -*-
# Description:
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
import types
+
from sys import version_info
PY_VERSION = version_info[:2]
+try:
+ if PY_VERSION > (3, 1):
+ from pyyaml3 import SafeLoader as YamlSafeLoader
+ else:
+ from pyyaml2 import SafeLoader as YamlSafeLoader
+except ImportError:
+ from yaml import SafeLoader as YamlSafeLoader
+
+
if PY_VERSION > (3, 1):
- from pyyaml3 import SafeLoader as YamlSafeLoader
from importlib.machinery import SourceFileLoader
DEFAULT_MAPPING_TAG = 'tag:yaml.org,2002:map'
else:
- from pyyaml2 import SafeLoader as YamlSafeLoader
from imp import load_source as SourceFileLoader
DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map'
@@ -26,6 +35,14 @@ def dict_constructor(loader, node):
return OrderedDict(loader.construct_pairs(node))
+def safe_load(stream):
+ loader = YamlSafeLoader(stream)
+ try:
+ return loader.get_single_data()
+ finally:
+ loader.dispose()
+
+
YamlSafeLoader.add_constructor(DEFAULT_MAPPING_TAG, dict_constructor)
diff --git a/python.d/python_modules/bases/loggers.py b/collectors/python.d.plugin/python_modules/bases/loggers.py
index fc40b83d3..39be77a79 100644
--- a/python.d/python_modules/bases/loggers.py
+++ b/collectors/python.d.plugin/python_modules/bases/loggers.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description:
# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
import logging
import traceback
diff --git a/python.d/python_modules/pyyaml2/__init__.py b/collectors/python.d.plugin/python_modules/pyyaml2/__init__.py
index 76e19e13f..4d560e438 100644
--- a/python.d/python_modules/pyyaml2/__init__.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/__init__.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from error import *
diff --git a/python.d/python_modules/pyyaml2/composer.py b/collectors/python.d.plugin/python_modules/pyyaml2/composer.py
index 06e5ac782..6b41b8067 100644
--- a/python.d/python_modules/pyyaml2/composer.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/composer.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['Composer', 'ComposerError']
diff --git a/python.d/python_modules/pyyaml2/constructor.py b/collectors/python.d.plugin/python_modules/pyyaml2/constructor.py
index 635faac3e..8ad1b90a7 100644
--- a/python.d/python_modules/pyyaml2/constructor.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/constructor.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
'ConstructorError']
diff --git a/python.d/python_modules/pyyaml2/cyaml.py b/collectors/python.d.plugin/python_modules/pyyaml2/cyaml.py
index 68dcd7519..2858ab479 100644
--- a/python.d/python_modules/pyyaml2/cyaml.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/cyaml.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['CBaseLoader', 'CSafeLoader', 'CLoader',
'CBaseDumper', 'CSafeDumper', 'CDumper']
diff --git a/python.d/python_modules/pyyaml2/dumper.py b/collectors/python.d.plugin/python_modules/pyyaml2/dumper.py
index f811d2c91..3685cbeeb 100644
--- a/python.d/python_modules/pyyaml2/dumper.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/dumper.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['BaseDumper', 'SafeDumper', 'Dumper']
diff --git a/python.d/python_modules/pyyaml2/emitter.py b/collectors/python.d.plugin/python_modules/pyyaml2/emitter.py
index e5bcdcccb..9a460a0fd 100644
--- a/python.d/python_modules/pyyaml2/emitter.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/emitter.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# Emitter expects events obeying the following grammar:
# stream ::= STREAM-START document* STREAM-END
diff --git a/python.d/python_modules/pyyaml2/error.py b/collectors/python.d.plugin/python_modules/pyyaml2/error.py
index 577686db5..5466be721 100644
--- a/python.d/python_modules/pyyaml2/error.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/error.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['Mark', 'YAMLError', 'MarkedYAMLError']
diff --git a/python.d/python_modules/pyyaml2/events.py b/collectors/python.d.plugin/python_modules/pyyaml2/events.py
index f79ad389c..283452add 100644
--- a/python.d/python_modules/pyyaml2/events.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/events.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# Abstract classes.
diff --git a/python.d/python_modules/pyyaml2/loader.py b/collectors/python.d.plugin/python_modules/pyyaml2/loader.py
index 293ff467b..1c195531f 100644
--- a/python.d/python_modules/pyyaml2/loader.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/loader.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['BaseLoader', 'SafeLoader', 'Loader']
diff --git a/python.d/python_modules/pyyaml2/nodes.py b/collectors/python.d.plugin/python_modules/pyyaml2/nodes.py
index c4f070c41..ed2a1b43e 100644
--- a/python.d/python_modules/pyyaml2/nodes.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/nodes.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
class Node(object):
def __init__(self, tag, value, start_mark, end_mark):
diff --git a/python.d/python_modules/pyyaml2/parser.py b/collectors/python.d.plugin/python_modules/pyyaml2/parser.py
index f9e3057f3..97ba08337 100644
--- a/python.d/python_modules/pyyaml2/parser.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/parser.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# The following YAML grammar is LL(1) and is parsed by a recursive descent
# parser.
diff --git a/python.d/python_modules/pyyaml2/reader.py b/collectors/python.d.plugin/python_modules/pyyaml2/reader.py
index 3249e6b9f..8d422954e 100644
--- a/python.d/python_modules/pyyaml2/reader.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/reader.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# This module contains abstractions for the input stream. You don't have to
# looks further, there are no pretty code.
#
diff --git a/python.d/python_modules/pyyaml2/representer.py b/collectors/python.d.plugin/python_modules/pyyaml2/representer.py
index 5f4fc70db..0a1404eca 100644
--- a/python.d/python_modules/pyyaml2/representer.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/representer.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
'RepresenterError']
diff --git a/python.d/python_modules/pyyaml2/resolver.py b/collectors/python.d.plugin/python_modules/pyyaml2/resolver.py
index 6b5ab8759..49922debf 100644
--- a/python.d/python_modules/pyyaml2/resolver.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/resolver.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['BaseResolver', 'Resolver']
diff --git a/python.d/python_modules/pyyaml2/scanner.py b/collectors/python.d.plugin/python_modules/pyyaml2/scanner.py
index 5228fad65..971da6127 100644
--- a/python.d/python_modules/pyyaml2/scanner.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/scanner.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# Scanner produces tokens of the following types:
# STREAM-START
diff --git a/python.d/python_modules/pyyaml2/serializer.py b/collectors/python.d.plugin/python_modules/pyyaml2/serializer.py
index 0bf1e96dc..15fdbb0c0 100644
--- a/python.d/python_modules/pyyaml2/serializer.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/serializer.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['Serializer', 'SerializerError']
diff --git a/python.d/python_modules/pyyaml2/tokens.py b/collectors/python.d.plugin/python_modules/pyyaml2/tokens.py
index 4d0b48a39..c5c4fb116 100644
--- a/python.d/python_modules/pyyaml2/tokens.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml2/tokens.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
class Token(object):
def __init__(self, start_mark, end_mark):
diff --git a/python.d/python_modules/pyyaml3/__init__.py b/collectors/python.d.plugin/python_modules/pyyaml3/__init__.py
index a5e20f94d..a884b33cf 100644
--- a/python.d/python_modules/pyyaml3/__init__.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/__init__.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from .error import *
diff --git a/python.d/python_modules/pyyaml3/composer.py b/collectors/python.d.plugin/python_modules/pyyaml3/composer.py
index d5c6a7acd..c418bba91 100644
--- a/python.d/python_modules/pyyaml3/composer.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/composer.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['Composer', 'ComposerError']
diff --git a/python.d/python_modules/pyyaml3/constructor.py b/collectors/python.d.plugin/python_modules/pyyaml3/constructor.py
index 981543aeb..ee09a7a7e 100644
--- a/python.d/python_modules/pyyaml3/constructor.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/constructor.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
'ConstructorError']
diff --git a/python.d/python_modules/pyyaml3/cyaml.py b/collectors/python.d.plugin/python_modules/pyyaml3/cyaml.py
index d5cb87e99..e6c16d894 100644
--- a/python.d/python_modules/pyyaml3/cyaml.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/cyaml.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['CBaseLoader', 'CSafeLoader', 'CLoader',
'CBaseDumper', 'CSafeDumper', 'CDumper']
diff --git a/python.d/python_modules/pyyaml3/dumper.py b/collectors/python.d.plugin/python_modules/pyyaml3/dumper.py
index 0b6912877..ba590c6e6 100644
--- a/python.d/python_modules/pyyaml3/dumper.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/dumper.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['BaseDumper', 'SafeDumper', 'Dumper']
diff --git a/python.d/python_modules/pyyaml3/emitter.py b/collectors/python.d.plugin/python_modules/pyyaml3/emitter.py
index 34cb145a5..d4be65a8e 100644
--- a/python.d/python_modules/pyyaml3/emitter.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/emitter.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# Emitter expects events obeying the following grammar:
# stream ::= STREAM-START document* STREAM-END
diff --git a/python.d/python_modules/pyyaml3/error.py b/collectors/python.d.plugin/python_modules/pyyaml3/error.py
index b796b4dc5..5fec7d449 100644
--- a/python.d/python_modules/pyyaml3/error.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/error.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['Mark', 'YAMLError', 'MarkedYAMLError']
diff --git a/python.d/python_modules/pyyaml3/events.py b/collectors/python.d.plugin/python_modules/pyyaml3/events.py
index f79ad389c..283452add 100644
--- a/python.d/python_modules/pyyaml3/events.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/events.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# Abstract classes.
diff --git a/python.d/python_modules/pyyaml3/loader.py b/collectors/python.d.plugin/python_modules/pyyaml3/loader.py
index 08c8f01b3..7ef6cf815 100644
--- a/python.d/python_modules/pyyaml3/loader.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/loader.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['BaseLoader', 'SafeLoader', 'Loader']
diff --git a/python.d/python_modules/pyyaml3/nodes.py b/collectors/python.d.plugin/python_modules/pyyaml3/nodes.py
index c4f070c41..ed2a1b43e 100644
--- a/python.d/python_modules/pyyaml3/nodes.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/nodes.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
class Node(object):
def __init__(self, tag, value, start_mark, end_mark):
diff --git a/python.d/python_modules/pyyaml3/parser.py b/collectors/python.d.plugin/python_modules/pyyaml3/parser.py
index 13a5995d2..bcec7f994 100644
--- a/python.d/python_modules/pyyaml3/parser.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/parser.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# The following YAML grammar is LL(1) and is parsed by a recursive descent
# parser.
diff --git a/python.d/python_modules/pyyaml3/reader.py b/collectors/python.d.plugin/python_modules/pyyaml3/reader.py
index f70e920f4..0a515fd64 100644
--- a/python.d/python_modules/pyyaml3/reader.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/reader.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# This module contains abstractions for the input stream. You don't have to
# looks further, there are no pretty code.
#
diff --git a/python.d/python_modules/pyyaml3/representer.py b/collectors/python.d.plugin/python_modules/pyyaml3/representer.py
index 67cd6fd25..756a18dcc 100644
--- a/python.d/python_modules/pyyaml3/representer.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/representer.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
'RepresenterError']
diff --git a/python.d/python_modules/pyyaml3/resolver.py b/collectors/python.d.plugin/python_modules/pyyaml3/resolver.py
index 0eece2582..50945e04d 100644
--- a/python.d/python_modules/pyyaml3/resolver.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/resolver.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['BaseResolver', 'Resolver']
diff --git a/python.d/python_modules/pyyaml3/scanner.py b/collectors/python.d.plugin/python_modules/pyyaml3/scanner.py
index 494d975ba..b55854e8b 100644
--- a/python.d/python_modules/pyyaml3/scanner.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/scanner.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# Scanner produces tokens of the following types:
# STREAM-START
diff --git a/python.d/python_modules/pyyaml3/serializer.py b/collectors/python.d.plugin/python_modules/pyyaml3/serializer.py
index fe911e67a..1ba2f7f9d 100644
--- a/python.d/python_modules/pyyaml3/serializer.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/serializer.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
__all__ = ['Serializer', 'SerializerError']
diff --git a/python.d/python_modules/pyyaml3/tokens.py b/collectors/python.d.plugin/python_modules/pyyaml3/tokens.py
index 4d0b48a39..c5c4fb116 100644
--- a/python.d/python_modules/pyyaml3/tokens.py
+++ b/collectors/python.d.plugin/python_modules/pyyaml3/tokens.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
class Token(object):
def __init__(self, start_mark, end_mark):
diff --git a/python.d/python_modules/urllib3/packages/backports/__init__.py b/collectors/python.d.plugin/python_modules/third_party/__init__.py
index e69de29bb..e69de29bb 100644
--- a/python.d/python_modules/urllib3/packages/backports/__init__.py
+++ b/collectors/python.d.plugin/python_modules/third_party/__init__.py
diff --git a/collectors/python.d.plugin/python_modules/third_party/boinc_client.py b/collectors/python.d.plugin/python_modules/third_party/boinc_client.py
new file mode 100644
index 000000000..ec21779a0
--- /dev/null
+++ b/collectors/python.d.plugin/python_modules/third_party/boinc_client.py
@@ -0,0 +1,515 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# client.py - Somewhat higher-level GUI_RPC API for BOINC core client
+#
+# Copyright (C) 2013 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
+# Copyright (C) 2017 Austin S. Hemmelgarn
+#
+# SPDX-License-Identifier: GPL-3.0
+
+# Based on client/boinc_cmd.cpp
+
+import hashlib
+import socket
+import sys
+import time
+from functools import total_ordering
+from xml.etree import ElementTree
+
+GUI_RPC_PASSWD_FILE = "/var/lib/boinc/gui_rpc_auth.cfg"
+
+GUI_RPC_HOSTNAME = None # localhost
+GUI_RPC_PORT = 31416
+GUI_RPC_TIMEOUT = 1
+
+class Rpc(object):
+ ''' Class to perform GUI RPC calls to a BOINC core client.
+ Usage in a context manager ('with' block) is recommended to ensure
+ disconnect() is called. Using the same instance for all calls is also
+ recommended so it reuses the same socket connection
+ '''
+ def __init__(self, hostname="", port=0, timeout=0, text_output=False):
+ self.hostname = hostname
+ self.port = port
+ self.timeout = timeout
+ self.sock = None
+ self.text_output = text_output
+
+ @property
+ def sockargs(self):
+ return (self.hostname, self.port, self.timeout)
+
+ def __enter__(self): self.connect(*self.sockargs); return self
+ def __exit__(self, *args): self.disconnect()
+
+ def connect(self, hostname="", port=0, timeout=0):
+ ''' Connect to (hostname, port) with timeout in seconds.
+ Hostname defaults to None (localhost), and port to 31416
+ Calling multiple times will disconnect previous connection (if any),
+ and (re-)connect to host.
+ '''
+ if self.sock:
+ self.disconnect()
+
+ self.hostname = hostname or GUI_RPC_HOSTNAME
+ self.port = port or GUI_RPC_PORT
+ self.timeout = timeout or GUI_RPC_TIMEOUT
+
+ self.sock = socket.create_connection(self.sockargs[0:2], self.sockargs[2])
+
+ def disconnect(self):
+ ''' Disconnect from host. Calling multiple times is OK (idempotent)
+ '''
+ if self.sock:
+ self.sock.close()
+ self.sock = None
+
+ def call(self, request, text_output=None):
+ ''' Do an RPC call. Pack and send the XML request and return the
+ unpacked reply. request can be either plain XML text or a
+ xml.etree.ElementTree.Element object. Return ElementTree.Element
+ or XML text according to text_output flag.
+ Will auto-connect if not connected.
+ '''
+ if text_output is None:
+ text_output = self.text_output
+
+ if not self.sock:
+ self.connect(*self.sockargs)
+
+ if not isinstance(request, ElementTree.Element):
+ request = ElementTree.fromstring(request)
+
+ # pack request
+ end = '\003'
+ if sys.version_info[0] < 3:
+ req = "<boinc_gui_rpc_request>\n{0}\n</boinc_gui_rpc_request>\n{1}".format(ElementTree.tostring(request).replace(' />', '/>'), end)
+ else:
+ req = "<boinc_gui_rpc_request>\n{0}\n</boinc_gui_rpc_request>\n{1}".format(ElementTree.tostring(request, encoding='unicode').replace(' />', '/>'), end).encode()
+
+ try:
+ self.sock.sendall(req)
+ except (socket.error, socket.herror, socket.gaierror, socket.timeout):
+ raise
+
+ req = ""
+ while True:
+ try:
+ buf = self.sock.recv(8192)
+ if not buf:
+ raise socket.error("No data from socket")
+ if sys.version_info[0] >= 3:
+ buf = buf.decode()
+ except socket.error:
+ raise
+ n = buf.find(end)
+ if not n == -1: break
+ req += buf
+ req += buf[:n]
+
+ # unpack reply (remove root tag, ie: first and last lines)
+ req = '\n'.join(req.strip().rsplit('\n')[1:-1])
+
+ if text_output:
+ return req
+ else:
+ return ElementTree.fromstring(req)
+
+def setattrs_from_xml(obj, xml, attrfuncdict={}):
+ ''' Helper to set values for attributes of a class instance by mapping
+ matching tags from a XML file.
+ attrfuncdict is a dict of functions to customize value data type of
+ each attribute. It falls back to simple int/float/bool/str detection
+ based on values defined in __init__(). This would not be needed if
+ Boinc used standard RPC protocol, which includes data type in XML.
+ '''
+ if not isinstance(xml, ElementTree.Element):
+ xml = ElementTree.fromstring(xml)
+ for e in list(xml):
+ if hasattr(obj, e.tag):
+ attr = getattr(obj, e.tag)
+ attrfunc = attrfuncdict.get(e.tag, None)
+ if attrfunc is None:
+ if isinstance(attr, bool): attrfunc = parse_bool
+ elif isinstance(attr, int): attrfunc = parse_int
+ elif isinstance(attr, float): attrfunc = parse_float
+ elif isinstance(attr, str): attrfunc = parse_str
+ elif isinstance(attr, list): attrfunc = parse_list
+ else: attrfunc = lambda x: x
+ setattr(obj, e.tag, attrfunc(e))
+ else:
+ pass
+ #print "class missing attribute '%s': %r" % (e.tag, obj)
+ return obj
+
+
+def parse_bool(e):
+ ''' Helper to convert ElementTree.Element.text to boolean.
+ Treat '<foo/>' (and '<foo>[[:blank:]]</foo>') as True
+ Treat '0' and 'false' as False
+ '''
+ if e.text is None:
+ return True
+ else:
+ return bool(e.text) and not e.text.strip().lower() in ('0', 'false')
+
+
+def parse_int(e):
+ ''' Helper to convert ElementTree.Element.text to integer.
+ Treat '<foo/>' (and '<foo></foo>') as 0
+ '''
+ # int(float()) allows casting to int a value expressed as float in XML
+ return 0 if e.text is None else int(float(e.text.strip()))
+
+
+def parse_float(e):
+ ''' Helper to convert ElementTree.Element.text to float. '''
+ return 0.0 if e.text is None else float(e.text.strip())
+
+
+def parse_str(e):
+ ''' Helper to convert ElementTree.Element.text to string. '''
+ return "" if e.text is None else e.text.strip()
+
+
+def parse_list(e):
+ ''' Helper to convert ElementTree.Element to list. For now, simply return
+ the list of root element's children
+ '''
+ return list(e)
+
+
+class Enum(object):
+ UNKNOWN = -1 # Not in original API
+
+ @classmethod
+ def name(cls, value):
+ ''' Quick-and-dirty fallback for getting the "name" of an enum item '''
+
+ # value as string, if it matches an enum attribute.
+ # Allows short usage as Enum.name("VALUE") besides Enum.name(Enum.VALUE)
+ if hasattr(cls, str(value)):
+ return cls.name(getattr(cls, value, None))
+
+ # value not handled in subclass name()
+ for k, v in cls.__dict__.items():
+ if v == value:
+ return k.lower().replace('_', ' ')
+
+ # value not found
+ return cls.name(Enum.UNKNOWN)
+
+
+class CpuSched(Enum):
+ ''' values of ACTIVE_TASK::scheduler_state and ACTIVE_TASK::next_scheduler_state
+ "SCHEDULED" is synonymous with "executing" except when CPU throttling
+ is in use.
+ '''
+ UNINITIALIZED = 0
+ PREEMPTED = 1
+ SCHEDULED = 2
+
+
+class ResultState(Enum):
+ ''' Values of RESULT::state in client.
+ THESE MUST BE IN NUMERICAL ORDER
+ (because of the > comparison in RESULT::computing_done())
+ see html/inc/common_defs.inc
+ '''
+ NEW = 0
+ #// New result
+ FILES_DOWNLOADING = 1
+ #// Input files for result (WU, app version) are being downloaded
+ FILES_DOWNLOADED = 2
+ #// Files are downloaded, result can be (or is being) computed
+ COMPUTE_ERROR = 3
+ #// computation failed; no file upload
+ FILES_UPLOADING = 4
+ #// Output files for result are being uploaded
+ FILES_UPLOADED = 5
+ #// Files are uploaded, notify scheduling server at some point
+ ABORTED = 6
+ #// result was aborted
+ UPLOAD_FAILED = 7
+ #// some output file permanent failure
+
+
+class Process(Enum):
+ ''' values of ACTIVE_TASK::task_state '''
+ UNINITIALIZED = 0
+ #// process doesn't exist yet
+ EXECUTING = 1
+ #// process is running, as far as we know
+ SUSPENDED = 9
+ #// we've sent it a "suspend" message
+ ABORT_PENDING = 5
+ #// process exceeded limits; send "abort" message, waiting to exit
+ QUIT_PENDING = 8
+ #// we've sent it a "quit" message, waiting to exit
+ COPY_PENDING = 10
+ #// waiting for async file copies to finish
+
+
+class _Struct(object):
+ ''' base helper class with common methods for all classes derived from
+ BOINC's C++ structs
+ '''
+ @classmethod
+ def parse(cls, xml):
+ return setattrs_from_xml(cls(), xml)
+
+ def __str__(self, indent=0):
+ buf = '{0}{1}:\n'.format('\t' * indent, self.__class__.__name__)
+ for attr in self.__dict__:
+ value = getattr(self, attr)
+ if isinstance(value, list):
+ buf += '{0}\t{1} [\n'.format('\t' * indent, attr)
+ for v in value: buf += '\t\t{0}\t\t,\n'.format(v)
+ buf += '\t]\n'
+ else:
+ buf += '{0}\t{1}\t{2}\n'.format('\t' * indent,
+ attr,
+ value.__str__(indent+2)
+ if isinstance(value, _Struct)
+ else repr(value))
+ return buf
+
+
+@total_ordering
+class VersionInfo(_Struct):
+ def __init__(self, major=0, minor=0, release=0):
+ self.major = major
+ self.minor = minor
+ self.release = release
+
+ @property
+ def _tuple(self):
+ return (self.major, self.minor, self.release)
+
+ def __eq__(self, other):
+ return isinstance(other, self.__class__) and self._tuple == other._tuple
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __gt__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self._tuple > other._tuple
+
+ def __str__(self):
+ return "{0}.{1}.{2}".format(self.major, self.minor, self.release)
+
+ def __repr__(self):
+ return "{0}{1}".format(self.__class__.__name__, self._tuple)
+
+
+class Result(_Struct):
+ ''' Also called "task" in some contexts '''
+ def __init__(self):
+ # Names and values follow lib/gui_rpc_client.h @ RESULT
+ # Order too, except when grouping contradicts client/result.cpp
+ # RESULT::write_gui(), then XML order is used.
+
+ self.name = ""
+ self.wu_name = ""
+ self.version_num = 0
+ #// identifies the app used
+ self.plan_class = ""
+ self.project_url = "" # from PROJECT.master_url
+ self.report_deadline = 0.0 # seconds since epoch
+ self.received_time = 0.0 # seconds since epoch
+ #// when we got this from server
+ self.ready_to_report = False
+ #// we're ready to report this result to the server;
+ #// either computation is done and all the files have been uploaded
+ #// or there was an error
+ self.got_server_ack = False
+ #// we've received the ack for this result from the server
+ self.final_cpu_time = 0.0
+ self.final_elapsed_time = 0.0
+ self.state = ResultState.NEW
+ self.estimated_cpu_time_remaining = 0.0
+ #// actually, estimated elapsed time remaining
+ self.exit_status = 0
+ #// return value from the application
+ self.suspended_via_gui = False
+ self.project_suspended_via_gui = False
+ self.edf_scheduled = False
+ #// temporary used to tell GUI that this result is deadline-scheduled
+ self.coproc_missing = False
+ #// a coproc needed by this job is missing
+ #// (e.g. because user removed their GPU board).
+ self.scheduler_wait = False
+ self.scheduler_wait_reason = ""
+ self.network_wait = False
+ self.resources = ""
+ #// textual description of resources used
+
+ #// the following defined if active
+ # XML is generated in client/app.cpp ACTIVE_TASK::write_gui()
+ self.active_task = False
+ self.active_task_state = Process.UNINITIALIZED
+ self.app_version_num = 0
+ self.slot = -1
+ self.pid = 0
+ self.scheduler_state = CpuSched.UNINITIALIZED
+ self.checkpoint_cpu_time = 0.0
+ self.current_cpu_time = 0.0
+ self.fraction_done = 0.0
+ self.elapsed_time = 0.0
+ self.swap_size = 0
+ self.working_set_size_smoothed = 0.0
+ self.too_large = False
+ self.needs_shmem = False
+ self.graphics_exec_path = ""
+ self.web_graphics_url = ""
+ self.remote_desktop_addr = ""
+ self.slot_path = ""
+ #// only present if graphics_exec_path is
+
+ # The following are not in original API, but are present in RPC XML reply
+ self.completed_time = 0.0
+ #// time when ready_to_report was set
+ self.report_immediately = False
+ self.working_set_size = 0
+ self.page_fault_rate = 0.0
+ #// derived by higher-level code
+
+ # The following are in API, but are NEVER in RPC XML reply. Go figure
+ self.signal = 0
+
+ self.app = None # APP*
+ self.wup = None # WORKUNIT*
+ self.project = None # PROJECT*
+ self.avp = None # APP_VERSION*
+
+ @classmethod
+ def parse(cls, xml):
+ if not isinstance(xml, ElementTree.Element):
+ xml = ElementTree.fromstring(xml)
+
+ # parse main XML
+ result = super(Result, cls).parse(xml)
+
+ # parse '<active_task>' children
+ active_task = xml.find('active_task')
+ if active_task is None:
+ result.active_task = False # already the default after __init__()
+ else:
+ result.active_task = True # already the default after main parse
+ result = setattrs_from_xml(result, active_task)
+
+ #// if CPU time is nonzero but elapsed time is zero,
+ #// we must be talking to an old client.
+ #// Set elapsed = CPU
+ #// (easier to deal with this here than in the manager)
+ if result.current_cpu_time != 0 and result.elapsed_time == 0:
+ result.elapsed_time = result.current_cpu_time
+
+ if result.final_cpu_time != 0 and result.final_elapsed_time == 0:
+ result.final_elapsed_time = result.final_cpu_time
+
+ return result
+
+ def __str__(self):
+ buf = '{0}:\n'.format(self.__class__.__name__)
+ for attr in self.__dict__:
+ value = getattr(self, attr)
+ if attr in ['received_time', 'report_deadline']:
+ value = time.ctime(value)
+ buf += '\t{0}\t{1}\n'.format(attr, value)
+ return buf
+
+
+class BoincClient(object):
+
+ def __init__(self, host="", port=0, passwd=None):
+ self.hostname = host
+ self.port = port
+ self.passwd = passwd
+ self.rpc = Rpc(text_output=False)
+ self.version = None
+ self.authorized = False
+
+ # Informative, not authoritative. Records status of *last* RPC call,
+ # but does not infer success about the *next* one.
+ # Thus, it should be read *after* an RPC call, not prior to one
+ self.connected = False
+
+ def __enter__(self): self.connect(); return self
+ def __exit__(self, *args): self.disconnect()
+
+ def connect(self):
+ try:
+ self.rpc.connect(self.hostname, self.port)
+ self.connected = True
+ except socket.error:
+ self.connected = False
+ return
+ self.authorized = self.authorize(self.passwd)
+ self.version = self.exchange_versions()
+
+ def disconnect(self):
+ self.rpc.disconnect()
+
+ def authorize(self, password):
+ ''' Request authorization. If password is None and we are connecting
+ to localhost, try to read password from the local config file
+ GUI_RPC_PASSWD_FILE. If file can't be read (not found or no
+ permission to read), try to authorize with a blank password.
+ If authorization is requested and fails, all subsequent calls
+ will be refused with socket.error 'Connection reset by peer' (104).
+ Since most local calls do no require authorization, do not attempt
+ it if you're not sure about the password.
+ '''
+ if password is None and not self.hostname:
+ password = read_gui_rpc_password() or ""
+ nonce = self.rpc.call('<auth1/>').text
+ authhash = hashlib.md5('{0}{1}'.format(nonce, password).encode()).hexdigest().lower()
+ reply = self.rpc.call('<auth2><nonce_hash>{0}</nonce_hash></auth2>'.format(authhash))
+
+ if reply.tag == 'authorized':
+ return True
+ else:
+ return False
+
+ def exchange_versions(self):
+ ''' Return VersionInfo instance with core client version info '''
+ return VersionInfo.parse(self.rpc.call('<exchange_versions/>'))
+
+ def get_tasks(self):
+ ''' Same as get_results(active_only=False) '''
+ return self.get_results(False)
+
+ def get_results(self, active_only=False):
+ ''' Get a list of results.
+ Those that are in progress will have information such as CPU time
+ and fraction done. Each result includes a name;
+ Use CC_STATE::lookup_result() to find this result in the current static state;
+ if it's not there, call get_state() again.
+ '''
+ reply = self.rpc.call("<get_results><active_only>{0}</active_only></get_results>".format(1 if active_only else 0))
+ if not reply.tag == 'results':
+ return []
+
+ results = []
+ for item in list(reply):
+ results.append(Result.parse(item))
+
+ return results
+
+
+def read_gui_rpc_password():
+ ''' Read password string from GUI_RPC_PASSWD_FILE file, trim the last CR
+ (if any), and return it
+ '''
+ try:
+ with open(GUI_RPC_PASSWD_FILE, 'r') as f:
+ buf = f.read()
+ if buf.endswith('\n'): return buf[:-1] # trim last CR
+ else: return buf
+ except IOError:
+ # Permission denied or File not found.
+ pass
diff --git a/python.d/python_modules/third_party/lm_sensors.py b/collectors/python.d.plugin/python_modules/third_party/lm_sensors.py
index 1d868f0e2..f10cd6209 100644
--- a/python.d/python_modules/third_party/lm_sensors.py
+++ b/collectors/python.d.plugin/python_modules/third_party/lm_sensors.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: LGPL-2.1
"""
@package sensors.py
Python Bindings for libsensors3
@@ -254,4 +255,4 @@ class SubFeatureIterator:
return subfeature
def next(self): # python2 compability
- return self.__next__() \ No newline at end of file
+ return self.__next__()
diff --git a/collectors/python.d.plugin/python_modules/third_party/mcrcon.py b/collectors/python.d.plugin/python_modules/third_party/mcrcon.py
new file mode 100644
index 000000000..a65a304b6
--- /dev/null
+++ b/collectors/python.d.plugin/python_modules/third_party/mcrcon.py
@@ -0,0 +1,74 @@
+# Minecraft Remote Console module.
+#
+# Copyright (C) 2015 Barnaby Gale
+#
+# SPDX-License-Identifier: MIT
+
+import socket
+import select
+import struct
+import time
+
+
+class MCRconException(Exception):
+ pass
+
+
+class MCRcon(object):
+ socket = None
+
+ def connect(self, host, port, password):
+ if self.socket is not None:
+ raise MCRconException("Already connected")
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.socket.settimeout(0.9)
+ self.socket.connect((host, port))
+ self.send(3, password)
+
+ def disconnect(self):
+ if self.socket is None:
+ raise MCRconException("Already disconnected")
+ self.socket.close()
+ self.socket = None
+
+ def read(self, length):
+ data = b""
+ while len(data) < length:
+ data += self.socket.recv(length - len(data))
+ return data
+
+ def send(self, out_type, out_data):
+ if self.socket is None:
+ raise MCRconException("Must connect before sending data")
+
+ # Send a request packet
+ out_payload = struct.pack('<ii', 0, out_type) + out_data.encode('utf8') + b'\x00\x00'
+ out_length = struct.pack('<i', len(out_payload))
+ self.socket.send(out_length + out_payload)
+
+ # Read response packets
+ in_data = ""
+ while True:
+ # Read a packet
+ in_length, = struct.unpack('<i', self.read(4))
+ in_payload = self.read(in_length)
+ in_id = struct.unpack('<ii', in_payload[:8])
+ in_data_partial, in_padding = in_payload[8:-2], in_payload[-2:]
+
+ # Sanity checks
+ if in_padding != b'\x00\x00':
+ raise MCRconException("Incorrect padding")
+ if in_id == -1:
+ raise MCRconException("Login failed")
+
+ # Record the response
+ in_data += in_data_partial.decode('utf8')
+
+ # If there's nothing more to receive, return the response
+ if len(select.select([self.socket], [], [], 0)[0]) == 0:
+ return in_data
+
+ def command(self, command):
+ result = self.send(2, command)
+ time.sleep(0.003) # MC-72390 workaround
+ return result
diff --git a/collectors/python.d.plugin/python_modules/third_party/monotonic.py b/collectors/python.d.plugin/python_modules/third_party/monotonic.py
new file mode 100644
index 000000000..da04bb857
--- /dev/null
+++ b/collectors/python.d.plugin/python_modules/third_party/monotonic.py
@@ -0,0 +1,171 @@
+# -*- coding: utf-8 -*-
+#
+# SPDX-License-Identifier: Apache-2.0
+"""
+ monotonic
+ ~~~~~~~~~
+
+ This module provides a ``monotonic()`` function which returns the
+ value (in fractional seconds) of a clock which never goes backwards.
+
+ On Python 3.3 or newer, ``monotonic`` will be an alias of
+ ``time.monotonic`` from the standard library. On older versions,
+ it will fall back to an equivalent implementation:
+
+ +-------------+----------------------------------------+
+ | Linux, BSD | ``clock_gettime(3)`` |
+ +-------------+----------------------------------------+
+ | Windows | ``GetTickCount`` or ``GetTickCount64`` |
+ +-------------+----------------------------------------+
+ | OS X | ``mach_absolute_time`` |
+ +-------------+----------------------------------------+
+
+ If no suitable implementation exists for the current platform,
+ attempting to import this module (or to import from it) will
+ cause a ``RuntimeError`` exception to be raised.
+
+
+ Copyright 2014, 2015, 2016 Ori Livneh <ori@wikimedia.org>
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+"""
+import time
+
+
+__all__ = ('monotonic',)
+
+
+try:
+ monotonic = time.monotonic
+except AttributeError:
+ import ctypes
+ import ctypes.util
+ import os
+ import sys
+ import threading
+ try:
+ if sys.platform == 'darwin': # OS X, iOS
+ # See Technical Q&A QA1398 of the Mac Developer Library:
+ # <https://developer.apple.com/library/mac/qa/qa1398/>
+ libc = ctypes.CDLL('/usr/lib/libc.dylib', use_errno=True)
+
+ class mach_timebase_info_data_t(ctypes.Structure):
+ """System timebase info. Defined in <mach/mach_time.h>."""
+ _fields_ = (('numer', ctypes.c_uint32),
+ ('denom', ctypes.c_uint32))
+
+ mach_absolute_time = libc.mach_absolute_time
+ mach_absolute_time.restype = ctypes.c_uint64
+
+ timebase = mach_timebase_info_data_t()
+ libc.mach_timebase_info(ctypes.byref(timebase))
+ ticks_per_second = timebase.numer / timebase.denom * 1.0e9
+
+ def monotonic():
+ """Monotonic clock, cannot go backward."""
+ return mach_absolute_time() / ticks_per_second
+
+ elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
+ if sys.platform.startswith('cygwin'):
+ # Note: cygwin implements clock_gettime (CLOCK_MONOTONIC = 4) since
+ # version 1.7.6. Using raw WinAPI for maximum version compatibility.
+
+ # Ugly hack using the wrong calling convention (in 32-bit mode)
+ # because ctypes has no windll under cygwin (and it also seems that
+ # the code letting you select stdcall in _ctypes doesn't exist under
+ # the preprocessor definitions relevant to cygwin).
+ # This is 'safe' because:
+ # 1. The ABI of GetTickCount and GetTickCount64 is identical for
+ # both calling conventions because they both have no parameters.
+ # 2. libffi masks the problem because after making the call it doesn't
+ # touch anything through esp and epilogue code restores a correct
+ # esp from ebp afterwards.
+ try:
+ kernel32 = ctypes.cdll.kernel32
+ except OSError: # 'No such file or directory'
+ kernel32 = ctypes.cdll.LoadLibrary('kernel32.dll')
+ else:
+ kernel32 = ctypes.windll.kernel32
+
+ GetTickCount64 = getattr(kernel32, 'GetTickCount64', None)
+ if GetTickCount64:
+ # Windows Vista / Windows Server 2008 or newer.
+ GetTickCount64.restype = ctypes.c_ulonglong
+
+ def monotonic():
+ """Monotonic clock, cannot go backward."""
+ return GetTickCount64() / 1000.0
+
+ else:
+ # Before Windows Vista.
+ GetTickCount = kernel32.GetTickCount
+ GetTickCount.restype = ctypes.c_uint32
+
+ get_tick_count_lock = threading.Lock()
+ get_tick_count_last_sample = 0
+ get_tick_count_wraparounds = 0
+
+ def monotonic():
+ """Monotonic clock, cannot go backward."""
+ global get_tick_count_last_sample
+ global get_tick_count_wraparounds
+
+ with get_tick_count_lock:
+ current_sample = GetTickCount()
+ if current_sample < get_tick_count_last_sample:
+ get_tick_count_wraparounds += 1
+ get_tick_count_last_sample = current_sample
+
+ final_milliseconds = get_tick_count_wraparounds << 32
+ final_milliseconds += get_tick_count_last_sample
+ return final_milliseconds / 1000.0
+
+ else:
+ try:
+ clock_gettime = ctypes.CDLL(ctypes.util.find_library('c'),
+ use_errno=True).clock_gettime
+ except Exception:
+ clock_gettime = ctypes.CDLL(ctypes.util.find_library('rt'),
+ use_errno=True).clock_gettime
+
+ class timespec(ctypes.Structure):
+ """Time specification, as described in clock_gettime(3)."""
+ _fields_ = (('tv_sec', ctypes.c_long),
+ ('tv_nsec', ctypes.c_long))
+
+ if sys.platform.startswith('linux'):
+ CLOCK_MONOTONIC = 1
+ elif sys.platform.startswith('freebsd'):
+ CLOCK_MONOTONIC = 4
+ elif sys.platform.startswith('sunos5'):
+ CLOCK_MONOTONIC = 4
+ elif 'bsd' in sys.platform:
+ CLOCK_MONOTONIC = 3
+ elif sys.platform.startswith('aix'):
+ CLOCK_MONOTONIC = ctypes.c_longlong(10)
+
+ def monotonic():
+ """Monotonic clock, cannot go backward."""
+ ts = timespec()
+ if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(ts)):
+ errno = ctypes.get_errno()
+ raise OSError(errno, os.strerror(errno))
+ return ts.tv_sec + ts.tv_nsec / 1.0e9
+
+ # Perform a sanity-check.
+ if monotonic() - monotonic() > 0:
+ raise ValueError('monotonic() is not monotonic!')
+
+ except Exception as e:
+ raise RuntimeError('no suitable implementation for this system: ' + repr(e))
diff --git a/python.d/python_modules/third_party/ordereddict.py b/collectors/python.d.plugin/python_modules/third_party/ordereddict.py
index d0b97d47c..589401b8f 100644
--- a/python.d/python_modules/third_party/ordereddict.py
+++ b/collectors/python.d.plugin/python_modules/third_party/ordereddict.py
@@ -1,24 +1,6 @@
# Copyright (c) 2009 Raymond Hettinger
#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-# OTHER DEALINGS IN THE SOFTWARE.
+# SPDX-License-Identifier: MIT
from UserDict import DictMixin
diff --git a/python.d/python_modules/urllib3/__init__.py b/collectors/python.d.plugin/python_modules/urllib3/__init__.py
index 26493ecb9..3add84816 100644
--- a/python.d/python_modules/urllib3/__init__.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/__init__.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
"""
urllib3 - Thread-safe connection pooling and re-using.
"""
diff --git a/python.d/python_modules/urllib3/_collections.py b/collectors/python.d.plugin/python_modules/urllib3/_collections.py
index 4849ddecd..c1d2fad36 100644
--- a/python.d/python_modules/urllib3/_collections.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/_collections.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
from collections import Mapping, MutableMapping
try:
diff --git a/python.d/python_modules/urllib3/connection.py b/collectors/python.d.plugin/python_modules/urllib3/connection.py
index c0d832998..f757493c7 100644
--- a/python.d/python_modules/urllib3/connection.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/connection.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
import datetime
import logging
diff --git a/python.d/python_modules/urllib3/connectionpool.py b/collectors/python.d.plugin/python_modules/urllib3/connectionpool.py
index b4f1166a6..90e4c86a5 100644
--- a/python.d/python_modules/urllib3/connectionpool.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/connectionpool.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
import errno
import logging
diff --git a/src/.keep b/collectors/python.d.plugin/python_modules/urllib3/contrib/__init__.py
index e69de29bb..e69de29bb 100644
--- a/src/.keep
+++ b/collectors/python.d.plugin/python_modules/urllib3/contrib/__init__.py
diff --git a/collectors/python.d.plugin/python_modules/urllib3/contrib/_securetransport/__init__.py b/collectors/python.d.plugin/python_modules/urllib3/contrib/_securetransport/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/collectors/python.d.plugin/python_modules/urllib3/contrib/_securetransport/__init__.py
diff --git a/python.d/python_modules/urllib3/contrib/_securetransport/bindings.py b/collectors/python.d.plugin/python_modules/urllib3/contrib/_securetransport/bindings.py
index e26b84086..bb826673f 100644
--- a/python.d/python_modules/urllib3/contrib/_securetransport/bindings.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/contrib/_securetransport/bindings.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
"""
This module uses ctypes to bind a whole bunch of functions and constants from
SecureTransport. The goal here is to provide the low-level API to
diff --git a/python.d/python_modules/urllib3/contrib/_securetransport/low_level.py b/collectors/python.d.plugin/python_modules/urllib3/contrib/_securetransport/low_level.py
index 5e3494bce..0f79a1372 100644
--- a/python.d/python_modules/urllib3/contrib/_securetransport/low_level.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/contrib/_securetransport/low_level.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
"""
Low-level helpers for the SecureTransport bindings.
diff --git a/python.d/python_modules/urllib3/contrib/appengine.py b/collectors/python.d.plugin/python_modules/urllib3/contrib/appengine.py
index 814b0222d..e74589fa8 100644
--- a/python.d/python_modules/urllib3/contrib/appengine.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/contrib/appengine.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
"""
This module provides a pool manager that uses Google App Engine's
`URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_.
diff --git a/python.d/python_modules/urllib3/contrib/ntlmpool.py b/collectors/python.d.plugin/python_modules/urllib3/contrib/ntlmpool.py
index 642e99ed2..3f8c9ebf5 100644
--- a/python.d/python_modules/urllib3/contrib/ntlmpool.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/contrib/ntlmpool.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
"""
NTLM authenticating pool, contributed by erikcederstran
diff --git a/python.d/python_modules/urllib3/contrib/pyopenssl.py b/collectors/python.d.plugin/python_modules/urllib3/contrib/pyopenssl.py
index 6645dbaa9..8d373507d 100644
--- a/python.d/python_modules/urllib3/contrib/pyopenssl.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/contrib/pyopenssl.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
"""
SSL with SNI_-support for Python 2. Follow these instructions if you would
like to verify SSL certificates in Python 2. Note, the default libraries do
diff --git a/python.d/python_modules/urllib3/contrib/securetransport.py b/collectors/python.d.plugin/python_modules/urllib3/contrib/securetransport.py
index 72b23ab1c..fcc30118c 100644
--- a/python.d/python_modules/urllib3/contrib/securetransport.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/contrib/securetransport.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
"""
SecureTranport support for urllib3 via ctypes.
diff --git a/python.d/python_modules/urllib3/contrib/socks.py b/collectors/python.d.plugin/python_modules/urllib3/contrib/socks.py
index 39e92fde1..1cb79285b 100644
--- a/python.d/python_modules/urllib3/contrib/socks.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/contrib/socks.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+# SPDX-License-Identifier: MIT
"""
This module contains provisional support for SOCKS proxies from within
urllib3. This module supports SOCKS4 (specifically the SOCKS4A variant) and
diff --git a/python.d/python_modules/urllib3/exceptions.py b/collectors/python.d.plugin/python_modules/urllib3/exceptions.py
index 6c4be5810..a71cabe06 100644
--- a/python.d/python_modules/urllib3/exceptions.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/exceptions.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
from .packages.six.moves.http_client import (
IncompleteRead as httplib_IncompleteRead
diff --git a/python.d/python_modules/urllib3/fields.py b/collectors/python.d.plugin/python_modules/urllib3/fields.py
index 19b0ae0c8..de7577b74 100644
--- a/python.d/python_modules/urllib3/fields.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/fields.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
import email.utils
import mimetypes
diff --git a/python.d/python_modules/urllib3/filepost.py b/collectors/python.d.plugin/python_modules/urllib3/filepost.py
index cd11cee46..3febc9cfe 100644
--- a/python.d/python_modules/urllib3/filepost.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/filepost.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
import codecs
diff --git a/python.d/python_modules/urllib3/packages/__init__.py b/collectors/python.d.plugin/python_modules/urllib3/packages/__init__.py
index 170e974c1..170e974c1 100644
--- a/python.d/python_modules/urllib3/packages/__init__.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/packages/__init__.py
diff --git a/collectors/python.d.plugin/python_modules/urllib3/packages/backports/__init__.py b/collectors/python.d.plugin/python_modules/urllib3/packages/backports/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/collectors/python.d.plugin/python_modules/urllib3/packages/backports/__init__.py
diff --git a/python.d/python_modules/urllib3/packages/backports/makefile.py b/collectors/python.d.plugin/python_modules/urllib3/packages/backports/makefile.py
index 75b80dcf8..8ab122f8b 100644
--- a/python.d/python_modules/urllib3/packages/backports/makefile.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/packages/backports/makefile.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+# SPDX-License-Identifier: MIT
"""
backports.makefile
~~~~~~~~~~~~~~~~~~
diff --git a/python.d/python_modules/urllib3/packages/ordered_dict.py b/collectors/python.d.plugin/python_modules/urllib3/packages/ordered_dict.py
index 4479363cc..9f7c0e6b8 100644
--- a/python.d/python_modules/urllib3/packages/ordered_dict.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/packages/ordered_dict.py
@@ -2,6 +2,7 @@
# Passes Python2.7's test suite and incorporates all the latest updates.
# Copyright 2009 Raymond Hettinger, released under the MIT License.
# http://code.activestate.com/recipes/576693/
+# SPDX-License-Identifier: MIT
try:
from thread import get_ident as _get_ident
except ImportError:
diff --git a/python.d/python_modules/urllib3/packages/six.py b/collectors/python.d.plugin/python_modules/urllib3/packages/six.py
index 190c0239c..31df5012b 100644
--- a/python.d/python_modules/urllib3/packages/six.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/packages/six.py
@@ -2,23 +2,7 @@
# Copyright (c) 2010-2015 Benjamin Peterson
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
diff --git a/python.d/python_modules/urllib3/packages/ssl_match_hostname/__init__.py b/collectors/python.d.plugin/python_modules/urllib3/packages/ssl_match_hostname/__init__.py
index d6594eb26..2aeeeff91 100644
--- a/python.d/python_modules/urllib3/packages/ssl_match_hostname/__init__.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/packages/ssl_match_hostname/__init__.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
import sys
try:
diff --git a/python.d/python_modules/urllib3/packages/ssl_match_hostname/_implementation.py b/collectors/python.d.plugin/python_modules/urllib3/packages/ssl_match_hostname/_implementation.py
index 1fd42f38a..647e081da 100644
--- a/python.d/python_modules/urllib3/packages/ssl_match_hostname/_implementation.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/packages/ssl_match_hostname/_implementation.py
@@ -1,7 +1,6 @@
"""The match_hostname() function from Python 3.3.3, essential when using SSL."""
-# Note: This file is under the PSF license as the code comes from the python
-# stdlib. http://docs.python.org/3/license.html
+# SPDX-License-Identifier: Python-2.0
import re
import sys
diff --git a/python.d/python_modules/urllib3/poolmanager.py b/collectors/python.d.plugin/python_modules/urllib3/poolmanager.py
index 4ae91744d..adea9bc01 100644
--- a/python.d/python_modules/urllib3/poolmanager.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/poolmanager.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
import collections
import functools
diff --git a/python.d/python_modules/urllib3/request.py b/collectors/python.d.plugin/python_modules/urllib3/request.py
index c0fddff04..f78331975 100644
--- a/python.d/python_modules/urllib3/request.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/request.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
from .filepost import encode_multipart_formdata
diff --git a/python.d/python_modules/urllib3/response.py b/collectors/python.d.plugin/python_modules/urllib3/response.py
index 408d9996a..cf14a3076 100644
--- a/python.d/python_modules/urllib3/response.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/response.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
from contextlib import contextmanager
import zlib
diff --git a/python.d/python_modules/urllib3/util/__init__.py b/collectors/python.d.plugin/python_modules/urllib3/util/__init__.py
index 2f2770b62..bba628d98 100644
--- a/python.d/python_modules/urllib3/util/__init__.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/util/__init__.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
# For backwards compatibility, provide imports that used to be here.
from .connection import is_connection_dropped
diff --git a/python.d/python_modules/urllib3/util/connection.py b/collectors/python.d.plugin/python_modules/urllib3/util/connection.py
index bf699cfd0..3bd69e8fa 100644
--- a/python.d/python_modules/urllib3/util/connection.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/util/connection.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
import socket
from .wait import wait_for_read
diff --git a/python.d/python_modules/urllib3/util/request.py b/collectors/python.d.plugin/python_modules/urllib3/util/request.py
index 3ddfcd559..18f27b032 100644
--- a/python.d/python_modules/urllib3/util/request.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/util/request.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
from base64 import b64encode
diff --git a/python.d/python_modules/urllib3/util/response.py b/collectors/python.d.plugin/python_modules/urllib3/util/response.py
index 67cf730ab..e4cda93d4 100644
--- a/python.d/python_modules/urllib3/util/response.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/util/response.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
from ..packages.six.moves import http_client as httplib
diff --git a/python.d/python_modules/urllib3/util/retry.py b/collectors/python.d.plugin/python_modules/urllib3/util/retry.py
index c603cb490..61e63afec 100644
--- a/python.d/python_modules/urllib3/util/retry.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/util/retry.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
import time
import logging
diff --git a/python.d/python_modules/urllib3/util/selectors.py b/collectors/python.d.plugin/python_modules/urllib3/util/selectors.py
index d75cb266b..c0997b1a2 100644
--- a/python.d/python_modules/urllib3/util/selectors.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/util/selectors.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
# Backport of selectors.py from Python 3.5+ to support Python < 3.4
# Also has the behavior specified in PEP 475 which is to retry syscalls
# in the case of an EINTR error. This module is required because selectors34
diff --git a/python.d/python_modules/urllib3/util/ssl_.py b/collectors/python.d.plugin/python_modules/urllib3/util/ssl_.py
index 33d428ed8..ece3ec39e 100644
--- a/python.d/python_modules/urllib3/util/ssl_.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/util/ssl_.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
import errno
import warnings
diff --git a/python.d/python_modules/urllib3/util/timeout.py b/collectors/python.d.plugin/python_modules/urllib3/util/timeout.py
index cec817e6e..4041cf9b9 100644
--- a/python.d/python_modules/urllib3/util/timeout.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/util/timeout.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
# The default socket timeout, used by httplib to indicate that no timeout was
# specified by the user
diff --git a/python.d/python_modules/urllib3/util/url.py b/collectors/python.d.plugin/python_modules/urllib3/util/url.py
index 6b6f9968d..99fd6534a 100644
--- a/python.d/python_modules/urllib3/util/url.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/util/url.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from __future__ import absolute_import
from collections import namedtuple
diff --git a/python.d/python_modules/urllib3/util/wait.py b/collectors/python.d.plugin/python_modules/urllib3/util/wait.py
index cb396e508..21e72979c 100644
--- a/python.d/python_modules/urllib3/util/wait.py
+++ b/collectors/python.d.plugin/python_modules/urllib3/util/wait.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
from .selectors import (
HAS_SELECT,
DefaultSelector,
diff --git a/collectors/python.d.plugin/rabbitmq/Makefile.inc b/collectors/python.d.plugin/rabbitmq/Makefile.inc
new file mode 100644
index 000000000..7e67ef512
--- /dev/null
+++ b/collectors/python.d.plugin/rabbitmq/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += rabbitmq/rabbitmq.chart.py
+dist_pythonconfig_DATA += rabbitmq/rabbitmq.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += rabbitmq/README.md rabbitmq/Makefile.inc
+
diff --git a/collectors/python.d.plugin/rabbitmq/README.md b/collectors/python.d.plugin/rabbitmq/README.md
new file mode 100644
index 000000000..22d367c4d
--- /dev/null
+++ b/collectors/python.d.plugin/rabbitmq/README.md
@@ -0,0 +1,56 @@
+# rabbitmq
+
+Module monitor rabbitmq performance and health metrics.
+
+Following charts are drawn:
+
+1. **Queued Messages**
+ * ready
+ * unacknowledged
+
+2. **Message Rates**
+ * ack
+ * redelivered
+ * deliver
+ * publish
+
+3. **Global Counts**
+ * channels
+ * consumers
+ * connections
+ * queues
+ * exchanges
+
+4. **File Descriptors**
+ * used descriptors
+
+5. **Socket Descriptors**
+ * used descriptors
+
+6. **Erlang processes**
+ * used processes
+
+7. **Erlang run queue**
+ * Erlang run queue
+
+8. **Memory**
+ * free memory in megabytes
+
+9. **Disk Space**
+ * free disk space in gigabytes
+
+### configuration
+
+```yaml
+socket:
+ name : 'local'
+ host : '127.0.0.1'
+ port : 15672
+ user : 'guest'
+ pass : 'guest'
+
+```
+
+When no configuration file is found, module tries to connect to: `localhost:15672`.
+
+---
diff --git a/python.d/rabbitmq.chart.py b/collectors/python.d.plugin/rabbitmq/rabbitmq.chart.py
index b8847e9f8..8298b4032 100644
--- a/python.d/rabbitmq.chart.py
+++ b/collectors/python.d.plugin/rabbitmq/rabbitmq.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: rabbitmq netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
from collections import namedtuple
from json import loads
@@ -20,91 +21,104 @@ retries = 60
METHODS = namedtuple('METHODS', ['get_data', 'url', 'stats'])
-NODE_STATS = ['fd_used',
- 'mem_used',
- 'sockets_used',
- 'proc_used',
- 'disk_free',
- 'run_queue'
- ]
-OVERVIEW_STATS = ['object_totals.channels',
- 'object_totals.consumers',
- 'object_totals.connections',
- 'object_totals.queues',
- 'object_totals.exchanges',
- 'queue_totals.messages_ready',
- 'queue_totals.messages_unacknowledged',
- 'message_stats.ack',
- 'message_stats.redeliver',
- 'message_stats.deliver',
- 'message_stats.publish'
- ]
-ORDER = ['queued_messages', 'message_rates', 'global_counts',
- 'file_descriptors', 'socket_descriptors', 'erlang_processes', 'erlang_run_queue', 'memory', 'disk_space']
+NODE_STATS = [
+ 'fd_used',
+ 'mem_used',
+ 'sockets_used',
+ 'proc_used',
+ 'disk_free',
+ 'run_queue'
+]
+
+OVERVIEW_STATS = [
+ 'object_totals.channels',
+ 'object_totals.consumers',
+ 'object_totals.connections',
+ 'object_totals.queues',
+ 'object_totals.exchanges',
+ 'queue_totals.messages_ready',
+ 'queue_totals.messages_unacknowledged',
+ 'message_stats.ack',
+ 'message_stats.redeliver',
+ 'message_stats.deliver',
+ 'message_stats.publish'
+]
+
+ORDER = [
+ 'queued_messages',
+ 'message_rates',
+ 'global_counts',
+ 'file_descriptors',
+ 'socket_descriptors',
+ 'erlang_processes',
+ 'erlang_run_queue',
+ 'memory',
+ 'disk_space'
+]
CHARTS = {
'file_descriptors': {
- 'options': [None, 'File Descriptors', 'descriptors', 'overview',
- 'rabbitmq.file_descriptors', 'line'],
+ 'options': [None, 'File Descriptors', 'descriptors', 'overview', 'rabbitmq.file_descriptors', 'line'],
'lines': [
['fd_used', 'used', 'absolute']
- ]},
+ ]
+ },
'memory': {
- 'options': [None, 'Memory', 'MB', 'overview',
- 'rabbitmq.memory', 'line'],
+ 'options': [None, 'Memory', 'MB', 'overview', 'rabbitmq.memory', 'line'],
'lines': [
['mem_used', 'used', 'absolute', 1, 1024 << 10]
- ]},
+ ]
+ },
'disk_space': {
- 'options': [None, 'Disk Space', 'GB', 'overview',
- 'rabbitmq.disk_space', 'line'],
+ 'options': [None, 'Disk Space', 'GB', 'overview', 'rabbitmq.disk_space', 'line'],
'lines': [
['disk_free', 'free', 'absolute', 1, 1024 ** 3]
- ]},
+ ]
+ },
'socket_descriptors': {
- 'options': [None, 'Socket Descriptors', 'descriptors', 'overview',
- 'rabbitmq.sockets', 'line'],
+ 'options': [None, 'Socket Descriptors', 'descriptors', 'overview', 'rabbitmq.sockets', 'line'],
'lines': [
['sockets_used', 'used', 'absolute']
- ]},
+ ]
+ },
'erlang_processes': {
- 'options': [None, 'Erlang Processes', 'processes', 'overview',
- 'rabbitmq.processes', 'line'],
+ 'options': [None, 'Erlang Processes', 'processes', 'overview', 'rabbitmq.processes', 'line'],
'lines': [
['proc_used', 'used', 'absolute']
- ]},
+ ]
+ },
'erlang_run_queue': {
- 'options': [None, 'Erlang Run Queue', 'processes', 'overview',
- 'rabbitmq.erlang_run_queue', 'line'],
+ 'options': [None, 'Erlang Run Queue', 'processes', 'overview', 'rabbitmq.erlang_run_queue', 'line'],
'lines': [
- ['run_queue',' length', 'absolute']
- ]},
+ ['run_queue', 'length', 'absolute']
+ ]
+ },
'global_counts': {
- 'options': [None, 'Global Counts', 'counts', 'overview',
- 'rabbitmq.global_counts', 'line'],
+ 'options': [None, 'Global Counts', 'counts', 'overview', 'rabbitmq.global_counts', 'line'],
'lines': [
['object_totals_channels', 'channels', 'absolute'],
['object_totals_consumers', 'consumers', 'absolute'],
['object_totals_connections', 'connections', 'absolute'],
['object_totals_queues', 'queues', 'absolute'],
['object_totals_exchanges', 'exchanges', 'absolute']
- ]},
+ ]
+ },
'queued_messages': {
- 'options': [None, 'Queued Messages', 'messages', 'overview',
- 'rabbitmq.queued_messages', 'stacked'],
+ 'options': [None, 'Queued Messages', 'messages', 'overview', 'rabbitmq.queued_messages', 'stacked'],
'lines': [
['queue_totals_messages_ready', 'ready', 'absolute'],
['queue_totals_messages_unacknowledged', 'unacknowledged', 'absolute']
- ]},
+ ]
+ },
'message_rates': {
- 'options': [None, 'Message Rates', 'messages/s', 'overview',
- 'rabbitmq.message_rates', 'stacked'],
+ 'options': [None, 'Message Rates', 'messages/s', 'overview', 'rabbitmq.message_rates', 'stacked'],
'lines': [
['message_stats_ack', 'ack', 'incremental'],
['message_stats_redeliver', 'redeliver', 'incremental'],
['message_stats_deliver', 'deliver', 'incremental'],
['message_stats_publish', 'publish', 'incremental']
- ]}
+ ]
+ }
}
diff --git a/conf.d/python.d/rabbitmq.conf b/collectors/python.d.plugin/rabbitmq/rabbitmq.conf
index 3f90da8a2..3f90da8a2 100644
--- a/conf.d/python.d/rabbitmq.conf
+++ b/collectors/python.d.plugin/rabbitmq/rabbitmq.conf
diff --git a/collectors/python.d.plugin/redis/Makefile.inc b/collectors/python.d.plugin/redis/Makefile.inc
new file mode 100644
index 000000000..6aab08977
--- /dev/null
+++ b/collectors/python.d.plugin/redis/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += redis/redis.chart.py
+dist_pythonconfig_DATA += redis/redis.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += redis/README.md redis/Makefile.inc
+
diff --git a/collectors/python.d.plugin/redis/README.md b/collectors/python.d.plugin/redis/README.md
new file mode 100644
index 000000000..8d21df0ca
--- /dev/null
+++ b/collectors/python.d.plugin/redis/README.md
@@ -0,0 +1,42 @@
+# redis
+
+Get INFO data from redis instance.
+
+Following charts are drawn:
+
+1. **Operations** per second
+ * operations
+
+2. **Hit rate** in percent
+ * rate
+
+3. **Memory utilization** in kilobytes
+ * total
+ * lua
+
+4. **Database keys**
+ * lines are creates dynamically based on how many databases are there
+
+5. **Clients**
+ * connected
+ * blocked
+
+6. **Slaves**
+ * connected
+
+### configuration
+
+```yaml
+socket:
+ name : 'local'
+ socket : '/var/lib/redis/redis.sock'
+
+localhost:
+ name : 'local'
+ host : 'localhost'
+ port : 6379
+```
+
+When no configuration file is found, module tries to connect to TCP/IP socket: `localhost:6379`.
+
+---
diff --git a/collectors/python.d.plugin/redis/redis.chart.py b/collectors/python.d.plugin/redis/redis.chart.py
new file mode 100644
index 000000000..37d55ebfe
--- /dev/null
+++ b/collectors/python.d.plugin/redis/redis.chart.py
@@ -0,0 +1,261 @@
+# -*- coding: utf-8 -*-
+# Description: redis netdata python.d module
+# Author: Pawel Krupa (paulfantom)
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import re
+
+from copy import deepcopy
+
+from bases.FrameworkServices.SocketService import SocketService
+
+REDIS_ORDER = [
+ 'operations',
+ 'hit_rate',
+ 'memory',
+ 'keys_redis',
+ 'eviction',
+ 'net',
+ 'connections',
+ 'clients',
+ 'slaves',
+ 'persistence',
+ 'bgsave_now',
+ 'bgsave_health',
+ 'uptime',
+]
+
+PIKA_ORDER = [
+ 'operations',
+ 'hit_rate',
+ 'memory',
+ 'keys_pika',
+ 'connections',
+ 'clients',
+ 'slaves',
+ 'uptime',
+]
+
+
+CHARTS = {
+ 'operations': {
+ 'options': [None, 'Operations', 'operations/s', 'operations', 'redis.operations', 'line'],
+ 'lines': [
+ ['total_commands_processed', 'commands', 'incremental'],
+ ['instantaneous_ops_per_sec', 'operations', 'absolute']
+ ]
+ },
+ 'hit_rate': {
+ 'options': [None, 'Hit rate', 'percent', 'hits', 'redis.hit_rate', 'line'],
+ 'lines': [
+ ['hit_rate', 'rate', 'absolute']
+ ]
+ },
+ 'memory': {
+ 'options': [None, 'Memory utilization', 'kilobytes', 'memory', 'redis.memory', 'line'],
+ 'lines': [
+ ['used_memory', 'total', 'absolute', 1, 1024],
+ ['used_memory_lua', 'lua', 'absolute', 1, 1024]
+ ]
+ },
+ 'net': {
+ 'options': [None, 'Bandwidth', 'kilobits/s', 'network', 'redis.net', 'area'],
+ 'lines': [
+ ['total_net_input_bytes', 'in', 'incremental', 8, 1024],
+ ['total_net_output_bytes', 'out', 'incremental', -8, 1024]
+ ]
+ },
+ 'keys_redis': {
+ 'options': [None, 'Keys per Database', 'keys', 'keys', 'redis.keys', 'line'],
+ 'lines': []
+ },
+ 'keys_pika': {
+ 'options': [None, 'Keys', 'keys', 'keys', 'redis.keys', 'line'],
+ 'lines': [
+ ['kv_keys', 'kv', 'absolute'],
+ ['hash_keys', 'hash', 'absolute'],
+ ['list_keys', 'list', 'absolute'],
+ ['zset_keys', 'zset', 'absolute'],
+ ['set_keys', 'set', 'absolute']
+ ]
+ },
+ 'eviction': {
+ 'options': [None, 'Evicted Keys', 'keys', 'keys', 'redis.eviction', 'line'],
+ 'lines': [
+ ['evicted_keys', 'evicted', 'absolute']
+ ]
+ },
+ 'connections': {
+ 'options': [None, 'Connections', 'connections/s', 'connections', 'redis.connections', 'line'],
+ 'lines': [
+ ['total_connections_received', 'received', 'incremental', 1],
+ ['rejected_connections', 'rejected', 'incremental', -1]
+ ]
+ },
+ 'clients': {
+ 'options': [None, 'Clients', 'clients', 'connections', 'redis.clients', 'line'],
+ 'lines': [
+ ['connected_clients', 'connected', 'absolute', 1],
+ ['blocked_clients', 'blocked', 'absolute', -1]
+ ]
+ },
+ 'slaves': {
+ 'options': [None, 'Slaves', 'slaves', 'replication', 'redis.slaves', 'line'],
+ 'lines': [
+ ['connected_slaves', 'connected', 'absolute']
+ ]
+ },
+ 'persistence': {
+ 'options': [None, 'Persistence Changes Since Last Save', 'changes', 'persistence',
+ 'redis.rdb_changes', 'line'],
+ 'lines': [
+ ['rdb_changes_since_last_save', 'changes', 'absolute']
+ ]
+ },
+ 'bgsave_now': {
+ 'options': [None, 'Duration of the RDB Save Operation', 'seconds', 'persistence',
+ 'redis.bgsave_now', 'absolute'],
+ 'lines': [
+ ['rdb_bgsave_in_progress', 'rdb save', 'absolute']
+ ]
+ },
+ 'bgsave_health': {
+ 'options': [None, 'Status of the Last RDB Save Operation', 'status', 'persistence',
+ 'redis.bgsave_health', 'line'],
+ 'lines': [
+ ['rdb_last_bgsave_status', 'rdb save', 'absolute']
+ ]
+ },
+ 'uptime': {
+ 'options': [None, 'Uptime', 'seconds', 'uptime', 'redis.uptime', 'line'],
+ 'lines': [
+ ['uptime_in_seconds', 'uptime', 'absolute']
+ ]
+ }
+}
+
+
+def copy_chart(name):
+ return {name: deepcopy(CHARTS[name])}
+
+
+RE = re.compile(r'\n([a-z_0-9 ]+):(?:keys=)?([^,\r]+)')
+
+
+class Service(SocketService):
+ def __init__(self, configuration=None, name=None):
+ SocketService.__init__(self, configuration=configuration, name=name)
+ self._keep_alive = True
+
+ self.order = list()
+ self.definitions = dict()
+
+ self.host = self.configuration.get('host', 'localhost')
+ self.port = self.configuration.get('port', 6379)
+ self.unix_socket = self.configuration.get('socket')
+ p = self.configuration.get('pass')
+
+ self.auth_request = 'AUTH {0} \r\n'.format(p).encode() if p else None
+ self.request = 'INFO\r\n'.encode()
+ self.bgsave_time = 0
+
+ def do_auth(self):
+ resp = self._get_raw_data(request=self.auth_request)
+ if not resp:
+ return False
+ if resp.strip() != '+OK':
+ self.error('invalid password')
+ return False
+ return True
+
+ def get_raw_and_parse(self):
+ if self.auth_request and not self.do_auth():
+ return None
+
+ resp = self._get_raw_data()
+
+ if not resp:
+ return None
+
+ parsed = RE.findall(resp)
+
+ if not parsed:
+ self.error('response is invalid/empty')
+ return None
+
+ return dict((k.replace(' ', '_'), v) for k, v in parsed)
+
+ def get_data(self):
+ """
+ Get data from socket
+ :return: dict
+ """
+ data = self.get_raw_and_parse()
+
+ if not data:
+ return None
+
+ try:
+ data['hit_rate'] = (
+ (int(data['keyspace_hits']) * 100) / (int(data['keyspace_hits']) + int(data['keyspace_misses']))
+ )
+ except (KeyError, ZeroDivisionError):
+ data['hit_rate'] = 0
+
+ if data.get('redis_version') and data.get('rdb_bgsave_in_progress'):
+ self.get_data_redis_specific(data)
+
+ return data
+
+ def get_data_redis_specific(self, data):
+ if data['rdb_bgsave_in_progress'] != '0':
+ self.bgsave_time += self.update_every
+ else:
+ self.bgsave_time = 0
+
+ data['rdb_last_bgsave_status'] = 0 if data['rdb_last_bgsave_status'] == 'ok' else 1
+ data['rdb_bgsave_in_progress'] = self.bgsave_time
+
+ def check(self):
+ """
+ Parse configuration, check if redis is available, and dynamically create chart lines data
+ :return: boolean
+ """
+ data = self.get_raw_and_parse()
+
+ if not data:
+ return False
+
+ self.order = PIKA_ORDER if data.get('pika_version') else REDIS_ORDER
+
+ for n in self.order:
+ self.definitions.update(copy_chart(n))
+
+ if data.get('redis_version'):
+ for k in data:
+ if k.startswith('db'):
+ self.definitions['keys_redis']['lines'].append([k, None, 'absolute'])
+
+ return True
+
+ def _check_raw_data(self, data):
+ """
+ Check if all data has been gathered from socket.
+ Parse first line containing message length and check against received message
+ :param data: str
+ :return: boolean
+ """
+ length = len(data)
+ supposed = data.split('\n')[0][1:-1]
+ offset = len(supposed) + 4 # 1 dollar sing, 1 new line character + 1 ending sequence '\r\n'
+ if not supposed.isdigit():
+ return True
+ supposed = int(supposed)
+
+ if length - offset >= supposed:
+ self.debug('received full response from redis')
+ return True
+
+ self.debug('waiting more data from redis')
+ return False
diff --git a/conf.d/python.d/redis.conf b/collectors/python.d.plugin/redis/redis.conf
index 6363f6da7..6363f6da7 100644
--- a/conf.d/python.d/redis.conf
+++ b/collectors/python.d.plugin/redis/redis.conf
diff --git a/collectors/python.d.plugin/rethinkdbs/Makefile.inc b/collectors/python.d.plugin/rethinkdbs/Makefile.inc
new file mode 100644
index 000000000..dec604464
--- /dev/null
+++ b/collectors/python.d.plugin/rethinkdbs/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += rethinkdbs/rethinkdbs.chart.py
+dist_pythonconfig_DATA += rethinkdbs/rethinkdbs.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += rethinkdbs/README.md rethinkdbs/Makefile.inc
+
diff --git a/collectors/python.d.plugin/rethinkdbs/README.md b/collectors/python.d.plugin/rethinkdbs/README.md
new file mode 100644
index 000000000..5d357fa49
--- /dev/null
+++ b/collectors/python.d.plugin/rethinkdbs/README.md
@@ -0,0 +1,34 @@
+# rethinkdbs
+
+Module monitor rethinkdb health metrics.
+
+Following charts are drawn:
+
+1. **Connected Servers**
+ * connected
+ * missing
+
+2. **Active Clients**
+ * active
+
+3. **Queries** per second
+ * queries
+
+4. **Documents** per second
+ * documents
+
+### configuration
+
+```yaml
+
+localhost:
+ name : 'local'
+ host : '127.0.0.1'
+ port : 28015
+ user : "user"
+ password : "pass"
+```
+
+When no configuration file is found, module tries to connect to `127.0.0.1:28015`.
+
+---
diff --git a/collectors/python.d.plugin/rethinkdbs/rethinkdbs.chart.py b/collectors/python.d.plugin/rethinkdbs/rethinkdbs.chart.py
new file mode 100644
index 000000000..127e9ad4b
--- /dev/null
+++ b/collectors/python.d.plugin/rethinkdbs/rethinkdbs.chart.py
@@ -0,0 +1,235 @@
+# -*- coding: utf-8 -*-
+# Description: rethinkdb netdata python.d module
+# Author: Ilya Mashchenko (l2isbad)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+try:
+ import rethinkdb as rdb
+ HAS_RETHINKDB = True
+except ImportError:
+ HAS_RETHINKDB = False
+
+from bases.FrameworkServices.SimpleService import SimpleService
+
+ORDER = [
+ 'cluster_connected_servers',
+ 'cluster_clients_active',
+ 'cluster_queries',
+ 'cluster_documents',
+]
+
+
+def cluster_charts():
+ return {
+ 'cluster_connected_servers': {
+ 'options': [None, 'Connected Servers', 'servers', 'cluster', 'rethinkdb.cluster_connected_servers',
+ 'stacked'],
+ 'lines': [
+ ['cluster_servers_connected', 'connected'],
+ ['cluster_servers_missing', 'missing'],
+ ]
+ },
+ 'cluster_clients_active': {
+ 'options': [None, 'Active Clients', 'clients', 'cluster', 'rethinkdb.cluster_clients_active',
+ 'line'],
+ 'lines': [
+ ['cluster_clients_active', 'active'],
+ ]
+ },
+ 'cluster_queries': {
+ 'options': [None, 'Queries', 'queries/s', 'cluster', 'rethinkdb.cluster_queries', 'line'],
+ 'lines': [
+ ['cluster_queries_per_sec', 'queries'],
+ ]
+ },
+ 'cluster_documents': {
+ 'options': [None, 'Documents', 'documents/s', 'cluster', 'rethinkdb.cluster_documents', 'line'],
+ 'lines': [
+ ['cluster_read_docs_per_sec', 'reads'],
+ ['cluster_written_docs_per_sec', 'writes'],
+ ]
+ },
+ }
+
+
+def server_charts(n):
+ o = [
+ '{0}_client_connections'.format(n),
+ '{0}_clients_active'.format(n),
+ '{0}_queries'.format(n),
+ '{0}_documents'.format(n),
+ ]
+ f = 'server {0}'.format(n)
+
+ c = {
+ o[0]: {
+ 'options': [None, 'Client Connections', 'connections', f, 'rethinkdb.client_connections', 'line'],
+ 'lines': [
+ ['{0}_client_connections'.format(n), 'connections'],
+ ]
+ },
+ o[1]: {
+ 'options': [None, 'Active Clients', 'clients', f, 'rethinkdb.clients_active', 'line'],
+ 'lines': [
+ ['{0}_clients_active'.format(n), 'active'],
+ ]
+ },
+ o[2]: {
+ 'options': [None, 'Queries', 'queries/s', f, 'rethinkdb.queries', 'line'],
+ 'lines': [
+ ['{0}_queries_total'.format(n), 'queries', 'incremental'],
+ ]
+ },
+ o[3]: {
+ 'options': [None, 'Documents', 'documents/s', f, 'rethinkdb.documents', 'line'],
+ 'lines': [
+ ['{0}_read_docs_total'.format(n), 'reads', 'incremental'],
+ ['{0}_written_docs_total'.format(n), 'writes', 'incremental'],
+ ]
+ },
+ }
+
+ return o, c
+
+
+class Cluster:
+ def __init__(self, raw):
+ self.raw = raw
+
+ def data(self):
+ qe = self.raw['query_engine']
+
+ return {
+ 'cluster_clients_active': qe['clients_active'],
+ 'cluster_queries_per_sec': qe['queries_per_sec'],
+ 'cluster_read_docs_per_sec': qe['read_docs_per_sec'],
+ 'cluster_written_docs_per_sec': qe['written_docs_per_sec'],
+ 'cluster_servers_connected': 0,
+ 'cluster_servers_missing': 0,
+ }
+
+
+class Server:
+ def __init__(self, raw):
+ self.name = raw['server']
+ self.raw = raw
+
+ def error(self):
+ return self.raw.get('error')
+
+ def data(self):
+ qe = self.raw['query_engine']
+
+ d = {
+ 'client_connections': qe['client_connections'],
+ 'clients_active': qe['clients_active'],
+ 'queries_total': qe['queries_total'],
+ 'read_docs_total': qe['read_docs_total'],
+ 'written_docs_total': qe['written_docs_total'],
+ }
+
+ return dict(('{0}_{1}'.format(self.name, k), d[k]) for k in d)
+
+
+class Service(SimpleService):
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.order = list(ORDER)
+ self.definitions = cluster_charts()
+
+ self.host = self.configuration.get('host', '127.0.0.1')
+ self.port = self.configuration.get('port', 28015)
+ self.user = self.configuration.get('user', 'admin')
+ self.password = self.configuration.get('password')
+ self.timeout = self.configuration.get('timeout', 2)
+
+ self.conn = None
+ self.alive = True
+
+ def check(self):
+ if not HAS_RETHINKDB:
+ self.error('"rethinkdb" module is needed to use rethinkdbs.py')
+ return False
+
+ if not self.connect():
+ return None
+
+ stats = self.get_stats()
+
+ if not stats:
+ return None
+
+ for v in stats[1:]:
+ if get_id(v) == 'server':
+ o, c = server_charts(v['server'])
+ self.order.extend(o)
+ self.definitions.update(c)
+
+ return True
+
+ def get_data(self):
+ if not self.is_alive():
+ return None
+
+ stats = self.get_stats()
+
+ if not stats:
+ return None
+
+ data = dict()
+
+ # cluster
+ data.update(Cluster(stats[0]).data())
+
+ # servers
+ for v in stats[1:]:
+ if get_id(v) != 'server':
+ continue
+
+ s = Server(v)
+
+ if s.error():
+ data['cluster_servers_missing'] += 1
+ else:
+ data['cluster_servers_connected'] += 1
+ data.update(s.data())
+
+ return data
+
+ def get_stats(self):
+ try:
+ return list(rdb.db('rethinkdb').table('stats').run(self.conn).items)
+ except rdb.errors.ReqlError:
+ self.alive = False
+ return None
+
+ def connect(self):
+ try:
+ self.conn = rdb.connect(
+ host=self.host,
+ port=self.port,
+ user=self.user,
+ password=self.password,
+ timeout=self.timeout,
+ )
+ self.alive = True
+ return True
+ except rdb.errors.ReqlError as error:
+ self.error('Connection to {0}:{1} failed: {2}'.format(self.host, self.port, error))
+ return False
+
+ def reconnect(self):
+ # The connection is already closed after rdb.errors.ReqlError,
+ # so we do not need to call conn.close()
+ if self.connect():
+ return True
+ return False
+
+ def is_alive(self):
+ if not self.alive:
+ return self.reconnect()
+ return True
+
+
+def get_id(v):
+ return v['id'][0]
diff --git a/collectors/python.d.plugin/rethinkdbs/rethinkdbs.conf b/collectors/python.d.plugin/rethinkdbs/rethinkdbs.conf
new file mode 100644
index 000000000..73544fc2e
--- /dev/null
+++ b/collectors/python.d.plugin/rethinkdbs/rethinkdbs.conf
@@ -0,0 +1,78 @@
+# netdata python.d.plugin configuration for rethinkdb
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# Additionally to the above, rethinkdb also supports the following:
+#
+# host: IP or HOSTNAME # default is 'localhost'
+# port: PORT # default is 28015
+# user: USERNAME # default is 'admin'
+# password: PASSWORD # not set by default
+# timeout: TIMEOUT # default is 2
+
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
+# only one of them will run (they have the same name)
+
+local:
+ name: 'local'
+ host: 'localhost'
diff --git a/collectors/python.d.plugin/retroshare/Makefile.inc b/collectors/python.d.plugin/retroshare/Makefile.inc
new file mode 100644
index 000000000..891193e6d
--- /dev/null
+++ b/collectors/python.d.plugin/retroshare/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += retroshare/retroshare.chart.py
+dist_pythonconfig_DATA += retroshare/retroshare.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += retroshare/README.md retroshare/Makefile.inc
+
diff --git a/collectors/python.d.plugin/retroshare/README.md b/collectors/python.d.plugin/retroshare/README.md
new file mode 100644
index 000000000..e95095c65
--- /dev/null
+++ b/collectors/python.d.plugin/retroshare/README.md
@@ -0,0 +1 @@
+# retroshare
diff --git a/python.d/retroshare.chart.py b/collectors/python.d.plugin/retroshare/retroshare.chart.py
index 8c0330ec6..1d8e35050 100644
--- a/python.d/retroshare.chart.py
+++ b/collectors/python.d.plugin/retroshare/retroshare.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: RetroShare netdata python.d module
# Authors: sehraf
+# SPDX-License-Identifier: GPL-3.0-or-later
import json
@@ -20,19 +21,22 @@ CHARTS = {
'lines': [
['bandwidth_up_kb', 'Upload'],
['bandwidth_down_kb', 'Download']
- ]},
+ ]
+ },
'peers': {
'options': [None, 'RetroShare Peers', 'peers', 'RetroShare', 'retroshare.peers', 'line'],
'lines': [
['peers_all', 'All friends'],
['peers_connected', 'Connected friends']
- ]},
+ ]
+ },
'dht': {
'options': [None, 'Retroshare DHT', 'peers', 'RetroShare', 'retroshare.dht', 'line'],
'lines': [
['dht_size_all', 'DHT nodes estimated'],
['dht_size_rs', 'RS nodes estimated']
- ]}
+ ]
+ }
}
diff --git a/conf.d/python.d/retroshare.conf b/collectors/python.d.plugin/retroshare/retroshare.conf
index 9c92583f7..9c92583f7 100644
--- a/conf.d/python.d/retroshare.conf
+++ b/collectors/python.d.plugin/retroshare/retroshare.conf
diff --git a/collectors/python.d.plugin/samba/Makefile.inc b/collectors/python.d.plugin/samba/Makefile.inc
new file mode 100644
index 000000000..230a8ba43
--- /dev/null
+++ b/collectors/python.d.plugin/samba/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += samba/samba.chart.py
+dist_pythonconfig_DATA += samba/samba.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += samba/README.md samba/Makefile.inc
+
diff --git a/collectors/python.d.plugin/samba/README.md b/collectors/python.d.plugin/samba/README.md
new file mode 100644
index 000000000..44610d373
--- /dev/null
+++ b/collectors/python.d.plugin/samba/README.md
@@ -0,0 +1,67 @@
+# samba
+
+Performance metrics of Samba file sharing.
+
+**Requirements:**
+* `smbstatus` program
+* `sudo` program
+* `smbd` must be compiled with profiling enabled
+* `smbd` must be started either with the `-P 1` option or inside `smb.conf` using `smbd profiling level`
+* `netdata` user needs to be able to sudo the `smbstatus` program without password
+
+It produces the following charts:
+
+1. **Syscall R/Ws** in kilobytes/s
+ * sendfile
+ * recvfle
+
+2. **Smb2 R/Ws** in kilobytes/s
+ * readout
+ * writein
+ * readin
+ * writeout
+
+3. **Smb2 Create/Close** in operations/s
+ * create
+ * close
+
+4. **Smb2 Info** in operations/s
+ * getinfo
+ * setinfo
+
+5. **Smb2 Find** in operations/s
+ * find
+
+6. **Smb2 Notify** in operations/s
+ * notify
+
+7. **Smb2 Lesser Ops** as counters
+ * tcon
+ * negprot
+ * tdis
+ * cancel
+ * logoff
+ * flush
+ * lock
+ * keepalive
+ * break
+ * sessetup
+
+### prerequisite
+This module uses `smbstatus` which can only be executed by root. It uses
+`sudo` and assumes that it is configured such that the `netdata` user can
+execute `smbstatus` as root without password.
+
+Add to `sudoers`:
+
+ netdata ALL=(root) NOPASSWD: /path/to/smbstatus
+
+### configuration
+
+ **samba** is disabled by default. Should be explicitly enabled in `python.d.conf`.
+
+```yaml
+samba: yes
+```
+
+---
diff --git a/collectors/python.d.plugin/samba/samba.chart.py b/collectors/python.d.plugin/samba/samba.chart.py
new file mode 100644
index 000000000..b2278de9e
--- /dev/null
+++ b/collectors/python.d.plugin/samba/samba.chart.py
@@ -0,0 +1,138 @@
+# -*- coding: utf-8 -*-
+# Description: samba netdata python.d module
+# Author: Christopher Cox <chris_cox@endlessnow.com>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# The netdata user needs to be able to be able to sudo the smbstatus program
+# without password:
+# netdata ALL=(ALL) NOPASSWD: /usr/bin/smbstatus -P
+#
+# This makes calls to smbstatus -P
+#
+# This just looks at a couple of values out of syscall, and some from smb2.
+#
+# The Lesser Ops chart is merely a display of current counter values. They
+# didn't seem to change much to me. However, if you notice something changing
+# a lot there, bring one or more out into its own chart and make it incremental
+# (like find and notify... good examples).
+
+import re
+
+from bases.collection import find_binary
+from bases.FrameworkServices.ExecutableService import ExecutableService
+
+
+disabled_by_default = True
+
+# default module values (can be overridden per job in `config`)
+update_every = 5
+priority = 60000
+retries = 60
+
+ORDER = [
+ 'syscall_rw',
+ 'smb2_rw',
+ 'smb2_create_close',
+ 'smb2_info',
+ 'smb2_find',
+ 'smb2_notify',
+ 'smb2_sm_count'
+]
+
+CHARTS = {
+ 'syscall_rw': {
+ 'options': [None, 'R/Ws', 'kilobytes/s', 'syscall', 'syscall.rw', 'area'],
+ 'lines': [
+ ['syscall_sendfile_bytes', 'sendfile', 'incremental', 1, 1024],
+ ['syscall_recvfile_bytes', 'recvfile', 'incremental', -1, 1024]
+ ]
+ },
+ 'smb2_rw': {
+ 'options': [None, 'R/Ws', 'kilobytes/s', 'smb2', 'smb2.rw', 'area'],
+ 'lines': [
+ ['smb2_read_outbytes', 'readout', 'incremental', 1, 1024],
+ ['smb2_write_inbytes', 'writein', 'incremental', -1, 1024],
+ ['smb2_read_inbytes', 'readin', 'incremental', 1, 1024],
+ ['smb2_write_outbytes', 'writeout', 'incremental', -1, 1024]
+ ]
+ },
+ 'smb2_create_close': {
+ 'options': [None, 'Create/Close', 'operations/s', 'smb2', 'smb2.create_close', 'line'],
+ 'lines': [
+ ['smb2_create_count', 'create', 'incremental', 1, 1],
+ ['smb2_close_count', 'close', 'incremental', -1, 1]
+ ]
+ },
+ 'smb2_info': {
+ 'options': [None, 'Info', 'operations/s', 'smb2', 'smb2.get_set_info', 'line'],
+ 'lines': [
+ ['smb2_getinfo_count', 'getinfo', 'incremental', 1, 1],
+ ['smb2_setinfo_count', 'setinfo', 'incremental', -1, 1]
+ ]
+ },
+ 'smb2_find': {
+ 'options': [None, 'Find', 'operations/s', 'smb2', 'smb2.find', 'line'],
+ 'lines': [
+ ['smb2_find_count', 'find', 'incremental', 1, 1]
+ ]
+ },
+ 'smb2_notify': {
+ 'options': [None, 'Notify', 'operations/s', 'smb2', 'smb2.notify', 'line'],
+ 'lines': [
+ ['smb2_notify_count', 'notify', 'incremental', 1, 1]
+ ]
+ },
+ 'smb2_sm_count': {
+ 'options': [None, 'Lesser Ops', 'count', 'smb2', 'smb2.sm_counters', 'stacked'],
+ 'lines': [
+ ['smb2_tcon_count', 'tcon', 'absolute', 1, 1],
+ ['smb2_negprot_count', 'negprot', 'absolute', 1, 1],
+ ['smb2_tdis_count', 'tdis', 'absolute', 1, 1],
+ ['smb2_cancel_count', 'cancel', 'absolute', 1, 1],
+ ['smb2_logoff_count', 'logoff', 'absolute', 1, 1],
+ ['smb2_flush_count', 'flush', 'absolute', 1, 1],
+ ['smb2_lock_count', 'lock', 'absolute', 1, 1],
+ ['smb2_keepalive_count', 'keepalive', 'absolute', 1, 1],
+ ['smb2_break_count', 'break', 'absolute', 1, 1],
+ ['smb2_sessetup_count', 'sessetup', 'absolute', 1, 1]
+ ]
+ }
+}
+
+
+class Service(ExecutableService):
+ def __init__(self, configuration=None, name=None):
+ ExecutableService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+ self.rgx_smb2 = re.compile(r'(smb2_[^:]+|syscall_.*file_bytes):\s+(\d+)')
+
+ def check(self):
+ sudo_binary, smbstatus_binary = find_binary('sudo'), find_binary('smbstatus')
+
+ if not (sudo_binary and smbstatus_binary):
+ self.error("Can\'t locate 'sudo' or 'smbstatus' binary")
+ return False
+
+ self.command = [sudo_binary, '-v']
+ err = self._get_raw_data(stderr=True)
+ if err:
+ self.error(''.join(err))
+ return False
+
+ self.command = ' '.join([sudo_binary, '-n', smbstatus_binary, '-P'])
+
+ return ExecutableService.check(self)
+
+ def _get_data(self):
+ """
+ Format data received from shell command
+ :return: dict
+ """
+ raw_data = self._get_raw_data()
+ if not raw_data:
+ return None
+
+ parsed = self.rgx_smb2.findall(' '.join(raw_data))
+
+ return dict(parsed) or None
diff --git a/conf.d/python.d/samba.conf b/collectors/python.d.plugin/samba/samba.conf
index ee513c60f..ee513c60f 100644
--- a/conf.d/python.d/samba.conf
+++ b/collectors/python.d.plugin/samba/samba.conf
diff --git a/collectors/python.d.plugin/sensors/Makefile.inc b/collectors/python.d.plugin/sensors/Makefile.inc
new file mode 100644
index 000000000..5fb26e1c8
--- /dev/null
+++ b/collectors/python.d.plugin/sensors/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += sensors/sensors.chart.py
+dist_pythonconfig_DATA += sensors/sensors.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += sensors/README.md sensors/Makefile.inc
+
diff --git a/collectors/python.d.plugin/sensors/README.md b/collectors/python.d.plugin/sensors/README.md
new file mode 100644
index 000000000..eb1642d90
--- /dev/null
+++ b/collectors/python.d.plugin/sensors/README.md
@@ -0,0 +1,17 @@
+# sensors
+
+System sensors information.
+
+Charts are created dynamically.
+
+### configuration
+
+For detailed configuration information please read [`sensors.conf`](sensors.conf) file.
+
+### possible issues
+
+There have been reports from users that on certain servers, ACPI ring buffer errors are printed by the kernel (`dmesg`) when ACPI sensors are being accessed.
+We are tracking such cases in issue [#827](https://github.com/netdata/netdata/issues/827).
+Please join this discussion for help.
+
+---
diff --git a/python.d/sensors.chart.py b/collectors/python.d.plugin/sensors/sensors.chart.py
index 06e420b68..69d2bfe99 100644
--- a/python.d/sensors.chart.py
+++ b/collectors/python.d.plugin/sensors/sensors.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: sensors netdata python.d plugin
# Author: Pawel Krupa (paulfantom)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.FrameworkServices.SimpleService import SimpleService
from third_party import lm_sensors as sensors
@@ -16,37 +17,44 @@ CHARTS = {
'options': [None, ' temperature', 'Celsius', 'temperature', 'sensors.temperature', 'line'],
'lines': [
[None, None, 'absolute', 1, 1000]
- ]},
+ ]
+ },
'voltage': {
'options': [None, ' voltage', 'Volts', 'voltage', 'sensors.voltage', 'line'],
'lines': [
[None, None, 'absolute', 1, 1000]
- ]},
+ ]
+ },
'current': {
'options': [None, ' current', 'Ampere', 'current', 'sensors.current', 'line'],
'lines': [
[None, None, 'absolute', 1, 1000]
- ]},
+ ]
+ },
'power': {
'options': [None, ' power', 'Watt', 'power', 'sensors.power', 'line'],
'lines': [
[None, None, 'absolute', 1, 1000000]
- ]},
+ ]
+ },
'fan': {
'options': [None, ' fans speed', 'Rotations/min', 'fans', 'sensors.fan', 'line'],
'lines': [
[None, None, 'absolute', 1, 1000]
- ]},
+ ]
+ },
'energy': {
'options': [None, ' energy', 'Joule', 'energy', 'sensors.energy', 'areastack'],
'lines': [
[None, None, 'incremental', 1, 1000000]
- ]},
+ ]
+ },
'humidity': {
'options': [None, ' humidity', 'Percent', 'humidity', 'sensors.humidity', 'line'],
'lines': [
[None, None, 'absolute', 1, 1000]
- ]}
+ ]
+ }
}
LIMITS = {
@@ -94,7 +102,7 @@ class Service(SimpleService):
limit = LIMITS[type_name]
if val < limit[0] or val > limit[1]:
continue
- data[prefix + "_" + str(feature.name.decode())] = int(val * 1000)
+ data[prefix + '_' + str(feature.name.decode())] = int(val * 1000)
except Exception as error:
self.error(error)
return None
@@ -114,7 +122,7 @@ class Service(SimpleService):
continue
if TYPE_MAP[feature.type] == sensor:
# create chart
- name = chip_name + "_" + TYPE_MAP[feature.type]
+ name = chip_name + '_' + TYPE_MAP[feature.type]
if name not in self.order:
self.order.append(name)
chart_def = list(CHARTS[sensor]['options'])
@@ -122,7 +130,7 @@ class Service(SimpleService):
self.definitions[name] = {'options': chart_def}
self.definitions[name]['lines'] = []
line = list(CHARTS[sensor]['lines'][0])
- line[0] = chip_name + "_" + str(feature.name.decode())
+ line[0] = chip_name + '_' + str(feature.name.decode())
line[1] = sensors.get_label(chip, feature)
self.definitions[name]['lines'].append(line)
@@ -136,4 +144,3 @@ class Service(SimpleService):
self.create_definitions()
return True
-
diff --git a/conf.d/python.d/sensors.conf b/collectors/python.d.plugin/sensors/sensors.conf
index 83bbffd7d..83bbffd7d 100644
--- a/conf.d/python.d/sensors.conf
+++ b/collectors/python.d.plugin/sensors/sensors.conf
diff --git a/collectors/python.d.plugin/smartd_log/Makefile.inc b/collectors/python.d.plugin/smartd_log/Makefile.inc
new file mode 100644
index 000000000..dc1d0f3fb
--- /dev/null
+++ b/collectors/python.d.plugin/smartd_log/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += smartd_log/smartd_log.chart.py
+dist_pythonconfig_DATA += smartd_log/smartd_log.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += smartd_log/README.md smartd_log/Makefile.inc
+
diff --git a/collectors/python.d.plugin/smartd_log/README.md b/collectors/python.d.plugin/smartd_log/README.md
new file mode 100644
index 000000000..121a63573
--- /dev/null
+++ b/collectors/python.d.plugin/smartd_log/README.md
@@ -0,0 +1,38 @@
+# 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.
+
+---
diff --git a/python.d/smartd_log.chart.py b/collectors/python.d.plugin/smartd_log/smartd_log.chart.py
index 07ad88cd4..21dbccecc 100644
--- a/python.d/smartd_log.chart.py
+++ b/collectors/python.d.plugin/smartd_log/smartd_log.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: smart netdata python.d module
# Author: l2isbad, vorph1
+# SPDX-License-Identifier: GPL-3.0-or-later
import os
import re
@@ -115,7 +116,7 @@ def chart_template(chart_name):
chart_name: {
'options': [None, title, units, family, 'smartd_log.' + chart_name, 'line'],
'lines': []
- }
+ }
}
@@ -184,6 +185,12 @@ class Disk:
return self.name == other.name
return self.name == other
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(repr(self))
+
@handle_os_error
def is_active(self):
return (time() - os.path.getmtime(self.log_file.path)) / 60 < self.age
diff --git a/conf.d/python.d/smartd_log.conf b/collectors/python.d.plugin/smartd_log/smartd_log.conf
index 3fab3f1c0..3fab3f1c0 100644
--- a/conf.d/python.d/smartd_log.conf
+++ b/collectors/python.d.plugin/smartd_log/smartd_log.conf
diff --git a/collectors/python.d.plugin/spigotmc/Makefile.inc b/collectors/python.d.plugin/spigotmc/Makefile.inc
new file mode 100644
index 000000000..f9fa8b6b0
--- /dev/null
+++ b/collectors/python.d.plugin/spigotmc/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += spigotmc/spigotmc.chart.py
+dist_pythonconfig_DATA += spigotmc/spigotmc.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += spigotmc/README.md spigotmc/Makefile.inc
+
diff --git a/collectors/python.d.plugin/spigotmc/README.md b/collectors/python.d.plugin/spigotmc/README.md
new file mode 100644
index 000000000..ae5602587
--- /dev/null
+++ b/collectors/python.d.plugin/spigotmc/README.md
@@ -0,0 +1,22 @@
+# spigotmc
+
+This module does some really basic monitoring for Spigot Minecraft servers.
+
+It provides two charts, one tracking server-side ticks-per-second in
+1, 5 and 15 minute averages, and one tracking the number of currently
+active users.
+
+This is not compatible with Spigot plugins which change the format of
+the data returned by the `tps` or `list` console commands.
+
+### configuration
+
+```yaml
+host: localhost
+port: 25575
+password: pass
+```
+
+By default, a connection to port 25575 on the local system is attempted with an empty password.
+
+---
diff --git a/collectors/python.d.plugin/spigotmc/spigotmc.chart.py b/collectors/python.d.plugin/spigotmc/spigotmc.chart.py
new file mode 100644
index 000000000..a5e5ee0ee
--- /dev/null
+++ b/collectors/python.d.plugin/spigotmc/spigotmc.chart.py
@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+# Description: spigotmc netdata python.d module
+# Author: Austin S. Hemmelgarn (Ferroin)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import socket
+import platform
+
+from bases.FrameworkServices.SimpleService import SimpleService
+
+from third_party import mcrcon
+
+# Update only every 5 seconds because collection takes in excess of
+# 100ms sometimes, and mos tpeople won't care about second-by-second data.
+update_every = 5
+
+PRECISION = 100
+
+ORDER = ['tps', 'users']
+
+CHARTS = {
+ 'tps': {
+ 'options': [None, 'Spigot Ticks Per Second', 'ticks', 'spigotmc', 'spigotmc.tps', 'line'],
+ 'lines': [
+ ['tps1', '1 Minute Average', 'absolute', 1, PRECISION],
+ ['tps5', '5 Minute Average', 'absolute', 1, PRECISION],
+ ['tps15', '15 Minute Average', 'absolute', 1, PRECISION]
+ ]
+ },
+ 'users': {
+ 'options': [None, 'Minecraft Users', 'users', 'spigotmc', 'spigotmc.users', 'area'],
+ 'lines': [
+ ['users', 'Users', 'absolute', 1, 1]
+ ]
+ }
+}
+
+
+class Service(SimpleService):
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+ self.host = self.configuration.get('host', 'localhost')
+ self.port = self.configuration.get('port', 25575)
+ self.password = self.configuration.get('password', '')
+ self.console = mcrcon.MCRcon()
+ self.alive = True
+
+ def check(self):
+ if platform.system() != 'Linux':
+ self.error('Only supported on Linux.')
+ return False
+ try:
+ self.connect()
+ except (mcrcon.MCRconException, socket.error) as err:
+ self.error('Error connecting.')
+ self.error(repr(err))
+ return False
+ return True
+
+ def connect(self):
+ self.console.connect(self.host, self.port, self.password)
+
+ def reconnect(self):
+ try:
+ try:
+ self.console.disconnect()
+ except mcrcon.MCRconException:
+ pass
+ self.console.connect(self.host, self.port, self.password)
+ self.alive = True
+ except (mcrcon.MCRconException, socket.error) as err:
+ self.error('Error connecting.')
+ self.error(repr(err))
+ return False
+ return True
+
+ def is_alive(self):
+ if (not self.alive) or \
+ self.console.socket.getsockopt(socket.IPPROTO_TCP, socket.TCP_INFO, 0) != 1:
+ return self.reconnect()
+ return True
+
+ def _get_data(self):
+ if not self.is_alive():
+ return None
+ data = {}
+ try:
+ raw = self.console.command('tps')
+ # The above command returns a string that looks like this:
+ # '§6TPS from last 1m, 5m, 15m: §a19.99, §a19.99, §a19.99\n'
+ # The values we care about are the three numbers after the :
+ tmp = raw.split(':')[1].split(',')
+ data['tps1'] = float(tmp[0].lstrip(u' §a*')) * PRECISION
+ data['tps5'] = float(tmp[1].lstrip(u' §a*')) * PRECISION
+ data['tps15'] = float(tmp[2].lstrip(u' §a*').rstrip()) * PRECISION
+ except mcrcon.MCRconException:
+ self.error('Unable to fetch TPS values.')
+ except socket.error:
+ self.error('Connection is dead.')
+ self.alive = False
+ return None
+ except (TypeError, LookupError):
+ self.error('Unable to process TPS values.')
+ try:
+ raw = self.console.command('list')
+ # The above command returns a string that looks like this:
+ # 'There are 0/20 players online:'
+ # We care about the first number here.
+ data['users'] = int(raw.split()[2].split('/')[0])
+ except mcrcon.MCRconException:
+ self.error('Unable to fetch user counts.')
+ except socket.error:
+ self.error('Connection is dead.')
+ self.alive = False
+ return None
+ except (TypeError, LookupError):
+ self.error('Unable to process user counts.')
+ return data
diff --git a/collectors/python.d.plugin/spigotmc/spigotmc.conf b/collectors/python.d.plugin/spigotmc/spigotmc.conf
new file mode 100644
index 000000000..3ba492def
--- /dev/null
+++ b/collectors/python.d.plugin/spigotmc/spigotmc.conf
@@ -0,0 +1,68 @@
+# netdata python.d.plugin configuration for spigotmc
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# In addition to the above, spigotmc supports the following:
+#
+# host: localhost # The host to connect to. Defaults to the local system.
+# port: 25575 # THe port the remote console is listening on.
+# password: '' # The remote console password. Most be set correctly.
diff --git a/collectors/python.d.plugin/springboot/Makefile.inc b/collectors/python.d.plugin/springboot/Makefile.inc
new file mode 100644
index 000000000..06775f937
--- /dev/null
+++ b/collectors/python.d.plugin/springboot/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += springboot/springboot.chart.py
+dist_pythonconfig_DATA += springboot/springboot.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += springboot/README.md springboot/Makefile.inc
+
diff --git a/collectors/python.d.plugin/springboot/README.md b/collectors/python.d.plugin/springboot/README.md
new file mode 100644
index 000000000..008436a4f
--- /dev/null
+++ b/collectors/python.d.plugin/springboot/README.md
@@ -0,0 +1,129 @@
+# springboot
+
+This module will monitor one or more Java Spring-boot applications depending on configuration.
+
+It produces following charts:
+
+1. **Response Codes** in requests/s
+ * 1xx
+ * 2xx
+ * 3xx
+ * 4xx
+ * 5xx
+ * others
+
+2. **Threads**
+ * daemon
+ * total
+
+3. **GC Time** in milliseconds and **GC Operations** in operations/s
+ * Copy
+ * MarkSweep
+ * ...
+
+4. **Heap Mmeory Usage** in KB
+ * used
+ * committed
+
+### configuration
+
+Please see the [Monitoring Java Spring Boot Applications](https://github.com/netdata/netdata/wiki/Monitoring-Java-Spring-Boot-Applications) page for detailed info about module configuration.
+
+---
+
+# Monitoring Java Spring Boot Applications
+
+Netdata can be used to monitor running Java [Spring Boot](https://spring.io/) applications that expose their metrics with the use of the **Spring Boot Actuator** included in Spring Boot library.
+
+The Spring Boot Actuator exposes these metrics over HTTP and is very easy to use:
+* add `org.springframework.boot:spring-boot-starter-actuator` to your application dependencies
+* set `endpoints.metrics.sensitive=false` in your `application.properties`
+
+You can create custom Metrics by add and inject a PublicMetrics in your application.
+This is a example to add custom metrics:
+```java
+package com.example;
+
+import org.springframework.boot.actuate.endpoint.PublicMetrics;
+import org.springframework.boot.actuate.metrics.Metric;
+import org.springframework.stereotype.Service;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryPoolMXBean;
+import java.util.ArrayList;
+import java.util.Collection;
+
+@Service
+public class HeapPoolMetrics implements PublicMetrics {
+
+ private static final String PREFIX = "mempool.";
+ private static final String KEY_EDEN = PREFIX + "eden";
+ private static final String KEY_SURVIVOR = PREFIX + "survivor";
+ private static final String KEY_TENURED = PREFIX + "tenured";
+
+ @Override
+ public Collection<Metric<?>> metrics() {
+ Collection<Metric<?>> result = new ArrayList<>(4);
+ for (MemoryPoolMXBean mem : ManagementFactory.getMemoryPoolMXBeans()) {
+ String poolName = mem.getName();
+ String name = null;
+ if (poolName.indexOf("Eden Space") != -1) {
+ name = KEY_EDEN;
+ } else if (poolName.indexOf("Survivor Space") != -1) {
+ name = KEY_SURVIVOR;
+ } else if (poolName.indexOf("Tenured Gen") != -1 || poolName.indexOf("Old Gen") != -1) {
+ name = KEY_TENURED;
+ }
+
+ if (name != null) {
+ result.add(newMemoryMetric(name, mem.getUsage().getMax()));
+ result.add(newMemoryMetric(name + ".init", mem.getUsage().getInit()));
+ result.add(newMemoryMetric(name + ".committed", mem.getUsage().getCommitted()));
+ result.add(newMemoryMetric(name + ".used", mem.getUsage().getUsed()));
+ }
+ }
+ return result;
+ }
+
+ private Metric<Long> newMemoryMetric(String name, long bytes) {
+ return new Metric<>(name, bytes / 1024);
+ }
+}
+```
+
+Please refer [Spring Boot Actuator: Production-ready features](https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready.html) and [81. Actuator - Part IX. ‘How-to’ guides](https://docs.spring.io/spring-boot/docs/current/reference/html/howto-actuator.html) for more information.
+
+## Using netdata springboot module
+
+The springboot module is enabled by default. It looks up `http://localhost:8080/metrics` and `http://127.0.0.1:8080/metrics` to detect Spring Boot application by default. You can change it by editing `/etc/netdata/python.d/springboot.conf` (to edit it on your system run `/etc/netdata/edit-config python.d/springboot.conf`).
+
+This module defines some common charts, and you can add custom charts by change the configurations.
+
+The configuration format is like:
+```yaml
+<id>:
+ name: '<name>'
+ url: '<metrics endpoint>' # ex. http://localhost:8080/metrics
+ user: '<username>' # optional
+ pass: '<password>' # optional
+ defaults:
+ [<chart-id>]: true|false
+ extras:
+ - id: '<chart-id>'
+ options:
+ title: '***'
+ units: '***'
+ family: '***'
+ context: 'springboot.***'
+ charttype: 'stacked' | 'area' | 'line'
+ lines:
+ - { dimension: 'myapp_ok', name: 'ok', algorithm: 'absolute', multiplier: 1, divisor: 1} # it shows "myapp.ok" metrics
+ - { dimension: 'myapp_ng', name: 'ng', algorithm: 'absolute', multiplier: 1, divisor: 1} # it shows "myapp.ng" metrics
+```
+
+By default, it creates `response_code`, `threads`, `gc_time`, `gc_ope` abd `heap` charts.
+You can disable the default charts by set `defaults.<chart-id>: false`.
+
+The dimension name of extras charts should replace `.` to `_`.
+
+Please check [springboot.conf](springboot.conf) for more examples. \ No newline at end of file
diff --git a/python.d/springboot.chart.py b/collectors/python.d.plugin/springboot/springboot.chart.py
index 60ad0cccb..7df37e1d0 100644
--- a/python.d/springboot.chart.py
+++ b/collectors/python.d.plugin/springboot/springboot.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: tomcat netdata python.d module
# Author: Wing924
+# SPDX-License-Identifier: GPL-3.0-or-later
import json
from bases.FrameworkServices.UrlService import UrlService
@@ -17,54 +18,61 @@ DEFAULT_CHARTS = {
'response_code': {
'options': [None, "Response Codes", "requests/s", "response", "springboot.response_code", "stacked"],
'lines': [
- ["resp_other", 'Other', 'incremental'],
- ["resp_1xx", '1xx', 'incremental'],
- ["resp_2xx", '2xx', 'incremental'],
- ["resp_3xx", '3xx', 'incremental'],
- ["resp_4xx", '4xx', 'incremental'],
- ["resp_5xx", '5xx', 'incremental'],
- ]},
+ ["resp_other", 'Other', 'incremental'],
+ ["resp_1xx", '1xx', 'incremental'],
+ ["resp_2xx", '2xx', 'incremental'],
+ ["resp_3xx", '3xx', 'incremental'],
+ ["resp_4xx", '4xx', 'incremental'],
+ ["resp_5xx", '5xx', 'incremental'],
+ ]
+ },
'threads': {
'options': [None, "Threads", "current threads", "threads", "springboot.threads", "area"],
'lines': [
["threads_daemon", 'daemon', 'absolute'],
["threads", 'total', 'absolute'],
- ]},
+ ]
+ },
'gc_time': {
'options': [None, "GC Time", "milliseconds", "garbage collection", "springboot.gc_time", "stacked"],
'lines': [
- ["gc_copy_time", 'Copy', 'incremental'],
- ["gc_marksweepcompact_time", 'MarkSweepCompact', 'incremental'],
- ["gc_parnew_time", 'ParNew', 'incremental'],
- ["gc_concurrentmarksweep_time", 'ConcurrentMarkSweep', 'incremental'],
- ["gc_ps_scavenge_time", 'PS Scavenge', 'incremental'],
- ["gc_ps_marksweep_time", 'PS MarkSweep', 'incremental'],
- ["gc_g1_young_generation_time", 'G1 Young Generation', 'incremental'],
- ["gc_g1_old_generation_time", 'G1 Old Generation', 'incremental'],
- ]},
+ ["gc_copy_time", 'Copy', 'incremental'],
+ ["gc_marksweepcompact_time", 'MarkSweepCompact', 'incremental'],
+ ["gc_parnew_time", 'ParNew', 'incremental'],
+ ["gc_concurrentmarksweep_time", 'ConcurrentMarkSweep', 'incremental'],
+ ["gc_ps_scavenge_time", 'PS Scavenge', 'incremental'],
+ ["gc_ps_marksweep_time", 'PS MarkSweep', 'incremental'],
+ ["gc_g1_young_generation_time", 'G1 Young Generation', 'incremental'],
+ ["gc_g1_old_generation_time", 'G1 Old Generation', 'incremental'],
+ ]
+ },
'gc_ope': {
'options': [None, "GC Operations", "operations/s", "garbage collection", "springboot.gc_ope", "stacked"],
'lines': [
- ["gc_copy_count", 'Copy', 'incremental'],
- ["gc_marksweepcompact_count", 'MarkSweepCompact', 'incremental'],
- ["gc_parnew_count", 'ParNew', 'incremental'],
- ["gc_concurrentmarksweep_count", 'ConcurrentMarkSweep', 'incremental'],
- ["gc_ps_scavenge_count", 'PS Scavenge', 'incremental'],
- ["gc_ps_marksweep_count", 'PS MarkSweep', 'incremental'],
- ["gc_g1_young_generation_count", 'G1 Young Generation', 'incremental'],
- ["gc_g1_old_generation_count", 'G1 Old Generation', 'incremental'],
- ]},
+ ["gc_copy_count", 'Copy', 'incremental'],
+ ["gc_marksweepcompact_count", 'MarkSweepCompact', 'incremental'],
+ ["gc_parnew_count", 'ParNew', 'incremental'],
+ ["gc_concurrentmarksweep_count", 'ConcurrentMarkSweep', 'incremental'],
+ ["gc_ps_scavenge_count", 'PS Scavenge', 'incremental'],
+ ["gc_ps_marksweep_count", 'PS MarkSweep', 'incremental'],
+ ["gc_g1_young_generation_count", 'G1 Young Generation', 'incremental'],
+ ["gc_g1_old_generation_count", 'G1 Old Generation', 'incremental'],
+ ]
+ },
'heap': {
'options': [None, "Heap Memory Usage", "KB", "heap memory", "springboot.heap", "area"],
'lines': [
["heap_committed", 'committed', "absolute"],
["heap_used", 'used', "absolute"],
- ]},
+ ]
+ }
}
+
class ExtraChartError(ValueError):
pass
+
class Service(UrlService):
def __init__(self, configuration=None, name=None):
UrlService.__init__(self, configuration=configuration, name=name)
@@ -87,11 +95,11 @@ class Service(UrlService):
return None
result = {
- 'resp_1xx': 0,
- 'resp_2xx': 0,
- 'resp_3xx': 0,
- 'resp_4xx': 0,
- 'resp_5xx': 0,
+ 'resp_1xx': 0,
+ 'resp_2xx': 0,
+ 'resp_3xx': 0,
+ 'resp_4xx': 0,
+ 'resp_5xx': 0,
'resp_other': 0,
}
@@ -121,14 +129,14 @@ class Service(UrlService):
self.order.append(extra['id'])
def _add_extra_chart(self, chart):
- chart_id = chart.get('id', None) or die('id is not defined in extra chart')
- options = chart.get('options', None) or die('option is not defined in extra chart: %s' % chart_id)
- lines = chart.get('lines', None) or die('lines is not defined in extra chart: %s' % chart_id)
-
- title = options.get('title', None) or die('title is missing: %s' % chart_id)
- units = options.get('units', None) or die('units is missing: %s' % chart_id)
- family = options.get('family', title)
- context = options.get('context', 'springboot.' + title)
+ chart_id = chart.get('id', None) or self.die('id is not defined in extra chart')
+ options = chart.get('options', None) or self.die('option is not defined in extra chart: %s' % chart_id)
+ lines = chart.get('lines', None) or self.die('lines is not defined in extra chart: %s' % chart_id)
+
+ title = options.get('title', None) or self.die('title is missing: %s' % chart_id)
+ units = options.get('units', None) or self.die('units is missing: %s' % chart_id)
+ family = options.get('family', title)
+ context = options.get('context', 'springboot.' + title)
charttype = options.get('charttype', 'line')
result = {
@@ -137,11 +145,11 @@ class Service(UrlService):
}
for line in lines:
- dimension = line.get('dimension', None) or die('dimension is missing: %s' % chart_id)
- name = line.get('name', dimension)
- algorithm = line.get('algorithm', 'absolute')
+ dimension = line.get('dimension', None) or self.die('dimension is missing: %s' % chart_id)
+ name = line.get('name', dimension)
+ algorithm = line.get('algorithm', 'absolute')
multiplier = line.get('multiplier', 1)
- divisor = line.get('divisor', 1)
+ divisor = line.get('divisor', 1)
result['lines'].append([dimension, name, algorithm, multiplier, divisor])
self.definitions[chart_id] = result
diff --git a/conf.d/python.d/springboot.conf b/collectors/python.d.plugin/springboot/springboot.conf
index 40b5fb437..40b5fb437 100644
--- a/conf.d/python.d/springboot.conf
+++ b/collectors/python.d.plugin/springboot/springboot.conf
diff --git a/collectors/python.d.plugin/squid/Makefile.inc b/collectors/python.d.plugin/squid/Makefile.inc
new file mode 100644
index 000000000..76ecff81e
--- /dev/null
+++ b/collectors/python.d.plugin/squid/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += squid/squid.chart.py
+dist_pythonconfig_DATA += squid/squid.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += squid/README.md squid/Makefile.inc
+
diff --git a/collectors/python.d.plugin/squid/README.md b/collectors/python.d.plugin/squid/README.md
new file mode 100644
index 000000000..9c9b62f27
--- /dev/null
+++ b/collectors/python.d.plugin/squid/README.md
@@ -0,0 +1,38 @@
+# squid
+
+This module will monitor one or more squid instances depending on configuration.
+
+It produces following charts:
+
+1. **Client Bandwidth** in kilobits/s
+ * in
+ * out
+ * hits
+
+2. **Client Requests** in requests/s
+ * requests
+ * hits
+ * errors
+
+3. **Server Bandwidth** in kilobits/s
+ * in
+ * out
+
+4. **Server Requests** in requests/s
+ * requests
+ * errors
+
+### configuration
+
+```yaml
+priority : 50000
+
+local:
+ request : 'cache_object://localhost:3128/counters'
+ host : 'localhost'
+ port : 3128
+```
+
+Without any configuration module will try to autodetect where squid presents its `counters` data
+
+---
diff --git a/python.d/squid.chart.py b/collectors/python.d.plugin/squid/squid.chart.py
index ba8f982ff..fd54168f0 100644
--- a/python.d/squid.chart.py
+++ b/collectors/python.d.plugin/squid/squid.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: squid netdata python.d module
# Author: Pawel Krupa (paulfantom)
+# SPDX-License-Identifier: GPL-3.0-or-later
from bases.FrameworkServices.SocketService import SocketService
@@ -15,31 +16,35 @@ ORDER = ['clients_net', 'clients_requests', 'servers_net', 'servers_requests']
CHARTS = {
'clients_net': {
- 'options': [None, "Squid Client Bandwidth", "kilobits/s", "clients", "squid.clients_net", "area"],
+ 'options': [None, 'Squid Client Bandwidth', 'kilobits/s', 'clients', 'squid.clients_net', 'area'],
'lines': [
- ["client_http_kbytes_in", "in", "incremental", 8, 1],
- ["client_http_kbytes_out", "out", "incremental", -8, 1],
- ["client_http_hit_kbytes_out", "hits", "incremental", -8, 1]
- ]},
+ ['client_http_kbytes_in', 'in', 'incremental', 8, 1],
+ ['client_http_kbytes_out', 'out', 'incremental', -8, 1],
+ ['client_http_hit_kbytes_out', 'hits', 'incremental', -8, 1]
+ ]
+ },
'clients_requests': {
- 'options': [None, "Squid Client Requests", "requests/s", "clients", "squid.clients_requests", 'line'],
+ 'options': [None, 'Squid Client Requests', 'requests/s', 'clients', 'squid.clients_requests', 'line'],
'lines': [
- ["client_http_requests", "requests", "incremental"],
- ["client_http_hits", "hits", "incremental"],
- ["client_http_errors", "errors", "incremental", -1, 1]
- ]},
+ ['client_http_requests', 'requests', 'incremental'],
+ ['client_http_hits', 'hits', 'incremental'],
+ ['client_http_errors', 'errors', 'incremental', -1, 1]
+ ]
+ },
'servers_net': {
- 'options': [None, "Squid Server Bandwidth", "kilobits/s", "servers", "squid.servers_net", "area"],
+ 'options': [None, 'Squid Server Bandwidth', 'kilobits/s', 'servers', 'squid.servers_net', 'area'],
'lines': [
- ["server_all_kbytes_in", "in", "incremental", 8, 1],
- ["server_all_kbytes_out", "out", "incremental", -8, 1]
- ]},
+ ['server_all_kbytes_in', 'in', 'incremental', 8, 1],
+ ['server_all_kbytes_out', 'out', 'incremental', -8, 1]
+ ]
+ },
'servers_requests': {
- 'options': [None, "Squid Server Requests", "requests/s", "servers", "squid.servers_requests", 'line'],
+ 'options': [None, 'Squid Server Requests', 'requests/s', 'servers', 'squid.servers_requests', 'line'],
'lines': [
- ["server_all_requests", "requests", "incremental"],
- ["server_all_errors", "errors", "incremental", -1, 1]
- ]}
+ ['server_all_requests', 'requests', 'incremental'],
+ ['server_all_errors', 'errors', 'incremental', -1, 1]
+ ]
+ }
}
@@ -47,8 +52,8 @@ class Service(SocketService):
def __init__(self, configuration=None, name=None):
SocketService.__init__(self, configuration=configuration, name=name)
self._keep_alive = True
- self.request = ""
- self.host = "localhost"
+ self.request = ''
+ self.host = 'localhost'
self.port = 3128
self.order = ORDER
self.definitions = CHARTS
@@ -62,43 +67,43 @@ class Service(SocketService):
data = dict()
try:
- raw = ""
+ raw = ''
for tmp in response.split('\r\n'):
- if tmp.startswith("sample_time"):
+ if tmp.startswith('sample_time'):
raw = tmp
break
if raw.startswith('<'):
- self.error("invalid data received")
+ self.error('invalid data received')
return None
for row in raw.split('\n'):
- if row.startswith(("client", "server.all")):
- tmp = row.split("=")
+ if row.startswith(('client', 'server.all')):
+ tmp = row.split('=')
data[tmp[0].replace('.', '_').strip(' ')] = int(tmp[1])
except (ValueError, AttributeError, TypeError):
- self.error("invalid data received")
+ self.error('invalid data received')
return None
if not data:
- self.error("no data received")
+ self.error('no data received')
return None
return data
def _check_raw_data(self, data):
header = data[:1024].lower()
- if "connection: keep-alive" in header:
+ if 'connection: keep-alive' in header:
self._keep_alive = True
else:
self._keep_alive = False
- if data[-7:] == "\r\n0\r\n\r\n" and "transfer-encoding: chunked" in header: # HTTP/1.1 response
- self.debug("received full response from squid")
+ if data[-7:] == '\r\n0\r\n\r\n' and 'transfer-encoding: chunked' in header: # HTTP/1.1 response
+ self.debug('received full response from squid')
return True
- self.debug("waiting more data from squid")
+ self.debug('waiting more data from squid')
return False
def check(self):
@@ -109,10 +114,10 @@ class Service(SocketService):
self._parse_config()
# format request
req = self.request.decode()
- if not req.startswith("GET"):
- req = "GET " + req
- if not req.endswith(" HTTP/1.1\r\n\r\n"):
- req += " HTTP/1.1\r\n\r\n"
+ if not req.startswith('GET'):
+ req = 'GET ' + req
+ if not req.endswith(' HTTP/1.1\r\n\r\n'):
+ req += ' HTTP/1.1\r\n\r\n'
self.request = req.encode()
if self._get_data() is not None:
return True
diff --git a/conf.d/python.d/squid.conf b/collectors/python.d.plugin/squid/squid.conf
index 564187f00..564187f00 100644
--- a/conf.d/python.d/squid.conf
+++ b/collectors/python.d.plugin/squid/squid.conf
diff --git a/collectors/python.d.plugin/tomcat/Makefile.inc b/collectors/python.d.plugin/tomcat/Makefile.inc
new file mode 100644
index 000000000..940a7835e
--- /dev/null
+++ b/collectors/python.d.plugin/tomcat/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += tomcat/tomcat.chart.py
+dist_pythonconfig_DATA += tomcat/tomcat.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += tomcat/README.md tomcat/Makefile.inc
+
diff --git a/collectors/python.d.plugin/tomcat/README.md b/collectors/python.d.plugin/tomcat/README.md
new file mode 100644
index 000000000..e548bd338
--- /dev/null
+++ b/collectors/python.d.plugin/tomcat/README.md
@@ -0,0 +1,33 @@
+# tomcat
+
+Present tomcat containers memory utilization.
+
+Charts:
+
+1. **Requests** per second
+ * accesses
+
+2. **Volume** in KB/s
+ * volume
+
+3. **Threads**
+ * current
+ * busy
+
+4. **JVM Free Memory** in MB
+ * jvm
+
+### configuration
+
+```yaml
+localhost:
+ name : 'local'
+ url : 'http://127.0.0.1:8080/manager/status?XML=true'
+ user : 'tomcat_username'
+ pass : 'secret_tomcat_password'
+```
+
+Without configuration, module attempts to connect to `http://localhost:8080/manager/status?XML=true`, without any credentials.
+So it will probably fail.
+
+---
diff --git a/python.d/tomcat.chart.py b/collectors/python.d.plugin/tomcat/tomcat.chart.py
index a570d5643..3c2d0ed40 100644
--- a/python.d/tomcat.chart.py
+++ b/collectors/python.d.plugin/tomcat/tomcat.chart.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
# Description: tomcat netdata python.d module
# Author: Pawel Krupa (paulfantom)
+# Author: Wei He (Wing924)
+# SPDX-License-Identifier: GPL-3.0-or-later
import xml.etree.ElementTree as ET
@@ -16,67 +18,75 @@ ORDER = ['accesses', 'bandwidth', 'processing_time', 'threads', 'jvm', 'jvm_eden
CHARTS = {
'accesses': {
- 'options': [None, "Requests", "requests/s", "statistics", "tomcat.accesses", "area"],
+ 'options': [None, 'Requests', 'requests/s', 'statistics', 'tomcat.accesses', 'area'],
'lines': [
- ["requestCount", 'accesses', 'incremental'],
- ["errorCount", 'errors', 'incremental'],
- ]},
+ ['requestCount', 'accesses', 'incremental'],
+ ['errorCount', 'errors', 'incremental'],
+ ]
+ },
'bandwidth': {
- 'options': [None, "Bandwidth", "KB/s", "statistics", "tomcat.bandwidth", "area"],
+ 'options': [None, 'Bandwidth', 'KB/s', 'statistics', 'tomcat.bandwidth', 'area'],
'lines': [
- ["bytesSent", 'sent', 'incremental', 1, 1024],
- ["bytesReceived", 'received', 'incremental', 1, 1024],
- ]},
+ ['bytesSent', 'sent', 'incremental', 1, 1024],
+ ['bytesReceived', 'received', 'incremental', 1, 1024],
+ ]
+ },
'processing_time': {
- 'options': [None, "processing time", "seconds", "statistics", "tomcat.processing_time", "area"],
+ 'options': [None, 'processing time', 'seconds', 'statistics', 'tomcat.processing_time', 'area'],
'lines': [
- ["processingTime", 'processing time', 'incremental', 1, 1000]
- ]},
+ ['processingTime', 'processing time', 'incremental', 1, 1000]
+ ]
+ },
'threads': {
- 'options': [None, "Threads", "current threads", "statistics", "tomcat.threads", "area"],
+ 'options': [None, 'Threads', 'current threads', 'statistics', 'tomcat.threads', 'area'],
'lines': [
- ["currentThreadCount", 'current', "absolute"],
- ["currentThreadsBusy", 'busy', "absolute"]
- ]},
+ ['currentThreadCount', 'current', 'absolute'],
+ ['currentThreadsBusy', 'busy', 'absolute']
+ ]
+ },
'jvm': {
- 'options': [None, "JVM Memory Pool Usage", "MB", "memory", "tomcat.jvm", "stacked"],
+ 'options': [None, 'JVM Memory Pool Usage', 'MB', 'memory', 'tomcat.jvm', 'stacked'],
'lines': [
- ["free", 'free', "absolute", 1, 1048576],
- ["eden_used", 'eden', "absolute", 1, 1048576],
- ["survivor_used", 'survivor', "absolute", 1, 1048576],
- ["tenured_used", 'tenured', "absolute", 1, 1048576],
- ["code_cache_used", 'code cache', "absolute", 1, 1048576],
- ["compressed_used", 'compressed', "absolute", 1, 1048576],
- ["metaspace_used", 'metaspace', "absolute", 1, 1048576],
- ]},
+ ['free', 'free', 'absolute', 1, 1048576],
+ ['eden_used', 'eden', 'absolute', 1, 1048576],
+ ['survivor_used', 'survivor', 'absolute', 1, 1048576],
+ ['tenured_used', 'tenured', 'absolute', 1, 1048576],
+ ['code_cache_used', 'code cache', 'absolute', 1, 1048576],
+ ['compressed_used', 'compressed', 'absolute', 1, 1048576],
+ ['metaspace_used', 'metaspace', 'absolute', 1, 1048576],
+ ]
+ },
'jvm_eden': {
- 'options': [None, "Eden Memory Usage", "MB", "memory", "tomcat.jvm_eden", "area"],
+ 'options': [None, 'Eden Memory Usage', 'MB', 'memory', 'tomcat.jvm_eden', 'area'],
'lines': [
- ["eden_used", 'used', "absolute", 1, 1048576],
- ["eden_commited", 'commited', "absolute", 1, 1048576],
- ["eden_max", 'max', "absolute", 1, 1048576]
- ]},
+ ['eden_used', 'used', 'absolute', 1, 1048576],
+ ['eden_committed', 'committed', 'absolute', 1, 1048576],
+ ['eden_max', 'max', 'absolute', 1, 1048576]
+ ]
+ },
'jvm_survivor': {
- 'options': [None, "Survivor Memory Usage", "MB", "memory", "tomcat.jvm_survivor", "area"],
+ 'options': [None, 'Survivor Memory Usage', 'MB', 'memory', 'tomcat.jvm_survivor', 'area'],
'lines': [
- ["survivor_used", 'used', "absolute", 1, 1048576],
- ["survivor_commited", 'commited', "absolute", 1, 1048576],
- ["survivor_max", 'max', "absolute", 1, 1048576]
- ]},
+ ['survivor_used', 'used', 'absolute', 1, 1048576],
+ ['survivor_committed', 'committed', 'absolute', 1, 1048576],
+ ['survivor_max', 'max', 'absolute', 1, 1048576]
+ ]
+ },
'jvm_tenured': {
- 'options': [None, "Tenured Memory Usage", "MB", "memory", "tomcat.jvm_tenured", "area"],
+ 'options': [None, 'Tenured Memory Usage', 'MB', 'memory', 'tomcat.jvm_tenured', 'area'],
'lines': [
- ["tenured_used", 'used', "absolute", 1, 1048576],
- ["tenured_commited", 'commited', "absolute", 1, 1048576],
- ["tenured_max", 'max', "absolute", 1, 1048576]
- ]},
+ ['tenured_used', 'used', 'absolute', 1, 1048576],
+ ['tenured_committed', 'committed', 'absolute', 1, 1048576],
+ ['tenured_max', 'max', 'absolute', 1, 1048576]
+ ]
+ }
}
class Service(UrlService):
def __init__(self, configuration=None, name=None):
UrlService.__init__(self, configuration=configuration, name=name)
- self.url = self.configuration.get('url', "http://127.0.0.1:8080/manager/status?XML=true")
+ self.url = self.configuration.get('url', 'http://127.0.0.1:8080/manager/status?XML=true')
self.connector_name = self.configuration.get('connector_name', None)
self.order = ORDER
self.definitions = CHARTS
@@ -115,27 +125,27 @@ class Service(UrlService):
name = pool.get('name')
if 'Eden Space' in name:
data['eden_used'] = pool.get('usageUsed')
- data['eden_commited'] = pool.get('usageCommitted')
+ data['eden_committed'] = pool.get('usageCommitted')
data['eden_max'] = pool.get('usageMax')
elif 'Survivor Space' in name:
data['survivor_used'] = pool.get('usageUsed')
- data['survivor_commited'] = pool.get('usageCommitted')
+ data['survivor_committed'] = pool.get('usageCommitted')
data['survivor_max'] = pool.get('usageMax')
elif 'Tenured Gen' in name or 'Old Gen' in name:
data['tenured_used'] = pool.get('usageUsed')
- data['tenured_commited'] = pool.get('usageCommitted')
+ data['tenured_committed'] = pool.get('usageCommitted')
data['tenured_max'] = pool.get('usageMax')
elif name == 'Code Cache':
data['code_cache_used'] = pool.get('usageUsed')
- data['code_cache_commited'] = pool.get('usageCommitted')
+ data['code_cache_committed'] = pool.get('usageCommitted')
data['code_cache_max'] = pool.get('usageMax')
elif name == 'Compressed':
data['compressed_used'] = pool.get('usageUsed')
- data['compressed_commited'] = pool.get('usageCommitted')
+ data['compressed_committed'] = pool.get('usageCommitted')
data['compressed_max'] = pool.get('usageMax')
elif name == 'Metaspace':
data['metaspace_used'] = pool.get('usageUsed')
- data['metaspace_commited'] = pool.get('usageCommitted')
+ data['metaspace_committed'] = pool.get('usageCommitted')
data['metaspace_max'] = pool.get('usageMax')
if connector:
@@ -145,9 +155,9 @@ class Service(UrlService):
request_info = connector.find('requestInfo')
data['processingTime'] = request_info.get('processingTime')
- data['requestCount'] = request_info.get('requestCount')
- data['errorCount'] = request_info.get('errorCount')
- data['bytesReceived'] = request_info.get('bytesReceived')
- data['bytesSent'] = request_info.get('bytesSent')
+ data['requestCount'] = request_info.get('requestCount')
+ data['errorCount'] = request_info.get('errorCount')
+ data['bytesReceived'] = request_info.get('bytesReceived')
+ data['bytesSent'] = request_info.get('bytesSent')
return data or None
diff --git a/conf.d/python.d/tomcat.conf b/collectors/python.d.plugin/tomcat/tomcat.conf
index c63f06cfa..c63f06cfa 100644
--- a/conf.d/python.d/tomcat.conf
+++ b/collectors/python.d.plugin/tomcat/tomcat.conf
diff --git a/collectors/python.d.plugin/traefik/Makefile.inc b/collectors/python.d.plugin/traefik/Makefile.inc
new file mode 100644
index 000000000..926d56dda
--- /dev/null
+++ b/collectors/python.d.plugin/traefik/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += traefik/traefik.chart.py
+dist_pythonconfig_DATA += traefik/traefik.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += traefik/README.md traefik/Makefile.inc
+
diff --git a/collectors/python.d.plugin/traefik/README.md b/collectors/python.d.plugin/traefik/README.md
new file mode 100644
index 000000000..9b4a18208
--- /dev/null
+++ b/collectors/python.d.plugin/traefik/README.md
@@ -0,0 +1,54 @@
+# traefik
+
+Module uses the `health` API to provide statistics.
+
+It produces:
+
+1. **Responses** by statuses
+ * success (1xx, 2xx, 304)
+ * error (5xx)
+ * redirect (3xx except 304)
+ * bad (4xx)
+ * other (all other responses)
+
+2. **Responses** by codes
+ * 2xx (successful)
+ * 5xx (internal server errors)
+ * 3xx (redirect)
+ * 4xx (bad)
+ * 1xx (informational)
+ * other (non-standart responses)
+
+3. **Detailed Response Codes** requests/s (number of responses for each response code family individually)
+
+4. **Requests**/s
+ * request statistics
+
+5. **Total response time**
+ * sum of all response time
+
+6. **Average response time**
+
+7. **Average response time per iteration**
+
+8. **Uptime**
+ * Traefik server uptime
+
+### configuration
+
+Needs only `url` to server's `health`
+
+Here is an example for local server:
+
+```yaml
+update_every : 1
+priority : 60000
+
+local:
+ url : 'http://localhost:8080/health'
+ retries : 10
+```
+
+Without configuration, module attempts to connect to `http://localhost:8080/health`.
+
+---
diff --git a/python.d/traefik.chart.py b/collectors/python.d.plugin/traefik/traefik.chart.py
index f7c3e223b..dc8933220 100644
--- a/python.d/traefik.chart.py
+++ b/collectors/python.d.plugin/traefik/traefik.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: traefik netdata python.d module
# Author: Alexandre Menezes (@ale_menezes)
+# SPDX-License-Identifier: GPL-3.0-or-later
from json import loads
from collections import defaultdict
@@ -32,7 +33,8 @@ CHARTS = {
['redirects', 'redirect', 'incremental'],
['bad_requests', 'bad', 'incremental'],
['other_requests', 'other', 'incremental']
- ]},
+ ]
+ },
'response_codes': {
'options': [None, 'Responses by codes', 'requests/s', 'responses', 'traefik.response_codes', 'stacked'],
'lines': [
@@ -42,37 +44,45 @@ CHARTS = {
['4xx', None, 'incremental'],
['1xx', None, 'incremental'],
['other', None, 'incremental']
- ]},
+ ]
+ },
'detailed_response_codes': {
- 'options': [None, 'Detailed response codes', 'requests/s', 'responses', 'traefik.detailed_response_codes', 'stacked'],
- 'lines': [
- ]},
+ 'options': [None, 'Detailed response codes', 'requests/s', 'responses', 'traefik.detailed_response_codes',
+ 'stacked'],
+ 'lines': []
+ },
'requests': {
'options': [None, 'Requests', 'requests/s', 'requests', 'traefik.requests', 'line'],
'lines': [
['total_count', 'requests', 'incremental']
- ]},
+ ]
+ },
'total_response_time': {
'options': [None, 'Total response time', 'seconds', 'timings', 'traefik.total_response_time', 'line'],
'lines': [
['total_response_time_sec', 'response', 'absolute', 1, 10000]
- ]},
+ ]
+ },
'average_response_time': {
'options': [None, 'Average response time', 'milliseconds', 'timings', 'traefik.average_response_time', 'line'],
'lines': [
['average_response_time_sec', 'response', 'absolute', 1, 1000]
- ]},
+ ]
+ },
'average_response_time_per_iteration': {
- 'options': [None, 'Average response time per iteration', 'milliseconds', 'timings', 'traefik.average_response_time_per_iteration', 'line'],
+ 'options': [None, 'Average response time per iteration', 'milliseconds', 'timings',
+ 'traefik.average_response_time_per_iteration', 'line'],
'lines': [
['average_response_time_per_iteration_sec', 'response', 'incremental', 1, 10000]
- ]},
+ ]
+ },
'uptime': {
'options': [None, 'Uptime', 'seconds', 'uptime', 'traefik.uptime', 'line'],
'lines': [
['uptime_sec', 'uptime', 'absolute']
- ]}
+ ]
}
+}
HEALTH_STATS = [
'uptime_sec',
@@ -82,6 +92,7 @@ HEALTH_STATS = [
'total_status_code_count'
]
+
class Service(UrlService):
def __init__(self, configuration=None, name=None):
UrlService.__init__(self, configuration=configuration, name=name)
@@ -116,9 +127,11 @@ class Service(UrlService):
self.data['average_response_time_sec'] *= 1000000
self.data['total_response_time_sec'] *= 10000
if data['total_count'] != self.last_total_count:
- self.data['average_response_time_per_iteration_sec'] = (data['total_response_time_sec'] - self.last_total_response_time) * 1000000 / (data['total_count'] - self.last_total_count)
+ self.data['average_response_time_per_iteration_sec'] = \
+ (data['total_response_time_sec'] - self.last_total_response_time) * \
+ 1000000 / (data['total_count'] - self.last_total_count)
else:
- self.data['average_response_time_per_iteration_sec'] = 0
+ self.data['average_response_time_per_iteration_sec'] = 0
self.last_total_response_time = data['total_response_time_sec']
self.last_total_count = data['total_count']
@@ -165,6 +178,7 @@ class Service(UrlService):
self.charts['detailed_response_codes'].add_dimension([code, code, 'incremental'])
self.data[code] = value
+
def fetch_data_(raw_data, metrics):
data = dict()
diff --git a/conf.d/python.d/traefik.conf b/collectors/python.d.plugin/traefik/traefik.conf
index 909b9e549..909b9e549 100644
--- a/conf.d/python.d/traefik.conf
+++ b/collectors/python.d.plugin/traefik/traefik.conf
diff --git a/collectors/python.d.plugin/unbound/Makefile.inc b/collectors/python.d.plugin/unbound/Makefile.inc
new file mode 100644
index 000000000..59c306aed
--- /dev/null
+++ b/collectors/python.d.plugin/unbound/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += unbound/unbound.chart.py
+dist_pythonconfig_DATA += unbound/unbound.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += unbound/README.md unbound/Makefile.inc
+
diff --git a/collectors/python.d.plugin/unbound/README.md b/collectors/python.d.plugin/unbound/README.md
new file mode 100644
index 000000000..3b4fa16fd
--- /dev/null
+++ b/collectors/python.d.plugin/unbound/README.md
@@ -0,0 +1,76 @@
+# unbound
+
+Monitoring uses the remote control interface to fetch statistics.
+
+Provides the following charts:
+
+1. **Queries Processed**
+ * Ratelimited
+ * Cache Misses
+ * Cache Hits
+ * Expired
+ * Prefetched
+ * Recursive
+
+2. **Request List**
+ * Average Size
+ * Max Size
+ * Overwritten Requests
+ * Overruns
+ * Current Size
+ * User Requests
+
+3. **Recursion Timings**
+ * Average recursion processing time
+ * Median recursion processing time
+
+If extended stats are enabled, also provides:
+
+4. **Cache Sizes**
+ * Message Cache
+ * RRset Cache
+ * Infra Cache
+ * DNSSEC Key Cache
+ * DNSCrypt Shared Secret Cache
+ * DNSCrypt Nonce Cache
+
+### configuration
+
+Unbound must be manually configured to enable the remote-control protocol.
+Check the Unbound documentation for info on how to do this. Additionally,
+if you want to take advantage of the autodetection this plugin offers,
+you will need to make sure your `unbound.conf` file only uses spaces for
+indentation (the default config shipped by most distributions uses tabs
+instead of spaces).
+
+Once you have the Unbound control protocol enabled, you need to make sure
+that either the certificate and key are readable by Netdata (if you're
+using the regular control interface), or that the socket is accessible
+to Netdata (if you're using a UNIX socket for the contorl interface).
+
+By default, for the local system, everything can be auto-detected
+assuming Unbound is configured correctly and has been told to listen
+on the loopback interface or a UNIX socket. This is done by looking
+up info in the Unbound config file specified by the `ubconf` key.
+
+To enable extended stats for a given job, add `extended: yes` to the
+definition.
+
+You can also enable per-thread charts for a given job by adding
+`per_thread: yes` to the definition. Note that the numbe rof threads
+is only checked on startup.
+
+A basic local configuration with extended statistics and per-thread
+charts looks like this:
+
+```yaml
+local:
+ ubconf: /etc/unbound/unbound.conf
+ extended: yes
+ per_thread: yes
+```
+
+While it's a bit more complicated to set up correctly, it is recommended
+that you use a UNIX socket as it provides far better performance.
+
+---
diff --git a/collectors/python.d.plugin/unbound/unbound.chart.py b/collectors/python.d.plugin/unbound/unbound.chart.py
new file mode 100644
index 000000000..52fcbf7e2
--- /dev/null
+++ b/collectors/python.d.plugin/unbound/unbound.chart.py
@@ -0,0 +1,275 @@
+# -*- coding: utf-8 -*-
+# Description: unbound netdata python.d module
+# Author: Austin S. Hemmelgarn (Ferroin)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import os
+import sys
+
+from copy import deepcopy
+
+from bases.FrameworkServices.SocketService import SocketService
+from bases.loaders import YamlOrderedLoader
+
+PRECISION = 1000
+
+ORDER = ['queries', 'recursion', 'reqlist']
+
+CHARTS = {
+ 'queries': {
+ 'options': [None, 'Queries Processed', 'queries', 'Unbound', 'unbound.queries', 'line'],
+ 'lines': [
+ ['ratelimit', 'ratelimited', 'absolute', 1, 1],
+ ['cachemiss', 'cache_miss', 'absolute', 1, 1],
+ ['cachehit', 'cache_hit', 'absolute', 1, 1],
+ ['expired', 'expired', 'absolute', 1, 1],
+ ['prefetch', 'prefetched', 'absolute', 1, 1],
+ ['recursive', 'recursive', 'absolute', 1, 1]
+ ]
+ },
+ 'recursion': {
+ 'options': [None, 'Recursion Timings', 'seconds', 'Unbound', 'unbound.recursion', 'line'],
+ 'lines': [
+ ['recursive_avg', 'average', 'absolute', 1, PRECISION],
+ ['recursive_med', 'median', 'absolute', 1, PRECISION]
+ ]
+ },
+ 'reqlist': {
+ 'options': [None, 'Request List', 'items', 'Unbound', 'unbound.reqlist', 'line'],
+ 'lines': [
+ ['reqlist_avg', 'average_size', 'absolute', 1, 1],
+ ['reqlist_max', 'maximum_size', 'absolute', 1, 1],
+ ['reqlist_overwritten', 'overwritten_requests', 'absolute', 1, 1],
+ ['reqlist_exceeded', 'overruns', 'absolute', 1, 1],
+ ['reqlist_current', 'current_size', 'absolute', 1, 1],
+ ['reqlist_user', 'user_requests', 'absolute', 1, 1]
+ ]
+ }
+}
+
+# These get added too if we are told to use extended stats.
+EXTENDED_ORDER = ['cache']
+
+EXTENDED_CHARTS = {
+ 'cache': {
+ 'options': [None, 'Cache Sizes', 'items', 'Unbound', 'unbound.cache', 'stacked'],
+ 'lines': [
+ ['cache_message', 'message_cache', 'absolute', 1, 1],
+ ['cache_rrset', 'rrset_cache', 'absolute', 1, 1],
+ ['cache_infra', 'infra_cache', 'absolute', 1, 1],
+ ['cache_key', 'dnssec_key_cache', 'absolute', 1, 1],
+ ['cache_dnscss', 'dnscrypt_Shared_Secret_cache', 'absolute', 1, 1],
+ ['cache_dnscn', 'dnscrypt_Nonce_cache', 'absolute', 1, 1]
+ ]
+ }
+}
+
+# This is used as a templates for the per-thread charts.
+PER_THREAD_CHARTS = {
+ '_queries': {
+ 'options': [None, '{longname} Queries Processed', 'queries', 'Queries Processed',
+ 'unbound.threads.queries', 'line'],
+ 'lines': [
+ ['{shortname}_ratelimit', 'ratelimited', 'absolute', 1, 1],
+ ['{shortname}_cachemiss', 'cache_miss', 'absolute', 1, 1],
+ ['{shortname}_cachehit', 'cache_hit', 'absolute', 1, 1],
+ ['{shortname}_expired', 'expired', 'absolute', 1, 1],
+ ['{shortname}_prefetch', 'prefetched', 'absolute', 1, 1],
+ ['{shortname}_recursive', 'recursive', 'absolute', 1, 1]
+ ]
+ },
+ '_recursion': {
+ 'options': [None, '{longname} Recursion Timings', 'seconds', 'Recursive Timings',
+ 'unbound.threads.recursion', 'line'],
+ 'lines': [
+ ['{shortname}_recursive_avg', 'average', 'absolute', 1, PRECISION],
+ ['{shortname}_recursive_med', 'median', 'absolute', 1, PRECISION]
+ ]
+ },
+ '_reqlist': {
+ 'options': [None, '{longname} Request List', 'items', 'Request List', 'unbound.threads.reqlist', 'line'],
+ 'lines': [
+ ['{shortname}_reqlist_avg', 'average_size', 'absolute', 1, 1],
+ ['{shortname}_reqlist_max', 'maximum_size', 'absolute', 1, 1],
+ ['{shortname}_reqlist_overwritten', 'overwritten_requests', 'absolute', 1, 1],
+ ['{shortname}_reqlist_exceeded', 'overruns', 'absolute', 1, 1],
+ ['{shortname}_reqlist_current', 'current_size', 'absolute', 1, 1],
+ ['{shortname}_reqlist_user', 'user_requests', 'absolute', 1, 1]
+ ]
+ }
+}
+
+
+# This maps the Unbound stat names to our names and precision requiremnets.
+STAT_MAP = {
+ 'total.num.queries_ip_ratelimited': ('ratelimit', 1),
+ 'total.num.cachehits': ('cachehit', 1),
+ 'total.num.cachemiss': ('cachemiss', 1),
+ 'total.num.zero_ttl': ('expired', 1),
+ 'total.num.prefetch': ('prefetch', 1),
+ 'total.num.recursivereplies': ('recursive', 1),
+ 'total.requestlist.avg': ('reqlist_avg', 1),
+ 'total.requestlist.max': ('reqlist_max', 1),
+ 'total.requestlist.overwritten': ('reqlist_overwritten', 1),
+ 'total.requestlist.exceeded': ('reqlist_exceeded', 1),
+ 'total.requestlist.current.all': ('reqlist_current', 1),
+ 'total.requestlist.current.user': ('reqlist_user', 1),
+ 'total.recursion.time.avg': ('recursive_avg', PRECISION),
+ 'total.recursion.time.median': ('recursive_med', PRECISION),
+ 'msg.cache.count': ('cache_message', 1),
+ 'rrset.cache.count': ('cache_rrset', 1),
+ 'infra.cache.count': ('cache_infra', 1),
+ 'key.cache.count': ('cache_key', 1),
+ 'dnscrypt_shared_secret.cache.count': ('cache_dnscss', 1),
+ 'dnscrypt_nonce.cache.count': ('cache_dnscn', 1)
+}
+
+# Same as above, but for per-thread stats.
+PER_THREAD_STAT_MAP = {
+ '{shortname}.num.queries_ip_ratelimited': ('{shortname}_ratelimit', 1),
+ '{shortname}.num.cachehits': ('{shortname}_cachehit', 1),
+ '{shortname}.num.cachemiss': ('{shortname}_cachemiss', 1),
+ '{shortname}.num.zero_ttl': ('{shortname}_expired', 1),
+ '{shortname}.num.prefetch': ('{shortname}_prefetch', 1),
+ '{shortname}.num.recursivereplies': ('{shortname}_recursive', 1),
+ '{shortname}.requestlist.avg': ('{shortname}_reqlist_avg', 1),
+ '{shortname}.requestlist.max': ('{shortname}_reqlist_max', 1),
+ '{shortname}.requestlist.overwritten': ('{shortname}_reqlist_overwritten', 1),
+ '{shortname}.requestlist.exceeded': ('{shortname}_reqlist_exceeded', 1),
+ '{shortname}.requestlist.current.all': ('{shortname}_reqlist_current', 1),
+ '{shortname}.requestlist.current.user': ('{shortname}_reqlist_user', 1),
+ '{shortname}.recursion.time.avg': ('{shortname}_recursive_avg', PRECISION),
+ '{shortname}.recursion.time.median': ('{shortname}_recursive_med', PRECISION)
+}
+
+
+# Used to actually generate per-thread charts.
+def _get_perthread_info(thread):
+ sname = 'thread{0}'.format(thread)
+ lname = 'Thread {0}'.format(thread)
+ charts = dict()
+ order = []
+ statmap = dict()
+
+ for item in PER_THREAD_CHARTS:
+ cname = '{0}{1}'.format(sname, item)
+ chart = deepcopy(PER_THREAD_CHARTS[item])
+ chart['options'][1] = chart['options'][1].format(longname=lname)
+
+ for index, line in enumerate(chart['lines']):
+ chart['lines'][index][0] = line[0].format(shortname=sname)
+
+ order.append(cname)
+ charts[cname] = chart
+
+ for key, value in PER_THREAD_STAT_MAP.items():
+ statmap[key.format(shortname=sname)] = (value[0].format(shortname=sname), value[1])
+
+ return (charts, order, statmap)
+
+
+class Service(SocketService):
+ def __init__(self, configuration=None, name=None):
+ # The unbound control protocol is always TLS encapsulated
+ # unless it's used over a UNIX socket, so enable TLS _before_
+ # doing the normal SocketService initialization.
+ configuration['tls'] = True
+ self.port = 8935
+ SocketService.__init__(self, configuration, name)
+ self.ext = self.configuration.get('extended', None)
+ self.ubconf = self.configuration.get('ubconf', None)
+ self.perthread = self.configuration.get('per_thread', False)
+ self.threads = None
+ self.order = deepcopy(ORDER)
+ self.definitions = deepcopy(CHARTS)
+ self.request = 'UBCT1 stats\n'
+ self.statmap = deepcopy(STAT_MAP)
+ self._parse_config()
+ self._auto_config()
+ self.debug('Extended stats: {0}'.format(self.ext))
+ self.debug('Per-thread stats: {0}'.format(self.perthread))
+ if self.ext:
+ self.order = self.order + EXTENDED_ORDER
+ self.definitions.update(EXTENDED_CHARTS)
+ if self.unix_socket:
+ self.debug('Using unix socket: {0}'.format(self.unix_socket))
+ else:
+ self.debug('Connecting to: {0}:{1}'.format(self.host, self.port))
+ self.debug('Using key: {0}'.format(self.key))
+ self.debug('Using certificate: {0}'.format(self.cert))
+
+ def _auto_config(self):
+ if self.ubconf and os.access(self.ubconf, os.R_OK):
+ self.debug('Unbound config: {0}'.format(self.ubconf))
+ conf = YamlOrderedLoader.load_config_from_file(self.ubconf)[0]
+ if self.ext is None:
+ if 'extended-statistics' in conf['server']:
+ self.ext = conf['server']['extended-statistics']
+ if 'remote-control' in conf:
+ if conf['remote-control'].get('control-use-cert', False):
+ self.key = self.key or conf['remote-control'].get('control-key-file')
+ self.cert = self.cert or conf['remote-control'].get('control-cert-file')
+ self.port = self.port or conf['remote-control'].get('control-port')
+ else:
+ self.unix_socket = self.unix_socket or conf['remote-control'].get('control-interface')
+ else:
+ self.debug('Unbound configuration not found.')
+ if not self.key:
+ self.key = '/etc/unbound/unbound_control.key'
+ if not self.cert:
+ self.cert = '/etc/unbound/unbound_control.pem'
+ if not self.port:
+ self.port = 8953
+
+ def _generate_perthread_charts(self):
+ tmporder = list()
+ for thread in range(0, self.threads):
+ charts, order, statmap = _get_perthread_info(thread)
+ tmporder.extend(order)
+ self.definitions.update(charts)
+ self.statmap.update(statmap)
+ self.order.extend(sorted(tmporder))
+
+ def check(self):
+ # Check if authentication is working.
+ self._connect()
+ result = bool(self._sock)
+ self._disconnect()
+ # If auth works, and we need per-thread charts, query the server
+ # to see how many threads it's using. This somewhat abuses the
+ # SocketService API to get the data we need.
+ if result and self.perthread:
+ tmp = self.request
+ if sys.version_info[0] < 3:
+ self.request = 'UBCT1 status\n'
+ else:
+ self.request = b'UBCT1 status\n'
+ raw = self._get_raw_data()
+ for line in raw.splitlines():
+ if line.startswith('threads'):
+ self.threads = int(line.split()[1])
+ self._generate_perthread_charts()
+ break
+ if self.threads is None:
+ self.info('Unable to auto-detect thread counts, disabling per-thread stats.')
+ self.perthread = False
+ self.request = tmp
+ return result
+
+ @staticmethod
+ def _check_raw_data(data):
+ # The server will close the connection when it's done sending
+ # data, so just keep looping until that happens.
+ return False
+
+ def _get_data(self):
+ raw = self._get_raw_data()
+ data = dict()
+ tmp = dict()
+ for line in raw.splitlines():
+ stat = line.split('=')
+ tmp[stat[0]] = stat[1]
+ for item in self.statmap:
+ if item in tmp:
+ data[self.statmap[item][0]] = float(tmp[item]) * self.statmap[item][1]
+ return data
diff --git a/collectors/python.d.plugin/unbound/unbound.conf b/collectors/python.d.plugin/unbound/unbound.conf
new file mode 100644
index 000000000..46c4b097f
--- /dev/null
+++ b/collectors/python.d.plugin/unbound/unbound.conf
@@ -0,0 +1,87 @@
+# netdata python.d.plugin configuration for unbound
+#
+# 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_everye
+# and only if the module has collected values in the past.
+# retries: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# Additionally to the above, unbound also supports the following:
+#
+# host: localhost # The host to connect to.
+# port: 8953 # WHat port to use (defaults to 8953)
+# socket: /path/to/socket # A path to a UNIX socket to use instead
+# # of a TCP connection
+# tls_key_file: /path/to/key # The key file to use for authentication
+# tls_cert_file: /path/to/key # The certificate to use for authentication
+# extended: false # Whether to collect extended stats or not
+# per_thread: false # Whether to show charts for per-thread stats
+#
+# In addition to the above, you can set the following to try and
+# auto-detect most settings based on the unbound configuration:
+#
+# ubconf: /etc/unbound/unbound.conf
+#
+# Note that the SSL key and certificate need to be readable by the user
+# unbound runs as if you're using the regular control interface.
+# If you're using a UNIX socket, that has to be readable by the netdata user.
+
+# The following should work for most users if they have unbound configured
+# correctly.
+local:
+ ubconf: /etc/unbound/unbound.conf
diff --git a/collectors/python.d.plugin/uwsgi/Makefile.inc b/collectors/python.d.plugin/uwsgi/Makefile.inc
new file mode 100644
index 000000000..75d96de0e
--- /dev/null
+++ b/collectors/python.d.plugin/uwsgi/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += uwsgi/uwsgi.chart.py
+dist_pythonconfig_DATA += uwsgi/uwsgi.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += uwsgi/README.md uwsgi/Makefile.inc
+
diff --git a/collectors/python.d.plugin/uwsgi/README.md b/collectors/python.d.plugin/uwsgi/README.md
new file mode 100644
index 000000000..a062710df
--- /dev/null
+++ b/collectors/python.d.plugin/uwsgi/README.md
@@ -0,0 +1,37 @@
+# uwsgi
+
+Module monitor uwsgi performance metrics.
+
+https://uwsgi-docs.readthedocs.io/en/latest/StatsServer.html
+
+lines are creates dynamically based on how many workers are there
+
+Following charts are drawn:
+
+1. **Requests**
+ * requests per second
+ * transmitted data
+ * average request time
+
+2. **Memory**
+ * rss
+ * vsz
+
+3. **Exceptions**
+4. **Harakiris**
+5. **Respawns**
+
+### configuration
+
+```yaml
+socket:
+ name : 'local'
+ socket : '/tmp/stats.socket'
+
+localhost:
+ name : 'local'
+ host : 'localhost'
+ port : 1717
+```
+
+When no configuration file is found, module tries to connect to TCP/IP socket: `localhost:1717`.
diff --git a/collectors/python.d.plugin/uwsgi/uwsgi.chart.py b/collectors/python.d.plugin/uwsgi/uwsgi.chart.py
new file mode 100644
index 000000000..5ebcfb55b
--- /dev/null
+++ b/collectors/python.d.plugin/uwsgi/uwsgi.chart.py
@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+# Description: uwsgi netdata python.d module
+# Author: Robbert Segeren (robbert-ef)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import json
+from copy import deepcopy
+from bases.FrameworkServices.SocketService import SocketService
+
+# default module values (can be overridden per job in `config`)
+# update_every = 2
+priority = 60000
+retries = 60
+
+ORDER = [
+ 'requests',
+ 'tx',
+ 'avg_rt',
+ 'memory_rss',
+ 'memory_vsz',
+ 'exceptions',
+ 'harakiri',
+ 'respawn',
+]
+
+DYNAMIC_CHARTS = [
+ 'requests',
+ 'tx',
+ 'avg_rt',
+ 'memory_rss',
+ 'memory_vsz',
+]
+
+# NOTE: lines are created dynamically in `check()` method
+CHARTS = {
+ 'requests': {
+ 'options': [None, 'Requests', 'requests/s', 'requests', 'uwsgi.requests', 'stacked'],
+ 'lines': [
+ ['requests', 'requests', 'incremental']
+ ]
+ },
+ 'tx': {
+ 'options': [None, 'Transmitted data', 'KB/s', 'requests', 'uwsgi.tx', 'stacked'],
+ 'lines': [
+ ['tx', 'tx', 'incremental']
+ ]
+ },
+ 'avg_rt': {
+ 'options': [None, 'Average request time', 'ms', 'requests', 'uwsgi.avg_rt', 'line'],
+ 'lines': [
+ ['avg_rt', 'avg_rt', 'absolute']
+ ]
+ },
+ 'memory_rss': {
+ 'options': [None, 'RSS (Resident Set Size)', 'MB', 'memory', 'uwsgi.memory_rss', 'stacked'],
+ 'lines': [
+ ['memory_rss', 'memory_rss', 'absolute', 1, 1024 * 1024]
+ ]
+ },
+ 'memory_vsz': {
+ 'options': [None, 'VSZ (Virtual Memory Size)', 'MB', 'memory', 'uwsgi.memory_vsz', 'stacked'],
+ 'lines': [
+ ['memory_vsz', 'memory_vsz', 'absolute', 1, 1024 * 1024]
+ ]
+ },
+ 'exceptions': {
+ 'options': [None, 'Exceptions', 'exceptions', 'exceptions', 'uwsgi.exceptions', 'line'],
+ 'lines': [
+ ['exceptions', 'exceptions', 'incremental']
+ ]
+ },
+ 'harakiri': {
+ 'options': [None, 'Harakiris', 'harakiris', 'harakiris', 'uwsgi.harakiris', 'line'],
+ 'lines': [
+ ['harakiri_count', 'harakiris', 'incremental']
+ ]
+ },
+ 'respawn': {
+ 'options': [None, 'Respawns', 'respawns', 'respawns', 'uwsgi.respawns', 'line'],
+ 'lines': [
+ ['respawn_count', 'respawns', 'incremental']
+ ]
+ },
+}
+
+
+class Service(SocketService):
+ def __init__(self, configuration=None, name=None):
+ super(Service, self).__init__(configuration=configuration, name=name)
+ self.url = self.configuration.get('host', 'localhost')
+ self.port = self.configuration.get('port', 1717)
+ self.order = ORDER
+ self.definitions = deepcopy(CHARTS)
+
+ # Clear dynamic dimensions, these are added during `_get_data()` to allow adding workers at run-time
+ for chart in DYNAMIC_CHARTS:
+ self.definitions[chart]['lines'] = []
+
+ self.last_result = {}
+ self.workers = []
+
+ def read_data(self):
+ """
+ Read data from socket and parse as JSON.
+ :return: (dict) stats
+ """
+ raw_data = self._get_raw_data()
+ if not raw_data:
+ return None
+ try:
+ return json.loads(raw_data)
+ except ValueError as err:
+ self.error(err)
+ return None
+
+ def check(self):
+ """
+ Parse configuration and check if we can read data.
+ :return: boolean
+ """
+ self._parse_config()
+ return bool(self.read_data())
+
+ def add_worker_dimensions(self, key):
+ """
+ Helper to add dimensions for a worker.
+ :param key: (int or str) worker identifier
+ :return:
+ """
+ for chart in DYNAMIC_CHARTS:
+ for line in CHARTS[chart]['lines']:
+ dimension_id = '{}_{}'.format(line[0], key)
+ dimension_name = str(key)
+
+ dimension = [dimension_id, dimension_name] + line[2:]
+ self.charts[chart].add_dimension(dimension)
+
+ @staticmethod
+ def _check_raw_data(data):
+ # The server will close the connection when it's done sending
+ # data, so just keep looping until that happens.
+ return False
+
+ def _get_data(self):
+ """
+ Read data from socket
+ :return: dict
+ """
+ stats = self.read_data()
+ if not stats:
+ return None
+
+ result = {
+ 'exceptions': 0,
+ 'harakiri_count': 0,
+ 'respawn_count': 0,
+ }
+
+ for worker in stats['workers']:
+ key = worker['pid']
+
+ # Add dimensions for new workers
+ if key not in self.workers:
+ self.add_worker_dimensions(key)
+ self.workers.append(key)
+
+ result['requests_{}'.format(key)] = worker['requests']
+ result['tx_{}'.format(key)] = worker['tx']
+ result['avg_rt_{}'.format(key)] = worker['avg_rt']
+
+ # avg_rt is not reset by uwsgi, so reset here
+ if self.last_result.get('requests_{}'.format(key)) == worker['requests']:
+ result['avg_rt_{}'.format(key)] = 0
+
+ result['memory_rss_{}'.format(key)] = worker['rss']
+ result['memory_vsz_{}'.format(key)] = worker['vsz']
+
+ result['exceptions'] += worker['exceptions']
+ result['harakiri_count'] += worker['harakiri_count']
+ result['respawn_count'] += worker['respawn_count']
+
+ self.last_result = result
+ return result
diff --git a/collectors/python.d.plugin/uwsgi/uwsgi.conf b/collectors/python.d.plugin/uwsgi/uwsgi.conf
new file mode 100644
index 000000000..be1c2ada3
--- /dev/null
+++ b/collectors/python.d.plugin/uwsgi/uwsgi.conf
@@ -0,0 +1,94 @@
+# netdata python.d.plugin configuration for uwsgi
+#
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# Additionally to the above, uwsgi also supports the following:
+#
+# socket: 'path/to/uwsgistats.sock'
+#
+# or
+# host: 'IP or HOSTNAME' # the host to connect to
+# port: PORT # the port to connect to
+#
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
+# only one of them will run (they have the same name)
+#
+
+socket:
+ name : 'local'
+ socket : '/tmp/stats.socket'
+
+localhost:
+ name : 'local'
+ host : 'localhost'
+ port : 1717
+
+localipv4:
+ name : 'local'
+ host : '127.0.0.1'
+ port : 1717
+
+localipv6:
+ name : 'local'
+ host : '::1'
+ port : 1717
diff --git a/collectors/python.d.plugin/varnish/Makefile.inc b/collectors/python.d.plugin/varnish/Makefile.inc
new file mode 100644
index 000000000..2469b0592
--- /dev/null
+++ b/collectors/python.d.plugin/varnish/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += varnish/varnish.chart.py
+dist_pythonconfig_DATA += varnish/varnish.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += varnish/README.md varnish/Makefile.inc
+
diff --git a/collectors/python.d.plugin/varnish/README.md b/collectors/python.d.plugin/varnish/README.md
new file mode 100644
index 000000000..96c7cafaa
--- /dev/null
+++ b/collectors/python.d.plugin/varnish/README.md
@@ -0,0 +1,69 @@
+# varnish
+
+Module uses the `varnishstat` command to provide varnish cache statistics.
+
+It produces:
+
+1. **Connections Statistics** in connections/s
+ * accepted
+ * dropped
+
+2. **Client Requests** in requests/s
+ * received
+
+3. **All History Hit Rate Ratio** in percent
+ * hit
+ * miss
+ * hitpass
+
+4. **Current Poll Hit Rate Ratio** in percent
+ * hit
+ * miss
+ * hitpass
+
+5. **Expired Objects** in expired/s
+ * objects
+
+6. **Least Recently Used Nuked Objects** in nuked/s
+ * objects
+
+
+7. **Number Of Threads In All Pools** in threads
+ * threads
+
+8. **Threads Statistics** in threads/s
+ * created
+ * failed
+ * limited
+
+9. **Current Queue Length** in requests
+ * in queue
+
+10. **Backend Connections Statistics** in connections/s
+ * successful
+ * unhealthy
+ * reused
+ * closed
+ * resycled
+ * failed
+
+10. **Requests To The Backend** in requests/s
+ * received
+
+11. **ESI Statistics** in problems/s
+ * errors
+ * warnings
+
+12. **Memory Usage** in MB
+ * free
+ * allocated
+
+13. **Uptime** in seconds
+ * uptime
+
+
+### configuration
+
+No configuration is needed.
+
+---
diff --git a/python.d/varnish.chart.py b/collectors/python.d.plugin/varnish/varnish.chart.py
index d8145c0b6..d889c2b33 100644
--- a/python.d/varnish.chart.py
+++ b/collectors/python.d.plugin/varnish/varnish.chart.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Description: varnish netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
import re
@@ -12,13 +13,22 @@ from bases.FrameworkServices.ExecutableService import ExecutableService
priority = 60000
retries = 60
-ORDER = ['session_connections', 'client_requests',
- 'all_time_hit_rate', 'current_poll_hit_rate', 'cached_objects_expired', 'cached_objects_nuked',
- 'threads_total', 'threads_statistics', 'threads_queue_len',
- 'backend_connections', 'backend_requests',
- 'esi_statistics',
- 'memory_usage',
- 'uptime']
+ORDER = [
+ 'session_connections',
+ 'client_requests',
+ 'all_time_hit_rate',
+ 'current_poll_hit_rate',
+ 'cached_objects_expired',
+ 'cached_objects_nuked',
+ 'threads_total',
+ 'threads_statistics',
+ 'threads_queue_len',
+ 'backend_connections',
+ 'backend_requests',
+ 'esi_statistics',
+ 'memory_usage',
+ 'uptime'
+]
CHARTS = {
'session_connections': {
@@ -213,8 +223,9 @@ class Service(ExecutableService):
data.update(dict((param, value) for _, param, value in server_stats))
- data['memory_allocated'] = data['s0.g_bytes']
- data['memory_free'] = data['s0.g_space']
+ # varnish 5 uses default.g_bytes and default.g_space
+ data['memory_allocated'] = data.get('s0.g_bytes') or data.get('default.g_bytes')
+ data['memory_free'] = data.get('s0.g_space') or data.get('default.g_space')
return data
diff --git a/conf.d/python.d/varnish.conf b/collectors/python.d.plugin/varnish/varnish.conf
index 4b069d514..4b069d514 100644
--- a/conf.d/python.d/varnish.conf
+++ b/collectors/python.d.plugin/varnish/varnish.conf
diff --git a/collectors/python.d.plugin/w1sensor/Makefile.inc b/collectors/python.d.plugin/w1sensor/Makefile.inc
new file mode 100644
index 000000000..bddf146f5
--- /dev/null
+++ b/collectors/python.d.plugin/w1sensor/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += w1sensor/w1sensor.chart.py
+dist_pythonconfig_DATA += w1sensor/w1sensor.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += w1sensor/README.md w1sensor/Makefile.inc
+
diff --git a/collectors/python.d.plugin/w1sensor/README.md b/collectors/python.d.plugin/w1sensor/README.md
new file mode 100644
index 000000000..b18f08351
--- /dev/null
+++ b/collectors/python.d.plugin/w1sensor/README.md
@@ -0,0 +1,13 @@
+# w1sensor
+
+Data from 1-Wire sensors.
+On Linux these are supported by the wire, w1_gpio, and w1_therm modules.
+Currently temperature sensors are supported and automatically detected.
+
+Charts are created dynamically based on the number of detected sensors.
+
+### configuration
+
+For detailed configuration information please read [`w1sensor.conf`](w1sensor.conf) file.
+
+---
diff --git a/collectors/python.d.plugin/w1sensor/w1sensor.chart.py b/collectors/python.d.plugin/w1sensor/w1sensor.chart.py
new file mode 100644
index 000000000..493c4a135
--- /dev/null
+++ b/collectors/python.d.plugin/w1sensor/w1sensor.chart.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+# Description: 1-wire temperature monitor netdata python.d module
+# Author: Diomidis Spinellis <http://www.spinellis.gr>
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import os
+import re
+from bases.FrameworkServices.SimpleService import SimpleService
+
+# default module values (can be overridden per job in `config`)
+update_every = 5
+
+# Location where 1-Wire devices can be found
+W1_DIR = '/sys/bus/w1/devices/'
+
+# Lines matching the following regular expression contain a temperature value
+RE_TEMP = re.compile(r' t=(\d+)')
+
+ORDER = ['temp']
+
+CHARTS = {
+ 'temp': {
+ 'options': [None, '1-Wire Temperature Sensor', 'Celsius', 'Temperature', 'w1sensor.temp', 'line'],
+ 'lines': []
+ }
+}
+
+# Known and supported family members
+# Based on linux/drivers/w1/w1_family.h and w1/slaves/w1_therm.c
+THERM_FAMILY = {
+ '10': 'W1_THERM_DS18S20',
+ '22': 'W1_THERM_DS1822',
+ '28': 'W1_THERM_DS18B20',
+ '3b': 'W1_THERM_DS1825',
+ '42': 'W1_THERM_DS28EA00',
+}
+
+
+class Service(SimpleService):
+ """Provide netdata service for 1-Wire sensors"""
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER
+ self.definitions = CHARTS
+ self.probes = []
+
+ def check(self):
+ """Auto-detect available 1-Wire sensors, setting line definitions
+ and probes to be monitored."""
+ try:
+ file_names = os.listdir(W1_DIR)
+ except OSError as err:
+ self.error(err)
+ return False
+
+ lines = []
+ for file_name in file_names:
+ if file_name[2] != '-':
+ continue
+ if not file_name[0:2] in THERM_FAMILY:
+ continue
+
+ self.probes.append(file_name)
+ identifier = file_name[3:]
+ name = identifier
+ config_name = self.configuration.get('name_' + identifier)
+ if config_name:
+ name = config_name
+ lines.append(['w1sensor_temp_' + identifier, name, 'absolute',
+ 1, 10])
+ self.definitions['temp']['lines'] = lines
+ return len(self.probes) > 0
+
+ def get_data(self):
+ """Return data read from sensors."""
+ data = dict()
+
+ for file_name in self.probes:
+ file_path = W1_DIR + file_name + '/w1_slave'
+ identifier = file_name[3:]
+ try:
+ with open(file_path, 'r') as device_file:
+ for line in device_file:
+ matched = RE_TEMP.search(line)
+ if matched:
+ # Round to one decimal digit to filter-out noise
+ value = round(int(matched.group(1)) / 1000., 1)
+ value = int(value * 10)
+ data['w1sensor_temp_' + identifier] = value
+ except (OSError, IOError) as err:
+ self.error(err)
+ continue
+ return data or None
diff --git a/collectors/python.d.plugin/w1sensor/w1sensor.conf b/collectors/python.d.plugin/w1sensor/w1sensor.conf
new file mode 100644
index 000000000..a4aed8dd7
--- /dev/null
+++ b/collectors/python.d.plugin/w1sensor/w1sensor.conf
@@ -0,0 +1,74 @@
+# netdata python.d.plugin configuration for w1sensor
+#
+# 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: 5
+
+# 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: 60
+
+# autodetection_retry sets the job re-check interval in seconds.
+# The job is not deleted if check fails.
+# Attempts to start the job are made once every autodetection_retry.
+# This feature is disabled by default.
+# autodetection_retry: 0
+
+# ----------------------------------------------------------------------
+# 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: 5 # the JOB's data collection frequency
+# priority: 60000 # the JOB's order on the dashboard
+# retries: 60 # the JOB's number of restoration attempts
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
+#
+# Additionally to the above, example also supports the following:
+#
+# name_<1-Wire id>: '<human readable name>'
+# This allows associating a human readable name with a sensor's 1-Wire
+# identifier. Example:
+# name_00000022276e: 'Machine room'
+# name_00000022298f: 'Rack 12'
+#
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
+# only one of them will run (they have the same name)
diff --git a/collectors/python.d.plugin/web_log/Makefile.inc b/collectors/python.d.plugin/web_log/Makefile.inc
new file mode 100644
index 000000000..893115992
--- /dev/null
+++ b/collectors/python.d.plugin/web_log/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# THIS IS NOT A COMPLETE Makefile
+# IT IS INCLUDED BY ITS PARENT'S Makefile.am
+# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
+
+# install these files
+dist_python_DATA += web_log/web_log.chart.py
+dist_pythonconfig_DATA += web_log/web_log.conf
+
+# do not install these files, but include them in the distribution
+dist_noinst_DATA += web_log/README.md web_log/Makefile.inc
+
diff --git a/collectors/python.d.plugin/web_log/README.md b/collectors/python.d.plugin/web_log/README.md
new file mode 100644
index 000000000..6e8ea1dd5
--- /dev/null
+++ b/collectors/python.d.plugin/web_log/README.md
@@ -0,0 +1,64 @@
+# 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. **Current 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/web_log.chart.py b/collectors/python.d.plugin/web_log/web_log.chart.py
index be9baba92..20e15f4cb 100644
--- a/python.d/web_log.chart.py
+++ b/collectors/python.d.plugin/web_log/web_log.chart.py
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
# Description: web log netdata python.d module
# Author: l2isbad
+# SPDX-License-Identifier: GPL-3.0-or-later
import bisect
import re
import os
-import sys
from collections import namedtuple, defaultdict
from copy import deepcopy
@@ -16,21 +16,54 @@ except ImportError:
from itertools import ifilter as filter
from itertools import ifilterfalse as filterfalse
+try:
+ from sys import maxint
+except ImportError:
+ from sys import maxsize as maxint
+
from bases.collection import read_last_line
from bases.FrameworkServices.LogService import LogService
ORDER_APACHE_CACHE = ['apache_cache']
-ORDER_WEB = ['response_statuses', 'response_codes', 'bandwidth',
- 'response_time', 'response_time_hist', 'response_time_upstream', 'response_time_upstream_hist',
- 'requests_per_url', 'requests_per_user_defined', 'http_method', 'http_version',
- 'requests_per_ipproto', 'clients', 'clients_all']
-
-ORDER_SQUID = ['squid_response_statuses', 'squid_response_codes', 'squid_detailed_response_codes',
- 'squid_method', 'squid_mime_type', 'squid_hier_code', 'squid_transport_methods',
- 'squid_transport_errors', 'squid_code', 'squid_handling_opts', 'squid_object_types',
- 'squid_cache_events', 'squid_bytes', 'squid_duration', 'squid_clients', 'squid_clients_all']
+ORDER_WEB = [
+ 'response_statuses',
+ 'response_codes',
+ 'bandwidth',
+ 'response_time',
+ 'response_time_hist',
+ 'response_time_upstream',
+ 'response_time_upstream_hist',
+ 'requests_per_url',
+ 'requests_per_user_defined',
+ 'http_method',
+ 'vhost',
+ 'port',
+ 'http_version',
+ 'requests_per_ipproto',
+ 'clients',
+ 'clients_all'
+]
+
+ORDER_SQUID = [
+ 'squid_response_statuses',
+ 'squid_response_codes',
+ 'squid_detailed_response_codes',
+ 'squid_method',
+ 'squid_mime_type',
+ 'squid_hier_code',
+ 'squid_transport_methods',
+ 'squid_transport_errors',
+ 'squid_code',
+ 'squid_handling_opts',
+ 'squid_object_types',
+ 'squid_cache_events',
+ 'squid_bytes',
+ 'squid_duration',
+ 'squid_clients',
+ 'squid_clients_all'
+]
CHARTS_WEB = {
'response_codes': {
@@ -43,24 +76,27 @@ CHARTS_WEB = {
['1xx', None, 'incremental'],
['0xx', 'other', 'incremental'],
['unmatched', None, 'incremental']
- ]},
+ ]
+ },
'bandwidth': {
'options': [None, 'Bandwidth', 'kilobits/s', 'bandwidth', 'web_log.bandwidth', 'area'],
'lines': [
['resp_length', 'received', 'incremental', 8, 1000],
['bytes_sent', 'sent', 'incremental', -8, 1000]
- ]},
+ ]
+ },
'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]
- ]},
+ ]
+ },
'response_time_hist': {
'options': [None, 'Processing Time Histogram', 'requests/s', 'timings', 'web_log.response_time_hist', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'response_time_upstream': {
'options': [None, 'Processing Time Upstream', 'milliseconds', 'timings',
'web_log.response_time_upstream', 'area'],
@@ -68,62 +104,80 @@ CHARTS_WEB = {
['resp_time_upstream_min', 'min', 'incremental', 1, 1000],
['resp_time_upstream_max', 'max', 'incremental', 1, 1000],
['resp_time_upstream_avg', 'avg', 'incremental', 1, 1000]
- ]},
+ ]
+ },
'response_time_upstream_hist': {
'options': [None, 'Processing Time Histogram', 'requests/s', 'timings',
'web_log.response_time_upstream_hist', 'line'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'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': []},
+ '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'],
+ '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]
- ]},
+ ]
+ },
'requests_per_url': {
- 'options': [None, 'Requests Per Url', 'requests/s', 'urls', 'web_log.requests_per_url',
- 'stacked'],
+ 'options': [None, 'Requests Per Url', 'requests/s', 'urls', 'web_log.requests_per_url', 'stacked'],
'lines': [
['url_pattern_other', 'other', 'incremental', 1, 1]
- ]},
+ ]
+ },
'requests_per_user_defined': {
'options': [None, 'Requests Per User Defined Pattern', 'requests/s', 'user defined',
'web_log.requests_per_user_defined', 'stacked'],
'lines': [
['user_pattern_other', 'other', 'incremental', 1, 1]
- ]}
+ ]
+ },
+ 'port': {
+ 'options': [None, 'Requests Per Port', 'requests/s', 'port', 'web_log.port', 'stacked'],
+ 'lines': [
+ ['port_80', 'http', 'incremental', 1, 1],
+ ['port_443', 'https', 'incremental', 1, 1]
+ ]
+ },
+ 'vhost': {
+ 'options': [None, 'Requests Per Vhost', 'requests/s', 'vhost', 'web_log.vhost', 'stacked'],
+ 'lines': []
+ }
}
CHARTS_APACHE_CACHE = {
@@ -131,10 +185,11 @@ CHARTS_APACHE_CACHE = {
'options': [None, 'Apache Cached Responses', 'percent cached', 'cached', 'web_log.apache_cache_cache',
'stacked'],
'lines': [
- ["hit", 'cache', "percentage-of-absolute-row"],
- ["miss", None, "percentage-of-absolute-row"],
- ["other", None, "percentage-of-absolute-row"]
- ]}
+ ['hit', 'cache', 'percentage-of-absolute-row'],
+ ['miss', None, 'percentage-of-absolute-row'],
+ ['other', None, 'percentage-of-absolute-row']
+ ]
+ }
}
CHARTS_SQUID = {
@@ -145,13 +200,15 @@ CHARTS_SQUID = {
['duration_min', 'min', 'incremental', 1, 1000],
['duration_max', 'max', 'incremental', 1, 1000],
['duration_avg', 'avg', 'incremental', 1, 1000]
- ]},
+ ]
+ },
'squid_bytes': {
'options': [None, 'Amount Of Data Delivered To The Clients',
'kilobits/s', 'squid_bandwidth', 'web_log.squid_bytes', 'area'],
'lines': [
['bytes', 'sent', 'incremental', 8, 1000]
- ]},
+ ]
+ },
'squid_response_statuses': {
'options': [None, 'Response Statuses', 'responses/s', 'squid_responses', 'web_log.squid_response_statuses',
'stacked'],
@@ -161,7 +218,8 @@ CHARTS_SQUID = {
['redirects', 'redirect', 'incremental', 1, 1],
['bad_requests', 'bad', 'incremental', 1, 1],
['other_requests', 'other', 'incremental', 1, 1]
- ]},
+ ]
+ },
'squid_response_codes': {
'options': [None, 'Response Codes', 'responses/s', 'squid_responses',
'web_log.squid_response_codes', 'stacked'],
@@ -174,89 +232,113 @@ CHARTS_SQUID = {
['0xx', None, 'incremental'],
['other', None, 'incremental'],
['unmatched', None, 'incremental']
- ]},
+ ]
+ },
'squid_code': {
'options': [None, 'Responses Per Cache Result Of The Request',
'requests/s', 'squid_squid_cache', 'web_log.squid_code', 'stacked'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'squid_detailed_response_codes': {
'options': [None, 'Detailed Response Codes',
'responses/s', 'squid_responses', 'web_log.squid_detailed_response_codes', 'stacked'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'squid_hier_code': {
'options': [None, 'Responses Per Hierarchy Code',
'requests/s', 'squid_hierarchy', 'web_log.squid_hier_code', 'stacked'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'squid_method': {
'options': [None, 'Requests Per Method',
'requests/s', 'squid_requests', 'web_log.squid_method', 'stacked'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'squid_mime_type': {
'options': [None, 'Requests Per MIME Type',
'requests/s', 'squid_requests', 'web_log.squid_mime_type', 'stacked'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'squid_clients': {
'options': [None, 'Current Poll Unique Client IPs', 'unique ips', 'squid_clients',
'web_log.squid_clients', 'stacked'],
'lines': [
['unique_ipv4', 'ipv4', 'incremental'],
['unique_ipv6', 'ipv6', 'incremental']
- ]},
+ ]
+ },
'squid_clients_all': {
'options': [None, 'All Time Unique Client IPs', 'unique ips', 'squid_clients',
'web_log.squid_clients_all', 'stacked'],
'lines': [
['unique_tot_ipv4', 'ipv4', 'absolute'],
['unique_tot_ipv6', 'ipv6', 'absolute']
- ]},
+ ]
+ },
'squid_transport_methods': {
'options': [None, 'Transport Methods', 'requests/s', 'squid_squid_transport',
'web_log.squid_transport_methods', 'stacked'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'squid_transport_errors': {
'options': [None, 'Transport Errors', 'requests/s', 'squid_squid_transport',
'web_log.squid_transport_errors', 'stacked'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'squid_handling_opts': {
'options': [None, 'Handling Opts', 'requests/s', 'squid_squid_cache',
'web_log.squid_handling_opts', 'stacked'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'squid_object_types': {
'options': [None, 'Object Types', 'objects/s', 'squid_squid_cache',
'web_log.squid_object_types', 'stacked'],
- 'lines': [
- ]},
+ 'lines': []
+ },
'squid_cache_events': {
'options': [None, 'Cache Events', 'events/s', 'squid_squid_cache',
'web_log.squid_cache_events', 'stacked'],
- 'lines': [
- ]}
+ 'lines': []
+ }
}
NAMED_PATTERN = namedtuple('PATTERN', ['description', 'func'])
DET_RESP_AGGR = ['', '_1xx', '_2xx', '_3xx', '_4xx', '_5xx', '_Other']
-SQUID_CODES = dict(TCP='squid_transport_methods', UDP='squid_transport_methods', NONE='squid_transport_methods',
- CLIENT='squid_handling_opts', IMS='squid_handling_opts', ASYNC='squid_handling_opts',
- SWAPFAIL='squid_handling_opts', REFRESH='squid_handling_opts', SHARED='squid_handling_opts',
- REPLY='squid_handling_opts', NEGATIVE='squid_object_types', STALE='squid_object_types',
- OFFLINE='squid_object_types', INVALID='squid_object_types', FAIL='squid_object_types',
- MODIFIED='squid_object_types', UNMODIFIED='squid_object_types', REDIRECT='squid_object_types',
- HIT='squid_cache_events', MEM='squid_cache_events', MISS='squid_cache_events',
- DENIED='squid_cache_events', NOFETCH='squid_cache_events', TUNNEL='squid_cache_events',
- ABORTED='squid_transport_errors', TIMEOUT='squid_transport_errors')
+SQUID_CODES = {
+ 'TCP': 'squid_transport_methods',
+ 'UDP': 'squid_transport_methods',
+ 'NONE': 'squid_transport_methods',
+ 'CLIENT': 'squid_handling_opts',
+ 'IMS': 'squid_handling_opts',
+ 'ASYNC': 'squid_handling_opts',
+ 'SWAPFAIL': 'squid_handling_opts',
+ 'REFRESH': 'squid_handling_opts',
+ 'SHARED': 'squid_handling_opts',
+ 'REPLY': 'squid_handling_opts',
+ 'NEGATIVE': 'squid_object_types',
+ 'STALE': 'squid_object_types',
+ 'OFFLINE': 'squid_object_types',
+ 'INVALID': 'squid_object_types',
+ 'FAIL': 'squid_object_types',
+ 'MODIFIED': 'squid_object_types',
+ 'UNMODIFIED': 'squid_object_types',
+ 'REDIRECT': 'squid_object_types',
+ 'HIT': 'squid_cache_events',
+ 'MEM': 'squid_cache_events',
+ 'MISS': 'squid_cache_events',
+ 'DENIED': 'squid_cache_events',
+ 'NOFETCH': 'squid_cache_events',
+ 'TUNNEL': 'squid_cache_events',
+ 'ABORTED': 'squid_transport_errors',
+ 'TIMEOUT': 'squid_transport_errors'
+}
REQUEST_REGEX = re.compile(r'(?P<method>[A-Z]+) (?P<url>[^ ]+) [A-Z]+/(?P<http_version>\d(?:.\d)?)')
+MIME_TYPES = ['application', 'audio', 'example', 'font', 'image', 'message', 'model', 'multipart', 'text', 'video']
+
class Service(LogService):
def __init__(self, configuration=None, name=None):
@@ -283,7 +365,7 @@ class Service(LogService):
log_types = dict(web=Web, apache_cache=ApacheCache, squid=Squid)
if log_type not in log_types:
- self.error("bad log type {log_type}. Supported types: {types}".format(log_type=log_type,
+ self.error('bad log type {log_type}. Supported types: {types}'.format(log_type=log_type,
types=log_types.keys()))
return False
@@ -317,12 +399,35 @@ class Web:
self.definitions = deepcopy(CHARTS_WEB)
self.pre_filter = check_patterns('filter', self.configuration.get('filter'))
self.storage = dict()
- self.data = {'bytes_sent': 0, 'resp_length': 0, 'resp_time_min': 0, 'resp_time_max': 0,
- 'resp_time_avg': 0, 'resp_time_upstream_min': 0, 'resp_time_upstream_max': 0,
- 'resp_time_upstream_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}
+ self.data = {
+ 'bytes_sent': 0,
+ 'resp_length': 0,
+ 'resp_time_min': 0,
+ 'resp_time_max': 0,
+ 'resp_time_avg': 0,
+ 'resp_time_upstream_min': 0,
+ 'resp_time_upstream_max': 0,
+ 'resp_time_upstream_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 __getattr__(self, item):
return getattr(self.service, item)
@@ -367,21 +472,21 @@ class Web:
histogram = self.configuration.get('histogram', None)
if isinstance(histogram, list):
self.storage['bucket_index'] = histogram[:]
- self.storage['bucket_index'].append(sys.maxint)
+ self.storage['bucket_index'].append(maxint)
self.storage['buckets'] = [0] * (len(histogram) + 1)
self.storage['upstream_buckets'] = [0] * (len(histogram) + 1)
hist_lines = self.definitions['response_time_hist']['lines']
upstream_hist_lines = self.definitions['response_time_upstream_hist']['lines']
for i, le in enumerate(histogram):
- hist_key = "response_time_hist_%d" % i
- upstream_hist_key = "response_time_upstream_hist_%d" % i
+ hist_key = 'response_time_hist_%d' % i
+ upstream_hist_key = 'response_time_upstream_hist_%d' % i
hist_lines.append([hist_key, str(le), 'incremental', 1, 1])
upstream_hist_lines.append([upstream_hist_key, str(le), 'incremental', 1, 1])
- hist_lines.append(["response_time_hist_%d" % len(histogram), '+Inf', 'incremental', 1, 1])
- upstream_hist_lines.append(["response_time_upstream_hist_%d" % len(histogram), '+Inf', 'incremental', 1, 1])
+ hist_lines.append(['response_time_hist_%d' % len(histogram), '+Inf', 'incremental', 1, 1])
+ upstream_hist_lines.append(['response_time_upstream_hist_%d' % len(histogram), '+Inf', 'incremental', 1, 1])
elif histogram is not None:
- self.error("expect histogram list, but was {0}".format(type(histogram)))
+ self.error('expect histogram list, but was {0}'.format(type(histogram)))
if not self.configuration.get('all_time', True):
self.order.remove('clients_all')
@@ -395,10 +500,11 @@ class Web:
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': []}
+ 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.storage['url_pattern']:
@@ -499,8 +605,8 @@ class Web:
buckets = self.storage['buckets']
upstream_buckets = self.storage['upstream_buckets']
for i in range(0, len(self.storage['bucket_index'])):
- hist_key = "response_time_hist_%d" % i
- upstream_hist_key = "response_time_upstream_hist_%d" % i
+ hist_key = 'response_time_hist_%d' % i
+ upstream_hist_key = 'response_time_upstream_hist_%d' % i
self.data[hist_key] = buckets[i]
self.data[upstream_hist_key] = upstream_buckets[i]
@@ -596,7 +702,7 @@ class Web:
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
+ 3. if "time_multiplier" is in "custom_log_format" it must be <int> or <float> instance
If all parameters is ok we need to make sure:
1. Pattern search is success
@@ -623,8 +729,8 @@ class Web:
resp_time_func = self.configuration.get('custom_log_format', dict()).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')
+ if not isinstance(resp_time_func, (int, float)):
+ return find_regex_return(msg='Custom log: "time_multiplier" is not an integer or a float')
try:
regex = re.compile(pattern)
@@ -701,6 +807,23 @@ class Web:
'incremental'])
self.data[dim_id] = 0
self.data[dim_id] += 1
+ # requests per port number
+ if match_dict.get('port'):
+ if match_dict['port'] not in self.data:
+ self.charts['port'].add_dimension([match_dict['port'],
+ match_dict['port'],
+ 'incremental'])
+ self.data[match_dict['port']] = 0
+ self.data[match_dict['port']] += 1
+ # requests per vhost
+ if match_dict.get('vhost'):
+ dim_id = match_dict['vhost'].replace('.', '_')
+ if dim_id not in self.data:
+ self.charts['vhost'].add_dimension([dim_id,
+ match_dict['vhost'],
+ 'incremental'])
+ self.data[dim_id] = 0
+ self.data[dim_id] += 1
def get_data_per_response_codes_detailed(self, code):
"""
@@ -788,12 +911,29 @@ class Squid:
self.definitions = CHARTS_SQUID
self.pre_filter = check_patterns('filter', self.configuration.get('filter'))
self.storage = dict()
- self.data = {'duration_max': 0, 'duration_avg': 0, 'duration_min': 0, 'bytes': 0,
- '0xx': 0, '1xx': 0, '2xx': 0, '3xx': 0, '4xx': 0, '5xx': 0,
- 'other': 0, 'unmatched': 0, 'unique_ipv4': 0, 'unique_ipv6': 0,
- 'unique_tot_ipv4': 0, 'unique_tot_ipv6': 0, 'successful_requests': 0,
- 'redirects': 0, 'bad_requests': 0, 'server_errors': 0, 'other_requests': 0
- }
+ self.data = {
+ 'duration_max': 0,
+ 'duration_avg': 0,
+ 'duration_min': 0,
+ 'bytes': 0,
+ '0xx': 0,
+ '1xx': 0,
+ '2xx': 0,
+ '3xx': 0,
+ '4xx': 0,
+ '5xx': 0,
+ 'other': 0,
+ 'unmatched': 0,
+ 'unique_ipv4': 0,
+ 'unique_ipv6': 0,
+ 'unique_tot_ipv4': 0,
+ 'unique_tot_ipv6': 0,
+ 'successful_requests': 0,
+ 'redirects': 0,
+ 'bad_requests': 0,
+ 'server_errors': 0,
+ 'other_requests': 0
+ }
def __getattr__(self, item):
return getattr(self.service, item)
@@ -811,30 +951,35 @@ class Squid:
r' (?P<method>[A-Z_]+)'
r' (?P<url>[^ ]+)'
r' (?P<user>[^ ]+)'
- r' (?P<hier_code>[A-Z_]+)/[\da-f.:-]+'
- r' (?P<mime_type>[^\n]+)')
+ r' (?P<hier_code>[A-Z_]+)/[\da-z.:-]+'
+ r' (?P<mime_type>[A-Za-z-]*)')
match = self.storage['regex'].search(last_line)
if not match:
self.error('Regex not matches (%s)' % self.storage['regex'].pattern)
return False
self.storage['dynamic'] = {
- 'http_code':
- {'chart': 'squid_detailed_response_codes',
+ 'http_code': {
+ 'chart': 'squid_detailed_response_codes',
'func_dim_id': None,
- 'func_dim': None},
+ 'func_dim': None
+ },
'hier_code': {
'chart': 'squid_hier_code',
'func_dim_id': None,
- 'func_dim': lambda v: v.replace('HIER_', '')},
+ 'func_dim': lambda v: v.replace('HIER_', '')
+ },
'method': {
'chart': 'squid_method',
'func_dim_id': None,
- 'func_dim': None},
+ 'func_dim': None
+ },
'mime_type': {
'chart': 'squid_mime_type',
- 'func_dim_id': lambda v: v.split('/')[0],
- 'func_dim': None}}
+ 'func_dim_id': lambda v: str.lower(v) if str.lower(v) in MIME_TYPES else 'unknown',
+ 'func_dim': None
+ }
+ }
if not self.configuration.get('all_time', True):
self.order.remove('squid_clients_all')
return True
@@ -951,6 +1096,7 @@ def get_timings(timings, time):
timings['summary'] += time
timings['count'] += 1
+
def get_hist(index, buckets, time):
"""
:param index: histogram index (Ex. [10, 50, 100, 150, ...])
@@ -964,6 +1110,7 @@ def get_hist(index, buckets, time):
else:
break
+
def address_not_in_pool(pool, address, pool_size):
"""
:param pool: list of ip addresses
diff --git a/conf.d/python.d/web_log.conf b/collectors/python.d.plugin/web_log/web_log.conf
index c185f8d85..a67957aef 100644
--- a/conf.d/python.d/web_log.conf
+++ b/collectors/python.d.plugin/web_log/web_log.conf
@@ -84,7 +84,7 @@
# 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
+# time_multiplier: 1000000 # type <int>/<float> - convert time to microseconds
# histogram: [1,3,10,30,100, ...] # type list of int - Cumulative histogram of response time in milli seconds
# ----------------------------------------------------------------------
@@ -109,6 +109,17 @@
# CustomLog "/var/log/apache2/access.log" netdata
# ----------------------------------------------------------------------
+# VHOST AND PORT
+# if your want to graph the request/sec per virtual host and per port (to check the number of requests in http vs https)
+
+# in apache : (%v gives the hostname, %p the port number)
+# LogFormat "%v %p %h %t \"%r\" %>s %O %I %D \"%{Referer}i\" \"%{User-Agent}i\"" vhost_netdata
+#
+# and in this file in apache_vhosts_log section, add :
+# custom_log_format:
+# pattern: '(?P<vhost>[a-zA-Z\d.-_]+) (?P<port>\d+) (?P<address>[\da-f.:]+) \[.*\] "(?P<method>[A-Z]+)[^"]*" (?P<code>[1-9]\d{2}) (?P<bytes_sent>\d+) (?P<resp_length>\d+) (?P<resp_time>\d+)'
+
+# ----------------------------------------------------------------------
# AUTO-DETECTION JOBS
# only one of them per web server will run (when they have the same name)
diff --git a/collectors/statsd.plugin/Makefile.am b/collectors/statsd.plugin/Makefile.am
new file mode 100644
index 000000000..7f09bacd7
--- /dev/null
+++ b/collectors/statsd.plugin/Makefile.am
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
+
+statsdconfigdir=$(libconfigdir)/statsd.d
+dist_statsdconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ example.conf \
+ $(NULL)
+
+userstatsdconfigdir=$(configdir)/statsd.d
+dist_userstatsdconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
+
diff --git a/node.d/Makefile.in b/collectors/statsd.plugin/Makefile.in
index dd572ee8b..5c16a86d1 100644
--- a/node.d/Makefile.in
+++ b/collectors/statsd.plugin/Makefile.in
@@ -14,6 +14,8 @@
@SET_MAKE@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
@@ -78,19 +80,21 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-subdir = node.d
+subdir = collectors/statsd.plugin
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
- $(dist_node_DATA) $(dist_nodemodules_DATA) \
- $(dist_nodemoduleslibber_DATA)
+ $(dist_noinst_DATA) $(dist_statsdconfig_DATA) \
+ $(dist_userstatsdconfig_DATA)
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
- $(top_srcdir)/m4/ax_c_mallinfo.m4 \
- $(top_srcdir)/m4/ax_c_mallopt.m4 \
- $(top_srcdir)/m4/ax_check_compile_flag.m4 \
- $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
- $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/jemalloc.m4 \
- $(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
@@ -143,10 +147,10 @@ am__uninstall_files_from_dir = { \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
-am__installdirs = "$(DESTDIR)$(nodedir)" "$(DESTDIR)$(nodemodulesdir)" \
- "$(DESTDIR)$(nodemoduleslibberdir)"
-DATA = $(dist_node_DATA) $(dist_nodemodules_DATA) \
- $(dist_nodemoduleslibber_DATA)
+am__installdirs = "$(DESTDIR)$(statsdconfigdir)" \
+ "$(DESTDIR)$(userstatsdconfigdir)"
+DATA = $(dist_noinst_DATA) $(dist_statsdconfig_DATA) \
+ $(dist_userstatsdconfig_DATA)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
@@ -246,6 +250,7 @@ build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
+build_target = @build_target@
build_vendor = @build_vendor@
builddir = @builddir@
cachedir = @cachedir@
@@ -267,6 +272,7 @@ htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
+libconfigdir = @libconfigdir@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
@@ -293,33 +299,22 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
varlibdir = @varlibdir@
webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
-dist_node_DATA = \
+dist_noinst_DATA = \
README.md \
- named.node.js \
- fronius.node.js \
- sma_webbox.node.js \
- snmp.node.js \
- stiebeleltron.node.js \
$(NULL)
-nodemodulesdir = $(nodedir)/node_modules
-dist_nodemodules_DATA = \
- node_modules/netdata.js \
- node_modules/extend.js \
- node_modules/pixl-xml.js \
- node_modules/net-snmp.js \
- node_modules/asn1-ber.js \
- $(NULL)
+statsdconfigdir = $(libconfigdir)/statsd.d
+dist_statsdconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ example.conf \
+ $(NULL)
-nodemoduleslibberdir = $(nodedir)/node_modules/lib/ber
-dist_nodemoduleslibber_DATA = \
- node_modules/lib/ber/index.js \
- node_modules/lib/ber/errors.js \
- node_modules/lib/ber/reader.js \
- node_modules/lib/ber/types.js \
- node_modules/lib/ber/writer.js \
- $(NULL)
+userstatsdconfigdir = $(configdir)/statsd.d
+dist_userstatsdconfig_DATA = \
+ $(top_srcdir)/installer/.keep \
+ $(NULL)
all: all-am
@@ -333,9 +328,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
exit 1;; \
esac; \
done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu node.d/Makefile'; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/statsd.plugin/Makefile'; \
$(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --gnu node.d/Makefile
+ $(AUTOMAKE) --gnu collectors/statsd.plugin/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
@@ -354,69 +349,48 @@ $(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):
-install-dist_nodeDATA: $(dist_node_DATA)
- @$(NORMAL_INSTALL)
- @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"; \
- done | $(am__base_list) | \
- while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(nodedir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(nodedir)" || exit $$?; \
- done
-
-uninstall-dist_nodeDATA:
- @$(NORMAL_UNINSTALL)
- @list='$(dist_node_DATA)'; test -n "$(nodedir)" || list=; \
- files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- dir='$(DESTDIR)$(nodedir)'; $(am__uninstall_files_from_dir)
-install-dist_nodemodulesDATA: $(dist_nodemodules_DATA)
+install-dist_statsdconfigDATA: $(dist_statsdconfig_DATA)
@$(NORMAL_INSTALL)
- @list='$(dist_nodemodules_DATA)'; test -n "$(nodemodulesdir)" || list=; \
+ @list='$(dist_statsdconfig_DATA)'; test -n "$(statsdconfigdir)" || list=; \
if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(nodemodulesdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(nodemodulesdir)" || exit 1; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(statsdconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(statsdconfigdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(nodemodulesdir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(nodemodulesdir)" || exit $$?; \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(statsdconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(statsdconfigdir)" || exit $$?; \
done
-uninstall-dist_nodemodulesDATA:
+uninstall-dist_statsdconfigDATA:
@$(NORMAL_UNINSTALL)
- @list='$(dist_nodemodules_DATA)'; test -n "$(nodemodulesdir)" || list=; \
+ @list='$(dist_statsdconfig_DATA)'; test -n "$(statsdconfigdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- dir='$(DESTDIR)$(nodemodulesdir)'; $(am__uninstall_files_from_dir)
-install-dist_nodemoduleslibberDATA: $(dist_nodemoduleslibber_DATA)
+ dir='$(DESTDIR)$(statsdconfigdir)'; $(am__uninstall_files_from_dir)
+install-dist_userstatsdconfigDATA: $(dist_userstatsdconfig_DATA)
@$(NORMAL_INSTALL)
- @list='$(dist_nodemoduleslibber_DATA)'; test -n "$(nodemoduleslibberdir)" || list=; \
+ @list='$(dist_userstatsdconfig_DATA)'; test -n "$(userstatsdconfigdir)" || list=; \
if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(nodemoduleslibberdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(nodemoduleslibberdir)" || exit 1; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(userstatsdconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(userstatsdconfigdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(nodemoduleslibberdir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(nodemoduleslibberdir)" || exit $$?; \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(userstatsdconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(userstatsdconfigdir)" || exit $$?; \
done
-uninstall-dist_nodemoduleslibberDATA:
+uninstall-dist_userstatsdconfigDATA:
@$(NORMAL_UNINSTALL)
- @list='$(dist_nodemoduleslibber_DATA)'; test -n "$(nodemoduleslibberdir)" || list=; \
+ @list='$(dist_userstatsdconfig_DATA)'; test -n "$(userstatsdconfigdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- dir='$(DESTDIR)$(nodemoduleslibberdir)'; $(am__uninstall_files_from_dir)
+ dir='$(DESTDIR)$(userstatsdconfigdir)'; $(am__uninstall_files_from_dir)
tags TAGS:
ctags CTAGS:
@@ -458,7 +432,7 @@ check-am: all-am
check: check-am
all-am: Makefile $(DATA)
installdirs:
- for dir in "$(DESTDIR)$(nodedir)" "$(DESTDIR)$(nodemodulesdir)" "$(DESTDIR)$(nodemoduleslibberdir)"; do \
+ for dir in "$(DESTDIR)$(statsdconfigdir)" "$(DESTDIR)$(userstatsdconfigdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -512,8 +486,8 @@ info: info-am
info-am:
-install-data-am: install-dist_nodeDATA install-dist_nodemodulesDATA \
- install-dist_nodemoduleslibberDATA
+install-data-am: install-dist_statsdconfigDATA \
+ install-dist_userstatsdconfigDATA
install-dvi: install-dvi-am
@@ -557,25 +531,24 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-dist_nodeDATA uninstall-dist_nodemodulesDATA \
- uninstall-dist_nodemoduleslibberDATA
+uninstall-am: uninstall-dist_statsdconfigDATA \
+ uninstall-dist_userstatsdconfigDATA
.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_nodemoduleslibberDATA install-dvi install-dvi-am \
+ install-data-am install-dist_statsdconfigDATA \
+ install-dist_userstatsdconfigDATA 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 uninstall-dist_nodemodulesDATA \
- uninstall-dist_nodemoduleslibberDATA
+ uninstall-dist_statsdconfigDATA \
+ uninstall-dist_userstatsdconfigDATA
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/collectors/statsd.plugin/README.md b/collectors/statsd.plugin/README.md
new file mode 100644
index 000000000..6ef038343
--- /dev/null
+++ b/collectors/statsd.plugin/README.md
@@ -0,0 +1,523 @@
+# Netdata Statsd
+
+statsd is a system to collect data from any application. Applications are sending metrics to it, usually via non-blocking UDP communication, and statsd servers collect these metrics, perform a few simple calculations on them and push them to backend time-series databases.
+
+There is a [plethora of client libraries](https://github.com/etsy/statsd/wiki#client-implementations) for embedding statsd metrics to any application framework. This makes statsd quite popular for custom application metrics.
+
+## netdata statsd
+
+netdata is a fully featured statsd server. It can collect statsd formatted metrics, visualize them on its dashboards, stream them to other netdata servers or archive them to backend time-series databases.
+
+netdata statsd is inside netdata (an internal plugin, running inside the netdata daemon), it is configured via `netdata.conf` and by-default listens on standard statsd ports (tcp and udp 8125 - yes, netdata statsd server supports both tcp and udp at the same time).
+
+Since statsd is embedded in netdata, it means you now have a statsd server embedded on all your servers. So, the application can send its metrics to `localhost:8125`. This provides a distributed statsd implementation.
+
+netdata statsd is fast. It can collect more than **1.200.000 metrics per second** on modern hardware, more than **200Mbps of sustained statsd traffic**, using 1 CPU core (yes, it is single threaded - actually double-threaded, one thread collects metrics, another one updates the charts from the collected data).
+
+## metrics supported by netdata
+
+netdata fully supports the statsd protocol. All statsd client libraries can be used with netdata too.
+
+- **Gauges**
+
+ The application sends `name:value|g`, where `value` is any **decimal/fractional** number, statsd reports the latest value collected and the number of times it was updated (events).
+
+ The application may increment or decrement a previous value, by setting the first character of the value to ` + ` or ` - ` (so, the only way to set a gauge to an absolute negative value, is to first set it to zero).
+
+ Sampling rate is supported (check below).
+
+ When a gauge is not collected and the setting is not to show gaps on the charts (the default), the last value will be shown, until a data collection event changes it.
+
+- **Counters** and **Meters**
+
+ The application sends `name:value|c`, `name:value|C` or `name:value|m`, where `value` is a positive or negative **integer** number of events occurred, statsd reports the **rate** and the number of times it was updated (events).
+
+ `:value` can be omitted and statsd will assume it is `1`. `|c`, `|C` and `|m` can be omitted an statsd will assume it is `|m`. So, the application may send just `name` and statsd will parse it as `name:1|m`.
+
+ For counters use `|c` (esty/statsd compatible) or `|C` (brubeck compatible), for meters use `|m`.
+
+ Sampling rate is supported (check below).
+
+ When a counter or meter is not collected and the setting is not to show gaps on the charts (the default), zero will be shown, until a data collection event changes it.
+
+- **Timers** and **Histograms**
+
+ The application sends `name:value|ms` or `name:value|h`, where ` value` is any **decimal/fractional** number, statsd reports **min**, **max**, **average**, **sum**, **95th percentile**, **median** and **standard deviation** and the total number of times it was updated (events).
+
+ For timers use `|ms`, or histograms use `|h`. The only difference between the two, is the `units` of the charts (timers report milliseconds).
+
+ Sampling rate is supported (check below).
+
+ When a timer or histogram is not collected and the setting is not to show gaps on the charts (the default), zero will be shown, until a data collection event changes it.
+
+- **Sets**
+
+ The application sends `name:value|s`, where `value` is anything (**number or text**, leading and trailing spaces are removed), statsd reports the number of unique values sent and the number of times it was updated (events).
+
+ Sampling rate is **not** supported for Sets. `value` is always considered text.
+
+ When a set is not collected and the setting is not to show gaps on the charts (the default), zero will be shown, until a data collection event changes it.
+
+#### Sampling Rates
+
+The application may append `|@sampling_rate`, where `sampling_rate` is a number from `0.0` to `1.0`, to have statsd extrapolate the value, to predict to total for the whole period. So, if the application reports to statsd a value for 1/10th of the time, it can append `|@0.1` to the metrics it sends to statsd.
+
+#### Overlapping metrics
+
+netdata statsd maintains different indexes for each of the types supported. This means the same metric `name` may exist under different types concurrently.
+
+#### Multiple metrics per packet
+
+netdata accepts multiple metrics per packet if each is terminated with `\n`.
+
+#### TCP packets
+
+netdata listens for both TCP and UDP packets. For TCP though, is it important to always append `\n` on each metric. netdata uses this to detect if a metric is split into multiple TCP packets. On disconnect, even the remaining (non terminated with `\n`) buffer, is processed.
+
+#### UDP packets
+
+When sending multiple packets over UDP, it is important not to exceed the network MTU (usually 1500 bytes minus a few bytes for the headers). netdata will accept UDP packets up to 9000 bytes, but the underlying network will not exceed MTU.
+
+## configuration
+
+This is the statsd configuration at `/etc/netdata/netdata.conf`:
+
+```
+[statsd]
+ # enabled = yes
+ # decimal detail = 1000
+ # update every (flushInterval) = 1
+ # udp messages to process at once = 10
+ # create private charts for metrics matching = *
+ # max private charts allowed = 200
+ # max private charts hard limit = 1000
+ # private charts memory mode = save
+ # private charts history = 3996
+ # histograms and timers percentile (percentThreshold) = 95.00000
+ # add dimension for number of events received = yes
+ # gaps on gauges (deleteGauges) = no
+ # gaps on counters (deleteCounters) = no
+ # gaps on meters (deleteMeters) = no
+ # gaps on sets (deleteSets) = no
+ # gaps on histograms (deleteHistograms) = no
+ # gaps on timers (deleteTimers) = no
+ # listen backlog = 4096
+ # default port = 8125
+ # bind to = udp:localhost:8125 tcp:localhost:8125
+```
+
+### statsd main config options
+- `enabled = yes|no`
+
+ controls if statsd will be enabled for this netdata. The default is enabled.
+
+- `default port = 8125`
+
+ controls the port statsd will use. This is the default, since the next line, allows defining ports too.
+
+- `bind to = udp:localhost tcp:localhost`
+
+ is a space separated list of IPs and ports to listen to. The format is `PROTOCOL:IP:PORT` - if `PORT` is omitted, the `default port` will be used. If `IP` is IPv6, it needs to be enclosed in `[]`. `IP` can also be ` * ` (to listen on all IPs) or even a hostname.
+
+- `update every (flushInterval) = 1` seconds, controls the frequency statsd will push the collected metrics to netdata charts.
+
+- `decimal detail = 1000` controls the number of fractional digits in gauges and histograms. netdata collects metrics using signed 64 bit integers and their fractional detail is controlled using multipliers and divisors. This setting is used to multiply all collected values to convert them to integers and is also set as the divisors, so that the final data will be a floating point number with this fractional detail (1000 = X.0 - X.999, 10000 = X.0 - X.9999, etc).
+
+The rest of the settings are discussed below.
+
+## statsd charts
+
+netdata can visualize statsd collected metrics in 2 ways:
+
+1. Each metric gets its own **private chart**. This is the default and does not require any configuration (although there are a few options to tweak).
+
+2. **Synthetic charts** can be created, combining multiple metrics, independently of their metric types. For this type of charts, special configuration is required, to define the chart title, type, units, its dimensions, etc.
+
+### private metric charts
+
+Private charts are controlled with `create private charts for metrics matching = *`. This setting accepts a space separated list of simple patterns (use `*` as wildcard, prepend a pattern with `!` for a negative match, the order of patterns is important).
+
+So to render charts for all `myapp.*` metrics, except `myapp.*.badmetric`, use:
+
+```
+create private charts for metrics matching = !myapp.*.badmetric myapp.*
+```
+
+The default is to render private charts for all metrics.
+
+The `memory mode` of the round robin database and the `history` of private metric charts are controlled with `private charts memory mode` and `private charts history`. The defaults for both settings is to use the global netdata settings. So, you need to edit them only when you want statsd to use different settings compared to the global ones.
+
+If you have thousands of metrics, each with its own private chart, you may notice that your web browser becomes slow when you view the netdata dashboard (this is a web browser issue we need to address at the netdata UI). So, netdata has a protection to stop creating charts when `max private charts allowed = 200` (soft limit) is reached.
+
+The metrics above this soft limit are still processed by netdata and will be available to be sent to backend time-series databases, up to `max private charts hard limit = 1000`. So, between 200 and 1000 charts, netdata will still generate charts, but they will automatically be created with `memory mode = none` (netdata will not maintain a database for them). These metrics will be sent to backend time series databases, if the backend configuration is set to `as collected`.
+
+Metrics above the hard limit are still collected, but they can only be used in synthetic charts (once a metric is added to chart, it will be sent to backend servers too).
+
+Example private charts (automatically generated without any configuration):
+
+#### counters
+
+- Scope: **count the events of something** (e.g. number of file downloads)
+- Format: `name:INTEGER|c` or `name:INTEGER|C` or `name|c`
+- statsd increments the counter by the `INTEGER` number supplied (positive, or negative).
+
+![image](https://cloud.githubusercontent.com/assets/2662304/26131553/4a26d19c-3aa3-11e7-94e8-c53b5ed6ebc3.png)
+
+#### gauges
+
+- Scope: **report the value of something** (e.g. cache memory used by the application server)
+- Format: `name:FLOAT|g`
+- statsd remembers the last value supplied, and can increment or decrement the latest value if `FLOAT` begins with ` + ` or ` - `.
+
+![image](https://cloud.githubusercontent.com/assets/2662304/26131575/5d54e6f0-3aa3-11e7-9099-bc4440cd4592.png)
+
+#### histograms
+
+- Scope: **statistics on a size of events** (e.g. statistics on the sizes of files downloaded)
+- Format: `name:FLOAT|h`
+- statsd maintains a list of all the values supplied and provides statistics on them.
+
+![image](https://cloud.githubusercontent.com/assets/2662304/26131587/704de72a-3aa3-11e7-9ea9-0d2bb778c150.png)
+
+The same chart with `sum` unselected, to show the detail of the dimensions supported:
+![image](https://cloud.githubusercontent.com/assets/2662304/26131598/8076443a-3aa3-11e7-9ffa-ea535aee9c9f.png)
+
+#### meters
+
+This is identical to `counter`.
+
+- Scope: **count the events of something** (e.g. number of file downloads)
+- Format: `name:INTEGER|m` or `name|m` or just `name`
+- statsd increments the counter by the `INTEGER` number supplied (positive, or negative).
+
+![image](https://cloud.githubusercontent.com/assets/2662304/26131605/8fdf5a06-3aa3-11e7-963f-7ecf207d1dbc.png)
+
+#### sets
+
+- Scope: **count the unique occurrences of something** (e.g. unique filenames downloaded, or unique users that downloaded files)
+- Format: `name:TEXT|s`
+- statsd maintains a unique index of all values supplied, and reports the unique entries in it.
+
+![image](https://cloud.githubusercontent.com/assets/2662304/26131612/9eaa7b1a-3aa3-11e7-903b-d881e9a35be2.png)
+
+#### timers
+
+- Scope: **statistics on the duration of events** (e.g. statistics for the duration of file downloads)
+- Format: `name:FLOAT|ms`
+- statsd maintains a list of all the values supplied and provides statistics on them.
+
+![image](https://cloud.githubusercontent.com/assets/2662304/26131620/acbea6a4-3aa3-11e7-8bdd-4a8996847767.png)
+
+The same chart with the `sum` unselected:
+![image](https://cloud.githubusercontent.com/assets/2662304/26131629/bc34f2d2-3aa3-11e7-8a07-f2fc94ba4352.png)
+
+
+
+### synthetic statsd charts
+
+Using synthetic charts, you can create dedicated sections on the dashboard to render the charts. You can control everything: the main menu, the submenus, the charts, the dimensions on each chart, etc.
+
+Synthetic charts are organized in
+
+- **applications** (i.e. entries at the main menu of the netdata dashboard)
+- **charts for each application** (grouped in families - i.e. submenus at the dashboard menu)
+- **statsd metrics for each chart** (i.e. dimensions of the charts)
+
+For each application you need to create a `.conf` file in `/etc/netdata/statsd.d`.
+
+So, to create the statsd application `myapp`, you can create the file `/etc/netdata/statsd.d/myapp.conf`, with this content:
+
+```
+[app]
+ name = myapp
+ metrics = myapp.*
+ private charts = no
+ gaps when not collected = no
+ memory mode = ram
+ history = 60
+
+[dictionary]
+ m1 = metric1
+ m2 = metric2
+
+# replace 'mychart' with the chart id
+# the chart will be named: myapp.mychart
+[mychart]
+ name = mychart
+ title = my chart title
+ family = my family
+ context = chart.context
+ units = tests/s
+ priority = 91000
+ type = area
+ dimension = myapp.metric1 m1
+ dimension = myapp.metric2 m2
+```
+
+Using the above configuration `myapp` should get its own section on the dashboard, having one chart with 2 dimensions.
+
+`[app]` starts a new application definition. The supported settings in this section are:
+
+- `name` defines the name of the app.
+- `metrics` is a netdata simple pattern (space separated patterns, using `*` for wildcard, possibly starting with `!` for negative match). This pattern should match all the possible statsd metrics that will be participating in the application `myapp`.
+- `private charts = yes|no`, enables or disables private charts for the metrics matched.
+- `gaps when not collected = yes|no`, enables or disables gaps on the charts of the application, when metrics are not collected.
+- `memory mode` sets the memory mode for all charts of the application. The default is the global default for netdata (not the global default for statsd private charts).
+- `history` sets the size of the round robin database for this application. The default is the global default for netdata (not the global default for statsd private charts).
+
+`[dictionary]` defines name-value associations. These are used to renaming metrics, when added to synthetic charts. Metric names are also defined at each `dimension` line. However, using the dictionary dimension names can be declared globally, for each app and is the only way to rename dimensions when using patterns. Of course the dictionary can be empty or missing.
+
+Then, you can add any number of charts. Each chart should start with `[id]`. The chart will be called `app_name.id`. `family` controls the submenu on the dashboard. `context` controls the alarm templates. `priority` controls the ordering of the charts on the dashboard. The rest of the settings are informational.
+
+You can add any number of metrics to a chart, using `dimension` lines. These lines accept 5 space separated parameters:
+
+1. the metric name, as it is collected (it has to be matched by the `metrics = ` pattern of the app)
+2. the dimension name, as it should be shown on the chart
+3. an optional selector (type) of the value to shown (see below)
+4. an optional multiplier
+5. an optional divider
+6. optional flags, space separated and enclosed in quotes. All the external plugins `DIMENSION` flags can be used. Currently the only usable flag is `hidden`, to add the dimension, but not show it on the dashboard. This is usually needed to have the values available for percentage calculation, or use them in alarms.
+
+So, the format is this:
+```
+dimension = [pattern] METRIC NAME TYPE MULTIPLIER DIVIDER OPTIONS
+```
+
+`pattern` is a keyword. When set, `METRIC` is expected to be a netdata simple pattern that will be used to match all the statsd metrics to be added to the chart. So, `pattern` automatically matches any number of statsd metrics, all of which will be added as separate chart dimensions.
+
+`TYPE`, `MUTLIPLIER`, `DIVIDER` and `OPTIONS` are optional.
+
+`TYPE` can be:
+
+- `events` to show the number of events received by statsd for this metric
+- `last` to show the last value, as calculated at the flush interval of the metric (the default)
+
+Then for histograms and timers the following types are also supported:
+
+- `min`, show the minimum value
+- `max`, show the maximum value
+- `sum`, show the sum of all values
+- `average` (same as `last`)
+- `percentile`, show the 95th percentile (or any other percentile, as configured at statsd global config)
+- `median`, show the median of all values (i.e. sort all values and get the middle value)
+- `stddev`, show the standard deviation of the values
+
+#### example synthetic charts
+
+statsd metrics: `foo` and `bar`.
+
+Contents of file `/etc/netdata/stats.d/foobar.conf`:
+
+```
+[app]
+ name = foobarapp
+ metrics = foo bar
+ private charts = yes
+
+[foobar_chart1]
+ title = Hey, foo and bar together
+ family = foobar_family
+ context = foobarapp.foobars
+ units = foobars
+ type = area
+ dimension = foo 'foo me' last 1 1
+ dimension = bar 'bar me' last 1 1
+```
+
+I sent to statsd: `foo:10|g` and `bar:20|g`.
+
+I got these private charts:
+
+![screenshot from 2017-08-03 23-28-19](https://user-images.githubusercontent.com/2662304/28942295-7c3a73a8-78a3-11e7-88e5-a9a006bb7465.png)
+
+and this synthetic chart:
+
+![screenshot from 2017-08-03 23-29-14](https://user-images.githubusercontent.com/2662304/28942317-958a2c68-78a3-11e7-853f-32850141dd36.png)
+
+#### dictionary to name dimensions
+
+The `[dictionary]` section accepts any number of `name = value` pairs.
+
+netdata uses this dictionary as follows:
+
+1. When a `dimension` has a non-empty `NAME`, that name is looked up at the dictionary.
+
+2. If the above lookup gives nothing, or the `dimension` has an empty `NAME`, the original statsd metric name is looked up at the dictionary.
+
+3. If any of the above succeeds, netdata uses the `value` of the dictionary, to set the name of the dimension. The dimensions will have as ID the original statsd metric name, and as name, the dictionary value.
+
+So, you can use the dictionary in 2 ways:
+
+1. set `dimension = myapp.metric1 ''` and have at the dictionary `myapp.metric1 = metric1 name`
+2. set `dimension = myapp.metric1 'm1'` and have at the dictionary `m1 = metric1 name`
+
+In both cases, the dimension will be added with ID `myapp.metric1` and will be named `metric1 name`. So, in alarms you can use either of the 2 as `${myapp.metric1}` or `${metric1 name}`.
+
+> keep in mind that if you add multiple times the same statsd metric to a chart, netdata will append `TYPE` to the dimension ID, so `myapp.metric1` will be added as `myapp.metric1_last` or `myapp.metric1_events`, etc. If you add multiple times the same metric with the same `TYPE` to a chart, netdata will also append an incremental counter to the dimension ID, i.e. `myapp.metric1_last1`, `myapp.metric1_last2`, etc.
+
+#### dimension patterns
+
+netdata allows adding multiple dimensions to a chart, by matching the statsd metrics with a netdata simple pattern.
+
+Assume we have an API that provides statsd metrics for each response code per method it supports, like these:
+
+```
+myapp.api.get.200
+myapp.api.get.400
+myapp.api.get.500
+myapp.api.del.200
+myapp.api.del.400
+myapp.api.del.500
+myapp.api.post.200
+myapp.api.post.400
+myapp.api.post.500
+myapp.api.all.200
+myapp.api.all.400
+myapp.api.all.500
+```
+
+To add all response codes of `myapp.api.get` to a chart use this:
+
+```
+[api_get_responses]
+ ...
+ dimension = pattern 'myapp.api.get.* '' last 1 1
+```
+
+The above will add dimension named `200`, `400` and `500` (yes, netdata extracts the wildcarded part of the metric name - so the dimensions will be named with whatever the `*` matched). You can rename the dimensions with this:
+
+```
+[dictionary]
+ get.200 = 200 ok
+ get.400 = 400 bad request
+ get.500 = 500 cannot connect to db
+
+[api_get_responses]
+ ...
+ dimension = pattern 'myapp.api.get.* 'get.' last 1 1
+```
+
+Note that we added a `NAME` to the dimension line with `get.`. This is prefixed to the wildcarded part of the metric name, to compose the key for looking up the dictionary. So `500` became `get.500` which was looked up to the dictionary to find value `500 cannot connect to db`. This way we can have different dimension names, for each of the API methods (i.e. `get.500 = 500 cannot connect to db` while `post.500 = 500 cannot write to disk`).
+
+To add all API methods to a chart, do this:
+
+```
+[ok_by_method]
+ ...
+ dimension = pattern 'myapp.api.*.200 '' last 1 1
+```
+
+The above will add `get`, `post`, `del` and `all` to the chart.
+
+If `all` is not wanted (a `stacked` chart does not need the `all` dimension, since the sum of the dimensions provides the total), the line should be:
+
+```
+[ok_by_method]
+ ...
+ dimension = pattern '!myapp.api.all.* myapp.api.*.200 '' last 1 1
+```
+
+With the above, all methods except `all` will be added to the chart.
+
+To automatically rename the methods, use this:
+
+```
+[dictionary]
+ method.get = GET
+ method.post = ADD
+ method.del = DELETE
+
+[ok_by_method]
+ ...
+ dimension = pattern '!myapp.api.all.* myapp.api.*.200 'method.' last 1 1
+```
+
+Using the above, the dimensions will be added as `GET`, `ADD` and `DELETE`.
+
+
+## interpolation
+
+~~If you send just one value to statsd, you will notice that the chart is created but no value is shown. The reason is that netdata interpolates all values at second boundaries. For incremental values (`counters` and `meters` in statsd terminology), if you send 10 at 00:00:00.500, 20 at 00:00:01.500 and 30 at 00:00:02.500, netdata will show 15 at 00:00:01 and 25 at 00:00:02.~~
+
+~~This interpolation is automatic and global in netdata for all charts, for incremental values. This means that for the chart to start showing values you need to send 2 values across 2 flush intervals.~~
+
+~~(although this is required for incremental values, netdata allows mixing incremental and absolute values on the same charts, so this little limitation [i.e. 2 values to start visualization], is applied on all netdata dimensions).~~
+
+(statsd metrics do not loose their first data collection due to interpolation anymore - fixed with [PR #2411](https://github.com/netdata/netdata/pull/2411))
+
+## sending statsd metrics from shell scripts
+
+You can send/update statsd metrics from shell scripts. You can use this feature, to visualize in netdata automated jobs you run on your servers.
+
+The command you need to run is:
+
+```sh
+echo "NAME:VALUE|TYPE" | nc -u --send-only localhost 8125
+```
+
+Where:
+
+- `NAME` is the metric name
+- `VALUE` is the value for that metric (**gauges** `|g`, **timers** `|ms` and **histograms** `|h` accept decimal/fractional numbers, **counters** `|c` and **meters** `|m` accept integers, **sets** `|s` accept anything)
+- `TYPE` is one of `g`, `ms`, `h`, `c`, `m`, `s` to select the metric type.
+
+So, to set `metric1` as gauge to value `10`, use:
+
+```sh
+echo "metric1:10|g" | nc -u --send-only localhost 8125
+```
+
+To increment `metric2` by `10`, as a counter, use:
+
+```sh
+echo "metric2:10|c" | nc -u --send-only localhost 8125
+```
+
+You can send multiple metrics like this:
+
+```sh
+# send multiple metrics via UDP
+printf "metric1:10|g\nmetric2:10|c\n" | nc -u --send-only localhost 8125
+```
+
+Remember, for UDP communication each packet should not exceed the MTU. So, if you plan to push too many metrics at once, prefer TCP communication:
+
+```sh
+# send multiple metrics via TCP
+printf "metric1:10|g\nmetric2:10|c\n" | nc --send-only localhost 8125
+```
+
+You can also use this little function to take care of all the details:
+
+```sh
+#!/usr/bin/env bash
+
+STATSD_HOST="localhost"
+STATSD_PORT="8125"
+statsd() {
+ local udp="-u" all="${*}"
+
+ # if the string length of all parameters given is above 1000, use TCP
+ [ "${#all}" -gt 1000 ] && udp=
+
+ while [ ! -z "${1}" ]
+ do
+ printf "${1}\n"
+ shift
+ done | nc ${udp} --send-only ${STATSD_HOST} ${STATSD_PORT} || return 1
+
+ return 0
+}
+```
+
+You can use it like this:
+
+```sh
+# first, source it in your script
+source statsd.sh
+
+# then, at any point:
+statsd "metric1:10|g" "metric2:10|c" ...
+```
+
+The function is smart enough to call `nc` just once and pass all the metrics to it. It will also automatically switch to TCP if the metrics to send are above 1000 bytes.
diff --git a/conf.d/statsd.d/example.conf b/collectors/statsd.plugin/example.conf
index 0af9dd27d..2c7de6c7b 100644
--- a/conf.d/statsd.d/example.conf
+++ b/collectors/statsd.plugin/example.conf
@@ -1,16 +1,17 @@
# statsd synthetic charts configuration
-# You can add many .conf files, one for each of your apps
+# You can add many .conf files in /etc/netdata/statsd.d/,
+# one for each of your apps.
# start a new app - you can add many apps in the same file
[app]
# give a name for this app
# this controls the main menu on the dashboard
# and will be the prefix for all charts of the app
- name = myapp
+ name = myexampleapp
# match all the metrics of the app
- metrics = myapp.*
+ metrics = myexampleapp.*
# shall private charts of these metrics be created?
private charts = no
@@ -26,13 +27,11 @@
# the default is to use the global history
#history = 3600
-
-
# create a chart
-# this is its id - the chart will be named myapp.mychart
-[mychart]
+# this is its id - the chart will be named myexampleapp.myexamplechart
+[myexamplechart]
# a name for the chart, similar to the id (2 names for each chart)
- name = mychart
+ name = myexamplechart
# the chart title
title = my chart title
@@ -57,9 +56,9 @@
# events = the number of events for this metric
# last = the last value collected
# all the others are only valid for histograms and timers
- dimension = myapp.metric1 avg average 1 1
- dimension = myapp.metric1 lower min 1 1
- dimension = myapp.metric1 upper max 1 1
- dimension = myapp.metric2 other last 1 1
+ dimension = myexampleapp.metric1 avg average 1 1
+ dimension = myexampleapp.metric1 lower min 1 1
+ dimension = myexampleapp.metric1 upper max 1 1
+ dimension = myexampleapp.metric2 other last 1 1
# You can add as many charts as needed
diff --git a/src/statsd.c b/collectors/statsd.plugin/statsd.c
index 44ebd8894..c92bfd1c2 100644
--- a/src/statsd.c
+++ b/collectors/statsd.plugin/statsd.c
@@ -1,7 +1,10 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "statsd.h"
#define STATSD_CHART_PREFIX "statsd"
-#define STATSD_CHART_PRIORITY 90000
+
+#define PLUGIN_STATSD_NAME "statsd.plugin"
// --------------------------------------------------------------------------------------
@@ -87,7 +90,10 @@ typedef enum statsd_metric_options {
STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED = 0x00000002, // render a private chart for this metric
STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED = 0x00000004, // the metric has been checked if it should get private chart or not
STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT = 0x00000008, // show the count of events for this private chart
- STATSD_METRIC_OPTION_CHECKED_IN_APPS = 0x00000010, // set when this metric has been checked agains apps
+ STATSD_METRIC_OPTION_CHECKED_IN_APPS = 0x00000010, // set when this metric has been checked against apps
+ STATSD_METRIC_OPTION_USED_IN_APPS = 0x00000020, // set when this metric is used in apps
+ STATSD_METRIC_OPTION_CHECKED = 0x00000040, // set when the charting thread checks this metric for use in charts (its usefulness)
+ STATSD_METRIC_OPTION_USEFUL = 0x00000080, // set when the charting thread finds the metric useful (i.e. used in a chart)
} STATS_METRIC_OPTIONS;
typedef enum statsd_metric_type {
@@ -101,7 +107,7 @@ typedef enum statsd_metric_type {
typedef struct statsd_metric {
- avl avl; // indexing
+ avl avl; // indexing - has to be first
const char *name; // the name of the metric
uint32_t hash; // hash of the name
@@ -122,14 +128,15 @@ typedef struct statsd_metric {
// chart related members
STATS_METRIC_OPTIONS options; // STATSD_METRIC_OPTION_* (bitfield)
- char reset; // set to 1 to reset this metric to zero
+ char reset; // set to 1 by the charting thread to instruct the collector thread(s) to reset this metric
collected_number last; // the last value sent to netdata
- RRDSET *st; // the chart of this metric
+ RRDSET *st; // the private chart of this metric
RRDDIM *rd_value; // the dimension of this metric value
RRDDIM *rd_count; // the dimension for the number of events received
// linking, used for walking through all metrics
struct statsd_metric *next;
+ struct statsd_metric *next_useful;
} STATSD_METRIC;
@@ -140,10 +147,12 @@ typedef struct statsd_index {
char *name; // the name of the index of metrics
size_t events; // the number of events processed for this index
size_t metrics; // the number of metrics in this index
+ size_t useful; // the number of useful metrics in this index
STATSD_AVL_TREE index; // the AVL tree
STATSD_METRIC *first; // the linked list of metrics (new metrics are added in front)
+ STATSD_METRIC *first_useful; // the linked list of useful metrics (new metrics are added in front)
STATSD_FIRST_PTR_MUTEX; // when mutli-threading is enabled, a lock to protect the linked list
STATS_METRIC_OPTIONS default_options; // default options for all metrics in this index
@@ -255,13 +264,13 @@ static struct statsd {
SIMPLE_PATTERN *charts_for;
size_t tcp_idle_timeout;
- size_t decimal_detail;
+ collected_number decimal_detail;
size_t private_charts;
size_t max_private_charts;
size_t max_private_charts_hard;
RRD_MEMORY_MODE private_charts_memory_mode;
long private_charts_rrd_history_entries;
- int private_charts_hidden;
+ unsigned int private_charts_hidden:1;
STATSD_APP *apps;
size_t recvmmsg_size;
@@ -344,6 +353,7 @@ static struct statsd {
.threads = 0,
.collection_threads_status = NULL,
.sockets = {
+ .config = &netdata_config,
.config_section = CONFIG_SECTION_STATSD,
.default_bind_to = "udp:localhost tcp:localhost",
.default_port = STATSD_LISTEN_PORT,
@@ -427,6 +437,13 @@ static inline LONG_DOUBLE statsd_parse_float(const char *v, LONG_DOUBLE def) {
return value;
}
+static inline LONG_DOUBLE statsd_parse_sampling_rate(const char *v) {
+ LONG_DOUBLE sampling_rate = statsd_parse_float(v, 1.0);
+ if(unlikely(isless(sampling_rate, 0.001))) sampling_rate = 0.001;
+ if(unlikely(isgreater(sampling_rate, 1.0))) sampling_rate = 1.0;
+ return sampling_rate;
+}
+
static inline long long statsd_parse_int(const char *v, long long def) {
long long value;
@@ -455,7 +472,12 @@ static inline int value_is_zinit(const char *value) {
return (value && *value == 'z' && *++value == 'i' && *++value == 'n' && *++value == 'i' && *++value == 't' && *++value == '\0');
}
+#define is_metric_checked(m) ((m)->options & STATSD_METRIC_OPTION_CHECKED)
+#define is_metric_useful_for_collection(m) (!is_metric_checked(m) || ((m)->options & STATSD_METRIC_OPTION_USEFUL))
+
static inline void statsd_process_gauge(STATSD_METRIC *m, const char *value, const char *sampling) {
+ if(!is_metric_useful_for_collection(m)) return;
+
if(unlikely(!value || !*value)) {
error("STATSD: metric '%s' of type gauge, with empty value is ignored.", m->name);
return;
@@ -471,16 +493,18 @@ static inline void statsd_process_gauge(STATSD_METRIC *m, const char *value, con
}
else {
if (unlikely(*value == '+' || *value == '-'))
- m->gauge.value += statsd_parse_float(value, 1.0) / statsd_parse_float(sampling, 1.0);
+ m->gauge.value += statsd_parse_float(value, 1.0) / statsd_parse_sampling_rate(sampling);
else
- m->gauge.value = statsd_parse_float(value, 1.0) / statsd_parse_float(sampling, 1.0);
+ m->gauge.value = statsd_parse_float(value, 1.0);
m->events++;
m->count++;
}
}
-static inline void statsd_process_counter(STATSD_METRIC *m, const char *value, const char *sampling) {
+static inline void statsd_process_counter_or_meter(STATSD_METRIC *m, const char *value, const char *sampling) {
+ if(!is_metric_useful_for_collection(m)) return;
+
// we accept empty values for counters
if(unlikely(m->reset)) statsd_reset_metric(m);
@@ -489,21 +513,21 @@ static inline void statsd_process_counter(STATSD_METRIC *m, const char *value, c
// magic loading of metric, without affecting anything
}
else {
- m->counter.value += llrintl((LONG_DOUBLE) statsd_parse_int(value, 1) / statsd_parse_float(sampling, 1.0));
+ m->counter.value += llrintl((LONG_DOUBLE) statsd_parse_int(value, 1) / statsd_parse_sampling_rate(sampling));
m->events++;
m->count++;
}
}
-static inline void statsd_process_meter(STATSD_METRIC *m, const char *value, const char *sampling) {
- // this is the same with the counter
- statsd_process_counter(m, value, sampling);
-}
+#define statsd_process_counter(m, value, sampling) statsd_process_counter_or_meter(m, value, sampling)
+#define statsd_process_meter(m, value, sampling) statsd_process_counter_or_meter(m, value, sampling)
+
+static inline void statsd_process_histogram_or_timer(STATSD_METRIC *m, const char *value, const char *sampling, const char *type) {
+ if(!is_metric_useful_for_collection(m)) return;
-static inline void statsd_process_histogram(STATSD_METRIC *m, const char *value, const char *sampling) {
if(unlikely(!value || !*value)) {
- error("STATSD: metric '%s' of type histogram, with empty value is ignored.", m->name);
+ error("STATSD: metric of type %s, with empty value is ignored.", type);
return;
}
@@ -516,31 +540,35 @@ static inline void statsd_process_histogram(STATSD_METRIC *m, const char *value,
// magic loading of metric, without affecting anything
}
else {
- if (unlikely(m->histogram.ext->used == m->histogram.ext->size)) {
- netdata_mutex_lock(&m->histogram.ext->mutex);
- m->histogram.ext->size += statsd.histogram_increase_step;
- m->histogram.ext->values = reallocz(m->histogram.ext->values, sizeof(LONG_DOUBLE) * m->histogram.ext->size);
- netdata_mutex_unlock(&m->histogram.ext->mutex);
- }
+ LONG_DOUBLE v = statsd_parse_float(value, 1.0);
+ LONG_DOUBLE sampling_rate = statsd_parse_sampling_rate(sampling);
+ if(unlikely(isless(sampling_rate, 0.01))) sampling_rate = 0.01;
+ if(unlikely(isgreater(sampling_rate, 1.0))) sampling_rate = 1.0;
+
+ long long samples = llrintl(1.0 / sampling_rate);
+ while(samples-- > 0) {
+
+ if(unlikely(m->histogram.ext->used == m->histogram.ext->size)) {
+ netdata_mutex_lock(&m->histogram.ext->mutex);
+ m->histogram.ext->size += statsd.histogram_increase_step;
+ m->histogram.ext->values = reallocz(m->histogram.ext->values, sizeof(LONG_DOUBLE) * m->histogram.ext->size);
+ netdata_mutex_unlock(&m->histogram.ext->mutex);
+ }
- m->histogram.ext->values[m->histogram.ext->used++] = statsd_parse_float(value, 1.0) / statsd_parse_float(sampling, 1.0);
+ m->histogram.ext->values[m->histogram.ext->used++] = v;
+ }
m->events++;
m->count++;
}
}
-static inline void statsd_process_timer(STATSD_METRIC *m, const char *value, const char *sampling) {
- if(unlikely(!value || !*value)) {
- error("STATSD: metric of type timer, with empty value is ignored.");
- return;
- }
-
- // timers are a use case of histogram
- statsd_process_histogram(m, value, sampling);
-}
+#define statsd_process_timer(m, value, sampling) statsd_process_histogram_or_timer(m, value, sampling, "timer")
+#define statsd_process_histogram(m, value, sampling) statsd_process_histogram_or_timer(m, value, sampling, "histogram")
static inline void statsd_process_set(STATSD_METRIC *m, const char *value) {
+ if(!is_metric_useful_for_collection(m)) return;
+
if(unlikely(!value || !*value)) {
error("STATSD: metric of type set, with empty value is ignored.");
return;
@@ -578,8 +606,10 @@ static inline void statsd_process_set(STATSD_METRIC *m, const char *value) {
// --------------------------------------------------------------------------------------------------------------------
// statsd parsing
-static void statsd_process_metric(const char *name, const char *value, const char *type, const char *sampling) {
- debug(D_STATSD, "STATSD: raw metric '%s', value '%s', type '%s', rate '%s'", name?name:"(null)", value?value:"(null)", type?type:"(null)", sampling?sampling:"(null)");
+static void statsd_process_metric(const char *name, const char *value, const char *type, const char *sampling, const char *tags) {
+ (void)tags;
+
+ debug(D_STATSD, "STATSD: raw metric '%s', value '%s', type '%s', sampling '%s', tags '%s'", name?name:"(null)", value?value:"(null)", type?type:"(null)", sampling?sampling:"(null)", tags?tags:"(null)");
if(unlikely(!name || !*name)) return;
if(unlikely(!type || !*type)) type = "m";
@@ -663,8 +693,8 @@ static inline size_t statsd_process(char *buffer, size_t size, int require_newli
const char *s = buffer;
while(*s) {
- const char *name = NULL, *value = NULL, *type = NULL, *sampling = NULL;
- char *name_end = NULL, *value_end = NULL, *type_end = NULL, *sampling_end = NULL;
+ const char *name = NULL, *value = NULL, *type = NULL, *sampling = NULL, *tags = NULL;
+ char *name_end = NULL, *value_end = NULL, *type_end = NULL, *sampling_end = NULL, *tags_end = NULL;
s = name_end = (char *)statsd_parse_skip_up_to(name = s, ':', '|');
if(name == name_end) {
@@ -679,10 +709,15 @@ static inline size_t statsd_process(char *buffer, size_t size, int require_newli
s = type_end = (char *) statsd_parse_skip_up_to(type = ++s, '|', '@');
if(likely(*s == '|' || *s == '@')) {
- s = sampling_end = (char *) statsd_parse_skip_up_to(sampling = ++s, '\r', '\n');
+ s = sampling_end = (char *) statsd_parse_skip_up_to(sampling = ++s, '|', '#');
if(*sampling == '@') sampling++;
}
+ if(likely(*s == '|' || *s == '#')) {
+ s = tags_end = (char *) statsd_parse_skip_up_to(tags = ++s, '|', '|');
+ if(*tags == '#') tags++;
+ }
+
// skip everything until the end of the line
while(*s && *s != '\n') s++;
@@ -700,6 +735,7 @@ static inline size_t statsd_process(char *buffer, size_t size, int require_newli
, statsd_parse_field_trim(value, value_end)
, statsd_parse_field_trim(type, type_end)
, statsd_parse_field_trim(sampling, sampling_end)
+ , statsd_parse_field_trim(tags, tags_end)
);
}
@@ -997,7 +1033,7 @@ void *statsd_collector_thread(void *ptr) {
#define STATSD_CONF_LINE_MAX 8192
-static STATSD_APP_CHART_DIM_VALUE_TYPE string2valuetype(const char *type, size_t line, const char *path, const char *filename) {
+static STATSD_APP_CHART_DIM_VALUE_TYPE string2valuetype(const char *type, size_t line, const char *filename) {
if(!type || !*type) type = "last";
if(!strcmp(type, "events")) return STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS;
@@ -1010,7 +1046,7 @@ static STATSD_APP_CHART_DIM_VALUE_TYPE string2valuetype(const char *type, size_t
else if(!strcmp(type, "stddev")) return STATSD_APP_CHART_DIM_VALUE_TYPE_STDDEV;
else if(!strcmp(type, "percentile")) return STATSD_APP_CHART_DIM_VALUE_TYPE_PERCENTILE;
- error("STATSD: invalid type '%s' at line %zu of file '%s/%s'. Using 'last'.", type, line, path, filename);
+ error("STATSD: invalid type '%s' at line %zu of file '%s'. Using 'last'.", type, line, filename);
return STATSD_APP_CHART_DIM_VALUE_TYPE_LAST;
}
@@ -1076,19 +1112,14 @@ static STATSD_APP_CHART_DIM *add_dimension_to_app_chart(
return dim;
}
-static int statsd_readfile(const char *path, const char *filename, STATSD_APP *app, STATSD_APP_CHART *chart, DICTIONARY *dict) {
- debug(D_STATSD, "STATSD configuration reading file '%s/%s'", path, filename);
+static int statsd_readfile(const char *filename, STATSD_APP *app, STATSD_APP_CHART *chart, DICTIONARY *dict) {
+ debug(D_STATSD, "STATSD configuration reading file '%s'", filename);
char *buffer = mallocz(STATSD_CONF_LINE_MAX + 1);
- if(filename[0] == '/')
- strncpyz(buffer, filename, STATSD_CONF_LINE_MAX);
- else
- snprintfz(buffer, STATSD_CONF_LINE_MAX, "%s/%s", path, filename);
-
- FILE *fp = fopen(buffer, "r");
+ FILE *fp = fopen(filename, "r");
if(!fp) {
- error("STATSD: cannot open file '%s'.", buffer);
+ error("STATSD: cannot open file '%s'.", filename);
freez(buffer);
return -1;
}
@@ -1101,18 +1132,31 @@ static int statsd_readfile(const char *path, const char *filename, STATSD_APP *a
s = trim(buffer);
if (!s || *s == '#') {
- debug(D_STATSD, "STATSD: ignoring line %zu of file '%s/%s', it is empty.", line, path, filename);
+ debug(D_STATSD, "STATSD: ignoring line %zu of file '%s', it is empty.", line, filename);
continue;
}
- debug(D_STATSD, "STATSD: processing line %zu of file '%s/%s': %s", line, path, filename, buffer);
+ debug(D_STATSD, "STATSD: processing line %zu of file '%s': %s", line, filename, buffer);
if(*s == 'i' && strncmp(s, "include", 7) == 0) {
s = trim(&s[7]);
- if(s && *s)
- statsd_readfile(path, s, app, chart, dict);
+ if(s && *s) {
+ char *tmp;
+ if(*s == '/')
+ tmp = strdupz(s);
+ else {
+ // the file to be included is relative to current file
+ // find the directory name from the file we already read
+ char *filename2 = strdupz(filename); // copy filename, since dirname() will change it
+ char *dir = dirname(filename2); // find the directory part of the filename
+ tmp = strdupz_path_subpath(dir, s); // compose the new filename to read;
+ freez(filename2); // free the filename we copied
+ }
+ statsd_readfile(tmp, app, chart, dict);
+ freez(tmp);
+ }
else
- error("STATSD: ignoring line %zu of file '%s/%s', include filename is empty", line, path, s);
+ error("STATSD: ignoring line %zu of file '%s', include filename is empty", line, filename);
continue;
}
@@ -1160,7 +1204,7 @@ static int statsd_readfile(const char *path, const char *filename, STATSD_APP *a
chart->context = strdupz(s);
chart->family = strdupz("overview");
chart->units = strdupz("value");
- chart->priority = STATSD_CHART_PRIORITY;
+ chart->priority = NETDATA_CHART_PRIO_STATSD_PRIVATE;
chart->chart_type = RRDSET_TYPE_LINE;
chart->next = app->charts;
@@ -1174,20 +1218,20 @@ static int statsd_readfile(const char *path, const char *filename, STATSD_APP *a
}
}
else
- error("STATSD: ignoring line %zu ('%s') of file '%s/%s', [app] is not defined.", line, s, path, filename);
+ error("STATSD: ignoring line %zu ('%s') of file '%s', [app] is not defined.", line, s, filename);
continue;
}
if(!app) {
- error("STATSD: ignoring line %zu ('%s') of file '%s/%s', it is outside all sections.", line, s, path, filename);
+ error("STATSD: ignoring line %zu ('%s') of file '%s', it is outside all sections.", line, s, filename);
continue;
}
char *name = s;
char *value = strchr(s, '=');
if(!value) {
- error("STATSD: ignoring line %zu ('%s') of file '%s/%s', there is no = in it.", line, s, path, filename);
+ error("STATSD: ignoring line %zu ('%s') of file '%s', there is no = in it.", line, s, filename);
continue;
}
*value = '\0';
@@ -1197,11 +1241,11 @@ static int statsd_readfile(const char *path, const char *filename, STATSD_APP *a
value = trim(value);
if(!name || *name == '#') {
- error("STATSD: ignoring line %zu of file '%s/%s', name is empty.", line, path, filename);
+ error("STATSD: ignoring line %zu of file '%s', name is empty.", line, filename);
continue;
}
if(!value) {
- debug(D_CONFIG, "STATSD: ignoring line %zu of file '%s/%s', value is empty.", line, path, filename);
+ debug(D_CONFIG, "STATSD: ignoring line %zu of file '%s', value is empty.", line, filename);
continue;
}
@@ -1241,7 +1285,7 @@ static int statsd_readfile(const char *path, const char *filename, STATSD_APP *a
app->rrd_history_entries = 5;
}
else {
- error("STATSD: ignoring line %zu ('%s') of file '%s/%s'. Unknown keyword for the [app] section.", line, name, path, filename);
+ error("STATSD: ignoring line %zu ('%s') of file '%s'. Unknown keyword for the [app] section.", line, name, filename);
continue;
}
}
@@ -1326,14 +1370,14 @@ static int statsd_readfile(const char *path, const char *filename, STATSD_APP *a
, (multipler && *multipler)?str2l(multipler):1
, (divisor && *divisor)?str2l(divisor):1
, flags
- , string2valuetype(type, line, path, filename)
+ , string2valuetype(type, line, filename)
);
if(pattern)
dim->metric_pattern = simple_pattern_create(dim->metric, NULL, SIMPLE_PATTERN_EXACT);
}
else {
- error("STATSD: ignoring line %zu ('%s') of file '%s/%s'. Unknown keyword for the [%s] section.", line, name, path, filename, chart->id);
+ error("STATSD: ignoring line %zu ('%s') of file '%s'. Unknown keyword for the [%s] section.", line, name, filename, chart->id);
continue;
}
}
@@ -1344,49 +1388,13 @@ static int statsd_readfile(const char *path, const char *filename, STATSD_APP *a
return 0;
}
-static void statsd_readdir(const char *path) {
- size_t pathlen = strlen(path);
-
- debug(D_STATSD, "STATSD configuration reading directory '%s'", path);
-
- DIR *dir = opendir(path);
- if (!dir) {
- error("STATSD configuration cannot open directory '%s'.", path);
- return;
- }
-
- struct dirent *de = NULL;
- while ((de = readdir(dir))) {
- size_t len = strlen(de->d_name);
-
- if(de->d_type == DT_DIR
- && (
- (de->d_name[0] == '.' && de->d_name[1] == '\0')
- || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
- )) {
- debug(D_STATSD, "STATSD: ignoring directory '%s'", de->d_name);
- continue;
- }
-
- else if(de->d_type == DT_DIR) {
- char *s = mallocz(pathlen + strlen(de->d_name) + 2);
- strcpy(s, path);
- strcat(s, "/");
- strcat(s, de->d_name);
- statsd_readdir(s);
- freez(s);
- continue;
- }
-
- else if((de->d_type == DT_LNK || de->d_type == DT_REG || de->d_type == DT_UNKNOWN) &&
- len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
- statsd_readfile(path, de->d_name, NULL, NULL, NULL);
- }
-
- else debug(D_STATSD, "STATSD: ignoring file '%s'", de->d_name);
- }
+static int statsd_file_callback(const char *filename, void *data) {
+ (void)data;
+ return statsd_readfile(filename, NULL, NULL, NULL);
+}
- closedir(dir);
+static inline void statsd_readdir(const char *user_path, const char *stock_path, const char *subpath) {
+ recursive_config_double_dir_load(user_path, stock_path, subpath, statsd_file_callback, NULL, 0);
}
// --------------------------------------------------------------------------------------------------------------------
@@ -1445,7 +1453,7 @@ static inline RRDSET *statsd_private_rrdset_create(
, context // context
, title // title
, units // units
- , "statsd" // plugin
+ , PLUGIN_STATSD_NAME // plugin
, "private_chart" // module
, priority // priority
, update_every // update every
@@ -1484,7 +1492,7 @@ static inline void statsd_private_chart_gauge(STATSD_METRIC *m) {
, context // context
, title // title
, "value" // units
- , STATSD_CHART_PRIORITY
+ , NETDATA_CHART_PRIO_STATSD_PRIVATE
, statsd.update_every
, RRDSET_TYPE_LINE
);
@@ -1526,7 +1534,7 @@ static inline void statsd_private_chart_counter_or_meter(STATSD_METRIC *m, const
, context // context
, title // title
, "events/s" // units
- , STATSD_CHART_PRIORITY
+ , NETDATA_CHART_PRIO_STATSD_PRIVATE
, statsd.update_every
, RRDSET_TYPE_AREA
);
@@ -1568,7 +1576,7 @@ static inline void statsd_private_chart_set(STATSD_METRIC *m) {
, context // context
, title // title
, "entries" // units
- , STATSD_CHART_PRIORITY
+ , NETDATA_CHART_PRIO_STATSD_PRIVATE
, statsd.update_every
, RRDSET_TYPE_LINE
);
@@ -1610,7 +1618,7 @@ static inline void statsd_private_chart_timer_or_histogram(STATSD_METRIC *m, con
, context // context
, title // title
, units // units
- , STATSD_CHART_PRIORITY
+ , NETDATA_CHART_PRIO_STATSD_PRIVATE
, statsd.update_every
, RRDSET_TYPE_AREA
);
@@ -1649,14 +1657,14 @@ static inline void statsd_flush_gauge(STATSD_METRIC *m) {
debug(D_STATSD, "flushing gauge metric '%s'", m->name);
int updated = 0;
- if(m->count && !m->reset) {
+ if(unlikely(!m->reset && m->count)) {
m->last = (collected_number) (m->gauge.value * statsd.decimal_detail);
m->reset = 1;
updated = 1;
}
- if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED)))
+ if(unlikely(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED))))
statsd_private_chart_gauge(m);
}
@@ -1664,14 +1672,14 @@ static inline void statsd_flush_counter_or_meter(STATSD_METRIC *m, const char *d
debug(D_STATSD, "flushing %s metric '%s'", dim, m->name);
int updated = 0;
- if(m->count && !m->reset) {
+ if(unlikely(!m->reset && m->count)) {
m->last = m->counter.value;
m->reset = 1;
updated = 1;
}
- if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED)))
+ if(unlikely(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED))))
statsd_private_chart_counter_or_meter(m, dim, family);
}
@@ -1687,40 +1695,27 @@ static inline void statsd_flush_set(STATSD_METRIC *m) {
debug(D_STATSD, "flushing set metric '%s'", m->name);
int updated = 0;
- if(m->count && !m->reset) {
+ if(unlikely(!m->reset && m->count)) {
m->last = (collected_number)m->set.unique;
m->reset = 1;
updated = 1;
}
+ else {
+ m->last = 0;
+ }
- if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED)))
+ if(unlikely(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED))))
statsd_private_chart_set(m);
}
static inline void statsd_flush_timer_or_histogram(STATSD_METRIC *m, const char *dim, const char *family, const char *units) {
debug(D_STATSD, "flushing %s metric '%s'", dim, m->name);
- netdata_mutex_lock(&m->histogram.ext->mutex);
-
- if(unlikely(!m->histogram.ext->zeroed)) {
- // reset the metrics
- // if we collected anything, they will be updated below
- // this ensures that we report zeros if nothing is collected
-
- m->histogram.ext->last_min = 0;
- m->histogram.ext->last_max = 0;
- m->last = 0;
- m->histogram.ext->last_median = 0;
- m->histogram.ext->last_stddev = 0;
- m->histogram.ext->last_sum = 0;
- m->histogram.ext->last_percentile = 0;
-
- m->histogram.ext->zeroed = 1;
- }
-
int updated = 0;
- if(m->count && !m->reset && m->histogram.ext->used > 0) {
+ if(unlikely(!m->reset && m->count && m->histogram.ext->used > 0)) {
+ netdata_mutex_lock(&m->histogram.ext->mutex);
+
size_t len = m->histogram.ext->used;
LONG_DOUBLE *series = m->histogram.ext->values;
sort_series(series, len);
@@ -1738,6 +1733,8 @@ static inline void statsd_flush_timer_or_histogram(STATSD_METRIC *m, const char
else
m->histogram.ext->last_percentile = (collected_number)roundl(series[pct_len - 1] * statsd.decimal_detail);
+ netdata_mutex_unlock(&m->histogram.ext->mutex);
+
debug(D_STATSD, "STATSD %s metric %s: min " COLLECTED_NUMBER_FORMAT ", max " COLLECTED_NUMBER_FORMAT ", last " COLLECTED_NUMBER_FORMAT ", pcent " COLLECTED_NUMBER_FORMAT ", median " COLLECTED_NUMBER_FORMAT ", stddev " COLLECTED_NUMBER_FORMAT ", sum " COLLECTED_NUMBER_FORMAT,
dim, m->name, m->histogram.ext->last_min, m->histogram.ext->last_max, m->last, m->histogram.ext->last_percentile, m->histogram.ext->last_median, m->histogram.ext->last_stddev, m->histogram.ext->last_sum);
@@ -1745,11 +1742,24 @@ static inline void statsd_flush_timer_or_histogram(STATSD_METRIC *m, const char
m->reset = 1;
updated = 1;
}
+ else if(unlikely(!m->histogram.ext->zeroed)) {
+ // reset the metrics
+ // if we collected anything, they will be updated below
+ // this ensures that we report zeros if nothing is collected
- if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED)))
- statsd_private_chart_timer_or_histogram(m, dim, family, units);
+ m->histogram.ext->last_min = 0;
+ m->histogram.ext->last_max = 0;
+ m->last = 0;
+ m->histogram.ext->last_median = 0;
+ m->histogram.ext->last_stddev = 0;
+ m->histogram.ext->last_sum = 0;
+ m->histogram.ext->last_percentile = 0;
- netdata_mutex_unlock(&m->histogram.ext->mutex);
+ m->histogram.ext->zeroed = 1;
+ }
+
+ if(unlikely(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED))))
+ statsd_private_chart_timer_or_histogram(m, dim, family, units);
}
static inline void statsd_flush_timer(STATSD_METRIC *m) {
@@ -1837,6 +1847,7 @@ static inline void link_metric_to_app_dimension(STATSD_APP *app, STATSD_METRIC *
}
chart->dimensions_linked_count++;
+ m->options |= STATSD_METRIC_OPTION_USED_IN_APPS;
debug(D_STATSD, "metric '%s' of type %u linked with app '%s', chart '%s', dimension '%s', algorithm '%s'", m->name, m->type, app->name, chart->id, dim->name, rrd_algorithm_name(dim->algorithm));
}
@@ -1980,7 +1991,7 @@ static inline void statsd_update_app_chart(STATSD_APP *app, STATSD_APP_CHART *ch
, chart->context // context
, chart->title // title
, chart->units // units
- , "statsd" // plugin
+ , PLUGIN_STATSD_NAME // plugin
, chart->source // module
, chart->priority // priority
, statsd.update_every // update every
@@ -2043,7 +2054,13 @@ const char *statsd_metric_type_string(STATSD_METRIC_TYPE type) {
static inline void statsd_flush_index_metrics(STATSD_INDEX *index, void (*flush_metric)(STATSD_METRIC *)) {
STATSD_METRIC *m;
+
+ // find the useful metrics (incremental = each time we are called, we check the new metrics only)
for(m = index->first; m ; m = m->next) {
+ // since we add new metrics at the beginning
+ // check for useful charts, until the point we last checked
+ if(unlikely(is_metric_checked(m))) break;
+
if(unlikely(!(m->options & STATSD_METRIC_OPTION_CHECKED_IN_APPS))) {
log_access("NEW STATSD METRIC '%s': '%s'", statsd_metric_type_string(m->type), m->name);
check_if_metric_is_for_app(index, m);
@@ -2051,7 +2068,7 @@ static inline void statsd_flush_index_metrics(STATSD_INDEX *index, void (*flush_
}
if(unlikely(!(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED))) {
- if(statsd.private_charts >= statsd.max_private_charts_hard) {
+ if(unlikely(statsd.private_charts >= statsd.max_private_charts_hard)) {
debug(D_STATSD, "STATSD: metric '%s' will not be charted, because the hard limit of the maximum number of charts has been reached.", m->name);
info("STATSD: metric '%s' will not be charted, because the hard limit of the maximum number of charts (%zu) has been reached. Increase the number of charts by editing netdata.conf, [statsd] section.", m->name, statsd.max_private_charts);
m->options &= ~STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED;
@@ -2069,6 +2086,20 @@ static inline void statsd_flush_index_metrics(STATSD_INDEX *index, void (*flush_
m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED;
}
+ // mark it as checked
+ m->options |= STATSD_METRIC_OPTION_CHECKED;
+
+ // check if it is used in charts
+ if((m->options & (STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED|STATSD_METRIC_OPTION_USED_IN_APPS)) && !(m->options & STATSD_METRIC_OPTION_USEFUL)) {
+ m->options |= STATSD_METRIC_OPTION_USEFUL;
+ index->useful++;
+ m->next_useful = index->first_useful;
+ index->first_useful = m;
+ }
+ }
+
+ // flush all the useful metrics
+ for(m = index->first_useful; m ; m = m->next_useful) {
flush_metric(m);
}
}
@@ -2130,9 +2161,9 @@ void *statsd_main(void *ptr) {
statsd.max_private_charts_hard = (size_t)config_get_number(CONFIG_SECTION_STATSD, "max private charts hard limit", (long long)statsd.max_private_charts * 5);
statsd.private_charts_memory_mode = rrd_memory_mode_id(config_get(CONFIG_SECTION_STATSD, "private charts memory mode", rrd_memory_mode_name(default_rrd_memory_mode)));
statsd.private_charts_rrd_history_entries = (int)config_get_number(CONFIG_SECTION_STATSD, "private charts history", default_rrd_history_entries);
- statsd.decimal_detail = (size_t)config_get_number(CONFIG_SECTION_STATSD, "decimal detail", (long long int)statsd.decimal_detail);
+ statsd.decimal_detail = (collected_number)config_get_number(CONFIG_SECTION_STATSD, "decimal detail", (long long int)statsd.decimal_detail);
statsd.tcp_idle_timeout = (size_t) config_get_number(CONFIG_SECTION_STATSD, "disconnect idle tcp clients after seconds", (long long int)statsd.tcp_idle_timeout);
- statsd.private_charts_hidden = (int)config_get_boolean(CONFIG_SECTION_STATSD, "private charts hidden", statsd.private_charts_hidden);
+ statsd.private_charts_hidden = (unsigned int)config_get_boolean(CONFIG_SECTION_STATSD, "private charts hidden", statsd.private_charts_hidden);
statsd.histogram_percentile = (double)config_get_float(CONFIG_SECTION_STATSD, "histograms and timers percentile (percentThreshold)", statsd.histogram_percentile);
if(isless(statsd.histogram_percentile, 0) || isgreater(statsd.histogram_percentile, 100)) {
@@ -2186,11 +2217,7 @@ void *statsd_main(void *ptr) {
#endif
// read custom application definitions
- {
- char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/statsd.d", netdata_configured_config_dir);
- statsd_readdir(filename);
- }
+ statsd_readdir(netdata_configured_user_config_dir, netdata_configured_stock_config_dir, "statsd.d");
// ----------------------------------------------------------------------------------------------------------------
// statsd setup
@@ -2224,7 +2251,7 @@ void *statsd_main(void *ptr) {
, NULL
, "Metrics in the netdata statsd database"
, "metrics"
- , "statsd"
+ , PLUGIN_STATSD_NAME
, "stats"
, 132010
, statsd.update_every
@@ -2237,6 +2264,27 @@ void *statsd_main(void *ptr) {
RRDDIM *rd_metrics_histogram = rrddim_add(st_metrics, "histograms", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
RRDDIM *rd_metrics_set = rrddim_add(st_metrics, "sets", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ RRDSET *st_useful_metrics = rrdset_create_localhost(
+ "netdata"
+ , "statsd_useful_metrics"
+ , NULL
+ , "statsd"
+ , NULL
+ , "Useful metrics in the netdata statsd database"
+ , "metrics"
+ , PLUGIN_STATSD_NAME
+ , "stats"
+ , 132010
+ , statsd.update_every
+ , RRDSET_TYPE_STACKED
+ );
+ RRDDIM *rd_useful_metrics_gauge = rrddim_add(st_useful_metrics, "gauges", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ RRDDIM *rd_useful_metrics_counter = rrddim_add(st_useful_metrics, "counters", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ RRDDIM *rd_useful_metrics_timer = rrddim_add(st_useful_metrics, "timers", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ RRDDIM *rd_useful_metrics_meter = rrddim_add(st_useful_metrics, "meters", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ RRDDIM *rd_useful_metrics_histogram = rrddim_add(st_useful_metrics, "histograms", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ RRDDIM *rd_useful_metrics_set = rrddim_add(st_useful_metrics, "sets", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+
RRDSET *st_events = rrdset_create_localhost(
"netdata"
, "statsd_events"
@@ -2245,7 +2293,7 @@ void *statsd_main(void *ptr) {
, NULL
, "Events processed by the netdata statsd server"
, "events/s"
- , "statsd"
+ , PLUGIN_STATSD_NAME
, "stats"
, 132011
, statsd.update_every
@@ -2268,7 +2316,7 @@ void *statsd_main(void *ptr) {
, NULL
, "Read operations made by the netdata statsd server"
, "reads/s"
- , "statsd"
+ , PLUGIN_STATSD_NAME
, "stats"
, 132012
, statsd.update_every
@@ -2285,7 +2333,7 @@ void *statsd_main(void *ptr) {
, NULL
, "Bytes read by the netdata statsd server"
, "kilobits/s"
- , "netdata"
+ , PLUGIN_STATSD_NAME
, "stats"
, 132013
, statsd.update_every
@@ -2302,7 +2350,7 @@ void *statsd_main(void *ptr) {
, NULL
, "Network packets processed by the netdata statsd server"
, "packets/s"
- , "netdata"
+ , PLUGIN_STATSD_NAME
, "stats"
, 132014
, statsd.update_every
@@ -2319,7 +2367,7 @@ void *statsd_main(void *ptr) {
, NULL
, "statsd server TCP connects and disconnects"
, "events"
- , "statsd"
+ , PLUGIN_STATSD_NAME
, "stats"
, 132015
, statsd.update_every
@@ -2336,7 +2384,7 @@ void *statsd_main(void *ptr) {
, NULL
, "statsd server TCP connected sockets"
, "connected"
- , "statsd"
+ , PLUGIN_STATSD_NAME
, "stats"
, 132016
, statsd.update_every
@@ -2352,7 +2400,7 @@ void *statsd_main(void *ptr) {
, NULL
, "Private metric charts created by the netdata statsd server"
, "charts"
- , "statsd"
+ , PLUGIN_STATSD_NAME
, "stats"
, 132020
, statsd.update_every
@@ -2368,7 +2416,7 @@ void *statsd_main(void *ptr) {
, "netdata.statsd_cpu"
, "NetData statsd charting thread CPU usage"
, "milliseconds/s"
- , "statsd"
+ , PLUGIN_STATSD_NAME
, "stats"
, 132001
, statsd.update_every
@@ -2394,7 +2442,7 @@ void *statsd_main(void *ptr) {
, "netdata.statsd_cpu"
, title
, "milliseconds/s"
- , "statsd"
+ , PLUGIN_STATSD_NAME
, "stats"
, 132002 + i
, statsd.update_every
@@ -2430,6 +2478,7 @@ void *statsd_main(void *ptr) {
if(likely(hb_dt)) {
rrdset_next(st_metrics);
+ rrdset_next(st_useful_metrics);
rrdset_next(st_events);
rrdset_next(st_reads);
rrdset_next(st_bytes);
@@ -2450,6 +2499,14 @@ void *statsd_main(void *ptr) {
rrddim_set_by_pointer(st_metrics, rd_metrics_set, (collected_number)statsd.sets.metrics);
rrdset_done(st_metrics);
+ rrddim_set_by_pointer(st_useful_metrics, rd_useful_metrics_gauge, (collected_number)statsd.gauges.useful);
+ rrddim_set_by_pointer(st_useful_metrics, rd_useful_metrics_counter, (collected_number)statsd.counters.useful);
+ rrddim_set_by_pointer(st_useful_metrics, rd_useful_metrics_timer, (collected_number)statsd.timers.useful);
+ rrddim_set_by_pointer(st_useful_metrics, rd_useful_metrics_meter, (collected_number)statsd.meters.useful);
+ rrddim_set_by_pointer(st_useful_metrics, rd_useful_metrics_histogram, (collected_number)statsd.histograms.useful);
+ rrddim_set_by_pointer(st_useful_metrics, rd_useful_metrics_set, (collected_number)statsd.sets.useful);
+ rrdset_done(st_useful_metrics);
+
rrddim_set_by_pointer(st_events, rd_events_gauge, (collected_number)statsd.gauges.events);
rrddim_set_by_pointer(st_events, rd_events_counter, (collected_number)statsd.counters.events);
rrddim_set_by_pointer(st_events, rd_events_timer, (collected_number)statsd.timers.events);
diff --git a/collectors/statsd.plugin/statsd.h b/collectors/statsd.plugin/statsd.h
new file mode 100644
index 000000000..b741be76d
--- /dev/null
+++ b/collectors/statsd.plugin/statsd.h
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_STATSD_H
+#define NETDATA_STATSD_H 1
+
+#include "../../daemon/common.h"
+
+#define STATSD_LISTEN_PORT 8125
+#define STATSD_LISTEN_BACKLOG 4096
+
+#define NETDATA_PLUGIN_HOOK_STATSD \
+ { \
+ .name = "STATSD", \
+ .config_section = NULL, \
+ .config_name = NULL, \
+ .enabled = 1, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = statsd_main \
+ },
+
+
+extern void *statsd_main(void *ptr);
+
+#endif //NETDATA_STATSD_H
diff --git a/collectors/tc.plugin/Makefile.am b/collectors/tc.plugin/Makefile.am
new file mode 100644
index 000000000..f77e67d91
--- /dev/null
+++ b/collectors/tc.plugin/Makefile.am
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+CLEANFILES = \
+ tc-qos-helper.sh \
+ $(NULL)
+
+include $(top_srcdir)/build/subst.inc
+SUFFIXES = .in
+
+dist_plugins_SCRIPTS = \
+ tc-qos-helper.sh \
+ $(NULL)
+
+dist_noinst_DATA = \
+ tc-qos-helper.sh.in \
+ README.md \
+ $(NULL)
diff --git a/collectors/tc.plugin/Makefile.in b/collectors/tc.plugin/Makefile.in
new file mode 100644
index 000000000..d336e1f0d
--- /dev/null
+++ b/collectors/tc.plugin/Makefile.in
@@ -0,0 +1,562 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(top_srcdir)/build/subst.inc $(srcdir)/Makefile.in \
+ $(srcdir)/Makefile.am $(dist_plugins_SCRIPTS) \
+ $(dist_noinst_DATA)
+subdir = collectors/tc.plugin
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \
+ $(top_srcdir)/build/m4/ax_c__generic.m4 \
+ $(top_srcdir)/build/m4/ax_c_lto.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \
+ $(top_srcdir)/build/m4/ax_c_mallopt.m4 \
+ $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/build/m4/ax_pthread.m4 \
+ $(top_srcdir)/build/m4/jemalloc.m4 \
+ $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(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_noinst_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@
+OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSE_CANDIDATE = @SSE_CANDIDATE@
+STRIP = @STRIP@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+has_jemalloc = @has_jemalloc@
+has_tcmalloc = @has_tcmalloc@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libconfigdir = @libconfigdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+registrydir = @registrydir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+varlibdir = @varlibdir@
+webdir = @webdir@
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+CLEANFILES = \
+ tc-qos-helper.sh \
+ $(NULL)
+
+SUFFIXES = .in
+dist_plugins_SCRIPTS = \
+ tc-qos-helper.sh \
+ $(NULL)
+
+dist_noinst_DATA = \
+ tc-qos-helper.sh.in \
+ README.md \
+ $(NULL)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .in
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/build/subst.inc $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/tc.plugin/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu collectors/tc.plugin/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(top_srcdir)/build/subst.inc:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-dist_pluginsSCRIPTS: $(dist_plugins_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @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; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pluginsdir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pluginsdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dist_pluginsSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_plugins_SCRIPTS)'; test -n "$(pluginsdir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(pluginsdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pluginsdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_pluginsSCRIPTS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: 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_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_pluginsSCRIPTS
+
+.in:
+ if sed \
+ -e 's#[@]localstatedir_POST@#$(localstatedir)#g' \
+ -e 's#[@]sbindir_POST@#$(sbindir)#g' \
+ -e 's#[@]sysconfdir_POST@#$(sysconfdir)#g' \
+ -e 's#[@]pythondir_POST@#$(pythondir)#g' \
+ -e 's#[@]configdir_POST@#$(configdir)#g' \
+ -e 's#[@]libconfigdir_POST@#$(libconfigdir)#g' \
+ -e 's#[@]cachedir_POST@#$(cachedir)#g' \
+ $< > $@.tmp; then \
+ mv "$@.tmp" "$@"; \
+ else \
+ rm -f "$@.tmp"; \
+ false; \
+ 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.
+.NOEXPORT:
diff --git a/collectors/tc.plugin/README.md b/collectors/tc.plugin/README.md
new file mode 100644
index 000000000..6670c491f
--- /dev/null
+++ b/collectors/tc.plugin/README.md
@@ -0,0 +1,183 @@
+## tc.plugin
+
+Live demo - **[see it in action here](https://registry.my-netdata.io/#menu_tc)** !
+
+![qos](https://cloud.githubusercontent.com/assets/2662304/14439411/b7f36254-0033-11e6-93f0-c739bb6a1c3a.gif)
+
+Netdata monitors `tc` QoS classes for all interfaces.
+
+If you also use [FireQOS](http://firehol.org/tutorial/fireqos-new-user/) it will collect
+interface and class names.
+
+There is a [shell helper](tc-qos-helper.sh.in) for this (all parsing is done by the plugin
+in `C` code - this shell script is just a configuration for the command to run to get `tc` output).
+
+The source of the tc plugin is [here](plugin_tc.c). It is somewhat complex, because a state
+machine was needed to keep track of all the `tc` classes, including the pseudo classes tc
+dynamically creates.
+
+## Motivation
+
+One category of metrics missing in Linux monitoring, is bandwidth consumption for each open
+socket (inbound and outbound traffic). So, you cannot tell how much bandwidth your web server,
+your database server, your backup, your ssh sessions, etc are using.
+
+To solve this problem, the most *adventurous* Linux monitoring tools install kernel modules to
+capture all traffic, analyze it and provide reports per application. A lot of work, CPU intensive
+and with a great degree of risk (due to the kernel modules involved which might affect the
+stability of the whole system). Not to mention that such solutions are probably better suited
+for a core linux router in your network.
+
+Others use NFACCT, the netfilter accounting module which is already part of the Linux firewall.
+However, this would require configuring a firewall on every system you want to measure bandwidth.
+
+QoS monitoring attempts to solve this in a much cleaner way.
+
+## Introduction to QoS
+
+One of the features the Linux kernel has, but it is rarely used, is its ability to
+**apply QoS on traffic**. Even most interesting is that it can apply QoS to **both inbound and
+outbound traffic**.
+
+QoS is about 2 features:
+
+1. **Classify traffic**
+
+ Classification is the process of organizing traffic in groups, called **classes**.
+ Classification can evaluate every aspect of network packets, like source and destination ports,
+ source and destination IPs, netfilter marks, etc.
+
+ When you classify traffic, you just assign a label to it. For example **I call `web server`
+ traffic, the traffic from my server's tcp/80, tcp/443 and to my server's tcp/80, tcp/443,
+ while I call `web surfing` all other tcp/80 and tcp/443 traffic**. You can use any combinations
+ you like. There is no limit.
+
+2. **Apply traffic shaping rules to these classes**
+
+ Traffic shaping is used to control how network interface bandwidth should be shared among the
+ classes. Of course we are not interested for this feature to just monitor the traffic.
+ Classification will be enough for monitoring everything.
+
+The key reasons of applying QoS on all servers (even cloud ones) are:
+
+ - **ensure administrative tasks (like ssh, dns, etc) will always have a small but guaranteed
+ bandwidth.** QoS can guarantee that services like ssh, dns, ntp, etc will always have a small
+ supply of bandwidth. So, no matter what happens, you will be able to ssh to your server and
+ DNS will always work.
+
+ - **ensure other administrative tasks will not monopolize all the available bandwidth.**
+ Services like backups, file copies, database dumps, etc can easily monopolize all the
+ available bandwidth. It is common for example a nightly backup, or a huge file transfer
+ to negatively influence the end-user experience. QoS can fix that.
+
+ - **ensure each end-user connection will get a fair cut of the available bandwidth.**
+ Several QoS queuing disciplines in Linux do this automatically, without any configuration from you.
+ The result is that new sockets are favored over older ones, so that users will get a snappier
+ experience, while others are transferring large amounts of traffic.
+
+ - **protect the servers from DDoS attacks.**
+ When your system is under a DDoS attack, it will get a lot more bandwidth compared to the one it
+ can handle and probably your applications will crash. Setting a limit on the inbound traffic using
+ QoS, will protect your servers (throttle the requests) and depending on the size of the attack may
+ allow your legitimate users to access the server, while the attack is taking place.
+
+
+Once **traffic classification** is applied, netdata can visualize the bandwidth consumption per
+class in real-time (no configuration is needed for netdata - it will figure it out).
+
+QoS, is extremely light. You will configure it once, and this is it. It will not bother you again
+and it will not use any noticeable CPU resources, especially on application and database servers.
+
+## QoS in Linux? Have you lost your mind?
+
+Yes I know... but no, I have not!
+
+Of course, `tc` is probably **the most undocumented, complicated and unfriendly** command in Linux.
+
+For example, for matching a simple port range in `tc`, e.g. all the high ports, from 1025 to 65535
+inclusive, you have to match these:
+
+```
+1025/0xffff 1026/0xfffe 1028/0xfffc 1032/0xfff8 1040/0xfff0
+1056/0xffe0 1088/0xffc0 1152/0xff80 1280/0xff00 1536/0xfe00
+2048/0xf800 4096/0xf000 8192/0xe000 16384/0xc000 32768/0x8000
+```
+
+I know what you are thinking right now! **And I agree!**
+
+This is why I wrote **[FireQOS](https://firehol.org/tutorial/fireqos-new-user/)**, a tool to
+simplify QoS management in Linux.
+
+The **[FireHOL](https://firehol.org/)** package already distributes **[FireQOS](https://firehol.org/tutorial/fireqos-new-user/)**.
+Check the **[FireQOS tutorial](https://firehol.org/tutorial/fireqos-new-user/)**
+to learn how to write your own QoS configuration.
+
+With **[FireQOS](https://firehol.org/tutorial/fireqos-new-user/)**, it is **really simple for everyone
+to use QoS in Linux**. Just install the package `firehol`. It should already be available for your
+distribution. If not, check the **[FireHOL Installation Guide](https://firehol.org/installing/)**.
+After that, you will have the `fireqos` command.
+
+This is the file `/etc/firehol/fireqos.conf` we use at the netdata demo site:
+
+```sh
+ # configure the netdata ports
+ server_netdata_ports="tcp/19999"
+
+ interface eth0 world bidirectional ethernet balanced rate 50Mbit
+ class arp
+ match arp
+
+ class icmp
+ match icmp
+
+ class dns commit 1Mbit
+ server dns
+ client dns
+
+ class ntp
+ server ntp
+ client ntp
+
+ class ssh commit 2Mbit
+ server ssh
+ client ssh
+
+ class rsync commit 2Mbit max 10Mbit
+ server rsync
+ client rsync
+
+ class web_server commit 40Mbit
+ server http
+ server netdata
+
+ class client
+ client surfing
+
+ class nms commit 1Mbit
+ match input src 10.2.3.5
+```
+
+Nothing more is needed. You just run `fireqos start` to apply this configuration, restart netdata
+and you have real-time visualization of the bandwidth consumption of your applications. FireQOS is
+not a daemon. It will just convert the configuration to `tc` commands. It will run them and it will
+exit.
+
+**IMPORTANT**: If you copy this configuration to apply it to your system, please adapt the
+speeds - experiment in non-production environments to learn the tool, before applying it on
+your servers.
+
+And this is what you are going to get:
+
+![image](https://cloud.githubusercontent.com/assets/2662304/14436322/c91d90a4-0024-11e6-9fb1-57cdef1580df.png)
+
+---
+
+## More examples:
+
+This is QoS from a linux router. Check these features:
+
+1. It is real-time (per second updates)
+2. QoS really works in Linux - check that the `background` traffic is squeezed when `surfing` needs it.
+
+![test2](https://cloud.githubusercontent.com/assets/2662304/14093004/68966020-f553-11e5-98fe-ffee2086fafd.gif)
+
diff --git a/src/plugin_tc.c b/collectors/tc.plugin/plugin_tc.c
index 4b6d84e11..083cc2986 100644
--- a/src/plugin_tc.c
+++ b/collectors/tc.plugin/plugin_tc.c
@@ -1,6 +1,9 @@
-#include "common.h"
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_tc.h"
#define RRD_TYPE_TC "tc"
+#define PLUGIN_TC_NAME "tc.plugin"
// ----------------------------------------------------------------------------
// /sbin/tc processor
@@ -391,9 +394,9 @@ static inline void tc_device_commit(struct tc_device *d) {
, RRD_TYPE_TC ".qos"
, "Class Usage"
, "kilobits/s"
- , "tc"
+ , PLUGIN_TC_NAME
, NULL
- , 7000
+ , NETDATA_CHART_PRIO_TC_QOS
, localhost->rrd_update_every
, d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED
);
@@ -402,7 +405,7 @@ static inline void tc_device_commit(struct tc_device *d) {
rrdset_next(d->st_bytes);
if(unlikely(d->name_updated)) rrdset_set_name(d->st_bytes, d->name);
- // FIXME
+ // TODO
// update the family
}
@@ -439,9 +442,9 @@ static inline void tc_device_commit(struct tc_device *d) {
, RRD_TYPE_TC ".qos_packets"
, "Class Packets"
, "packets/s"
- , "tc"
+ , PLUGIN_TC_NAME
, NULL
- , 7010
+ , NETDATA_CHART_PRIO_TC_QOS_PACKETS
, localhost->rrd_update_every
, d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED
);
@@ -455,7 +458,7 @@ static inline void tc_device_commit(struct tc_device *d) {
rrdset_set_name(d->st_packets, name);
}
- // FIXME
+ // TODO
// update the family
}
@@ -492,9 +495,9 @@ static inline void tc_device_commit(struct tc_device *d) {
, RRD_TYPE_TC ".qos_dropped"
, "Class Dropped Packets"
, "packets/s"
- , "tc"
+ , PLUGIN_TC_NAME
, NULL
- , 7020
+ , NETDATA_CHART_PRIO_TC_QOS_DROPPED
, localhost->rrd_update_every
, d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED
);
@@ -508,7 +511,7 @@ static inline void tc_device_commit(struct tc_device *d) {
rrdset_set_name(d->st_dropped, name);
}
- // FIXME
+ // TODO
// update the family
}
@@ -545,9 +548,9 @@ static inline void tc_device_commit(struct tc_device *d) {
, RRD_TYPE_TC ".qos_tokens"
, "Class Tokens"
, "tokens"
- , "tc"
+ , PLUGIN_TC_NAME
, NULL
- , 7030
+ , NETDATA_CHART_PRIO_TC_QOS_TOCKENS
, localhost->rrd_update_every
, RRDSET_TYPE_LINE
);
@@ -561,7 +564,7 @@ static inline void tc_device_commit(struct tc_device *d) {
rrdset_set_name(d->st_tokens, name);
}
- // FIXME
+ // TODO
// update the family
}
@@ -599,9 +602,9 @@ static inline void tc_device_commit(struct tc_device *d) {
, RRD_TYPE_TC ".qos_ctokens"
, "Class cTokens"
, "ctokens"
- , "tc"
+ , PLUGIN_TC_NAME
, NULL
- , 7040
+ , NETDATA_CHART_PRIO_TC_QOS_CTOCKENS
, localhost->rrd_update_every
, RRDSET_TYPE_LINE
);
@@ -616,7 +619,7 @@ static inline void tc_device_commit(struct tc_device *d) {
rrdset_set_name(d->st_ctokens, name);
}
- // FIXME
+ // TODO
// update the family
}
@@ -857,7 +860,7 @@ void *tc_main(void *ptr) {
struct rusage thread;
- char buffer[TC_LINE_MAX+1] = "";
+ char command[FILENAME_MAX + 1];
char *words[PLUGINSD_MAX_WORDS] = { NULL };
uint32_t BEGIN_HASH = simple_hash("BEGIN");
@@ -876,23 +879,24 @@ void *tc_main(void *ptr) {
#endif
uint32_t first_hash;
- snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", netdata_configured_plugins_dir);
- char *tc_script = config_get("plugin:tc", "script to run to get tc values", buffer);
+ snprintfz(command, 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", command);
while(!netdata_exit) {
FILE *fp;
struct tc_device *device = NULL;
struct tc_class *class = NULL;
- snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, localhost->rrd_update_every);
- debug(D_TC_LOOP, "executing '%s'", buffer);
+ snprintfz(command, TC_LINE_MAX, "exec %s %d", tc_script, localhost->rrd_update_every);
+ debug(D_TC_LOOP, "executing '%s'", command);
- fp = mypopen(buffer, (pid_t *)&tc_child_pid);
+ fp = mypopen(command, (pid_t *)&tc_child_pid);
if(unlikely(!fp)) {
- error("TC: Cannot popen(\"%s\", \"r\").", buffer);
+ error("TC: Cannot popen(\"%s\", \"r\").", command);
goto cleanup;
}
+ char buffer[TC_LINE_MAX+1] = "";
while(fgets(buffer, TC_LINE_MAX, fp) != NULL) {
if(unlikely(netdata_exit)) break;
@@ -1074,9 +1078,9 @@ void *tc_main(void *ptr) {
, NULL
, "NetData TC CPU usage"
, "milliseconds/s"
- , "tc"
+ , PLUGIN_TC_NAME
, NULL
- , 135000
+ , NETDATA_CHART_PRIO_NETDATA_TC_CPU
, localhost->rrd_update_every
, RRDSET_TYPE_STACKED
);
@@ -1101,9 +1105,9 @@ void *tc_main(void *ptr) {
, NULL
, "NetData TC script execution"
, "milliseconds/run"
- , "tc"
+ , PLUGIN_TC_NAME
, NULL
- , 135001
+ , NETDATA_CHART_PRIO_NETDATA_TC_TIME
, localhost->rrd_update_every
, RRDSET_TYPE_AREA
);
diff --git a/collectors/tc.plugin/plugin_tc.h b/collectors/tc.plugin/plugin_tc.h
new file mode 100644
index 000000000..c64658415
--- /dev/null
+++ b/collectors/tc.plugin/plugin_tc.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_PLUGIN_TC_H
+#define NETDATA_PLUGIN_TC_H 1
+
+#include "../../daemon/common.h"
+
+#if (TARGET_OS == OS_LINUX)
+
+#define NETDATA_PLUGIN_HOOK_LINUX_TC \
+ { \
+ .name = "PLUGIN[tc]", \
+ .config_section = CONFIG_SECTION_PLUGINS, \
+ .config_name = "tc", \
+ .enabled = 1, \
+ .thread = NULL, \
+ .init_routine = NULL, \
+ .start_routine = tc_main \
+ },
+
+extern void *tc_main(void *ptr);
+
+#else // (TARGET_OS == OS_LINUX)
+
+#define NETDATA_PLUGIN_HOOK_LINUX_TC
+
+#endif // (TARGET_OS == OS_LINUX)
+
+
+#endif /* NETDATA_PLUGIN_TC_H */
+
diff --git a/plugins.d/tc-qos-helper.sh b/collectors/tc.plugin/tc-qos-helper.sh
index 9153f22e2..b49d1f509 100755..100644
--- a/plugins.d/tc-qos-helper.sh
+++ b/collectors/tc.plugin/tc-qos-helper.sh
@@ -3,7 +3,7 @@
# netdata
# real-time performance and health monitoring, done right!
# (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
-# GPL v3+
+# SPDX-License-Identifier: GPL-3.0-or-later
#
# This script is a helper to allow netdata collect tc data.
# tc output parsing has been implemented in C, inside netdata
@@ -14,6 +14,47 @@ export LC_ALL=C
# -----------------------------------------------------------------------------
+# logging functions
+
+PROGRAM_FILE="$0"
+PROGRAM_NAME="$(basename $0)"
+PROGRAM_NAME="${PROGRAM_NAME/.plugin}"
+
+logdate() {
+ date "+%Y-%m-%d %H:%M:%S"
+}
+
+log() {
+ local status="${1}"
+ shift
+
+ echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}"
+
+}
+
+warning() {
+ log WARNING "${@}"
+}
+
+error() {
+ log ERROR "${@}"
+}
+
+info() {
+ log INFO "${@}"
+}
+
+fatal() {
+ log FATAL "${@}"
+ exit 1
+}
+
+debug=0
+debug() {
+ [ $debug -eq 1 ] && log DEBUG "${@}"
+}
+
+# -----------------------------------------------------------------------------
# find /var/run/fireqos
# the default
@@ -52,60 +93,24 @@ if [ ! -d "${fireqos_run_dir}" ]
if [ -d "${LOCALSTATEDIR}/run/fireqos" ]
then
fireqos_run_dir="${LOCALSTATEDIR}/run/fireqos"
+ else
+ warning "FireQoS is installed as '${fireqos}', its installation config at '${fireqos_exec_dir}/install.config' specifies local state data at '${LOCALSTATEDIR}/run/fireqos', but this directory is not found or is not readable (check the permissions of its parents)."
fi
+ else
+ warning "Although FireQoS is installed on this system as '${fireqos}', I cannot find/read its installation configuration at '${fireqos_exec_dir}/install.config'."
fi
+ else
+ warning "FireQoS is not installed on this system. Use FireQoS to apply traffic QoS and expose the class names to netdata. Check https://github.com/netdata/netdata/wiki/You-should-install-QoS-on-all-your-servers"
fi
fi
# -----------------------------------------------------------------------------
-# logging functions
-
-PROGRAM_FILE="$0"
-PROGRAM_NAME="$(basename $0)"
-PROGRAM_NAME="${PROGRAM_NAME/.plugin}"
-
-logdate() {
- date "+%Y-%m-%d %H:%M:%S"
-}
-
-log() {
- local status="${1}"
- shift
-
- echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}"
-
-}
-
-warning() {
- log WARNING "${@}"
-}
-
-error() {
- log ERROR "${@}"
-}
-
-info() {
- log INFO "${@}"
-}
-
-fatal() {
- log FATAL "${@}"
- exit 1
-}
-
-debug=0
-debug() {
- [ $debug -eq 1 ] && log DEBUG "${@}"
-}
-
-
-# -----------------------------------------------------------------------------
[ -z "${NETDATA_PLUGINS_DIR}" ] && NETDATA_PLUGINS_DIR="$(dirname "${0}")"
-[ -z "${NETDATA_CONFIG_DIR}" ] && NETDATA_CONFIG_DIR="$(dirname "${0}")/../../../../etc/netdata"
+[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="/usr/local/etc/netdata"
+[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="/usr/local/lib/netdata/conf.d"
plugins_dir="${NETDATA_PLUGINS_DIR}"
-config_dir="${NETDATA_CONFIG_DIR}"
tc="$(which tc 2>/dev/null || command -v tc 2>/dev/null)"
@@ -134,10 +139,17 @@ update_every=$((t))
# -----------------------------------------------------------------------------
# allow the user to override our defaults
-if [ -f "${config_dir}/tc-qos-helper.conf" ]
- then
- source "${config_dir}/tc-qos-helper.conf"
-fi
+for CONFIG in "${NETDATA_STOCK_CONFIG_DIR}/tc-qos-helper.conf" "${NETDATA_USER_CONFIG_DIR}/tc-qos-helper.conf"
+do
+ if [ -f "${CONFIG}" ]
+ then
+ info "Loading config file '${CONFIG}'..."
+ source "${CONFIG}"
+ [ $? -ne 0 ] && error "Failed to load config file '${CONFIG}'."
+ else
+ warning "Cannot find file '${CONFIG}'."
+ fi
+done
case "${tc_show}" in
qdisc|class)
diff --git a/collectors/tc.plugin/tc-qos-helper.sh.in b/collectors/tc.plugin/tc-qos-helper.sh.in
new file mode 100755
index 000000000..6f6b0a591
--- /dev/null
+++ b/collectors/tc.plugin/tc-qos-helper.sh.in
@@ -0,0 +1,315 @@
+#!/usr/bin/env bash
+
+# netdata
+# real-time performance and health monitoring, done right!
+# (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This script is a helper to allow netdata collect tc data.
+# tc output parsing has been implemented in C, inside netdata
+# This script allows setting names to dimensions.
+
+export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin"
+export LC_ALL=C
+
+
+# -----------------------------------------------------------------------------
+# logging functions
+
+PROGRAM_FILE="$0"
+PROGRAM_NAME="$(basename $0)"
+PROGRAM_NAME="${PROGRAM_NAME/.plugin}"
+
+logdate() {
+ date "+%Y-%m-%d %H:%M:%S"
+}
+
+log() {
+ local status="${1}"
+ shift
+
+ echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}"
+
+}
+
+warning() {
+ log WARNING "${@}"
+}
+
+error() {
+ log ERROR "${@}"
+}
+
+info() {
+ log INFO "${@}"
+}
+
+fatal() {
+ log FATAL "${@}"
+ exit 1
+}
+
+debug=0
+debug() {
+ [ $debug -eq 1 ] && log DEBUG "${@}"
+}
+
+# -----------------------------------------------------------------------------
+# 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"
+ else
+ warning "FireQoS is installed as '${fireqos}', its installation config at '${fireqos_exec_dir}/install.config' specifies local state data at '${LOCALSTATEDIR}/run/fireqos', but this directory is not found or is not readable (check the permissions of its parents)."
+ fi
+ else
+ warning "Although FireQoS is installed on this system as '${fireqos}', I cannot find/read its installation configuration at '${fireqos_exec_dir}/install.config'."
+ fi
+ else
+ warning "FireQoS is not installed on this system. Use FireQoS to apply traffic QoS and expose the class names to netdata. Check https://github.com/netdata/netdata/wiki/You-should-install-QoS-on-all-your-servers"
+ fi
+fi
+
+# -----------------------------------------------------------------------------
+
+[ -z "${NETDATA_PLUGINS_DIR}" ] && NETDATA_PLUGINS_DIR="$(dirname "${0}")"
+[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@"
+[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="@libconfigdir_POST@"
+
+plugins_dir="${NETDATA_PLUGINS_DIR}"
+tc="$(which tc 2>/dev/null || command -v tc 2>/dev/null)"
+
+
+# -----------------------------------------------------------------------------
+# 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
+
+for CONFIG in "${NETDATA_STOCK_CONFIG_DIR}/tc-qos-helper.conf" "${NETDATA_USER_CONFIG_DIR}/tc-qos-helper.conf"
+do
+ if [ -f "${CONFIG}" ]
+ then
+ info "Loading config file '${CONFIG}'..."
+ source "${CONFIG}"
+ [ $? -ne 0 ] && error "Failed to load config file '${CONFIG}'."
+ else
+ warning "Cannot find file '${CONFIG}'."
+ fi
+done
+
+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
+}
+
+# if found and included, this file overwrites 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."
+fi
+
+tc_devices=
+fix_names=
+
+# -----------------------------------------------------------------------------
+
+setclassname() {
+ 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 ]
+ then
+ local classid name rest
+ while read classid name rest
+ do
+ [ -z "${classid}" -o -z "${name}" -o "${classid}" = "#" -o "${name}" = "#" -o "${classid:0:1}" = "#" -o "${name:0:1}" = "#" ] && continue
+ setclassname "" "${name}" "${classid}"
+ done </etc/iproute2/tc_cls
+ return 0
+ fi
+ return 1
+}
+
+show_fireqos_names() {
+ local x="${1}" name n interface_dev interface_classes interface_classes_monitor
+
+ if [ -f "${fireqos_run_dir}/ifaces/${x}" ]
+ then
+ name="$(<"${fireqos_run_dir}/ifaces/${x}")"
+ echo "SETDEVICENAME ${name}"
+
+ interface_dev=
+ interface_classes=
+ interface_classes_monitor=
+ source "${fireqos_run_dir}/${name}.conf"
+ for n in ${interface_classes_monitor}
+ do
+ setclassname ${n//|/ }
+ done
+ [ ! -z "${interface_dev}" ] && echo "SETDEVICEGROUP ${interface_dev}"
+
+ return 0
+ fi
+
+ return 1
+}
+
+show_tc() {
+ local x="${1}"
+
+ echo "BEGIN ${x}"
+
+ # netdata can parse the output of tc
+ ${tc} -s ${tc_show} show dev ${x}
+
+ # check FireQOS names for classes
+ if [ ! -z "${fix_names}" ]
+ then
+ show_fireqos_names "${x}" || show_tc_cls "${x}"
+ fi
+
+ echo "END ${x}"
+}
+
+find_tc_devices() {
+ local count=0 devs= dev rest l
+
+ # find all the devices in the system
+ # without forking
+ while IFS=":| " read dev rest
+ do
+ count=$((count + 1))
+ [ ${count} -le 2 ] && continue
+ devs="${devs} ${dev}"
+ done </proc/net/dev
+
+ # from all the devices find the ones
+ # that have QoS defined
+ # unfortunately, one fork per device cannot be avoided
+ tc_devices=
+ for dev in ${devs}
+ do
+ l="$(${tc} class show dev ${dev} 2>/dev/null)"
+ [ ! -z "${l}" ] && tc_devices="${tc_devices} ${dev}"
+ done
+}
+
+# update devices and class names
+# once every 2 minutes
+names_every=$((qos_get_class_names_every / update_every))
+
+# exit this script every hour
+# it will be restarted automatically
+exit_after=$((qos_exit_every / update_every))
+
+c=0
+gc=0
+while [ 1 ]
+do
+ fix_names=
+ c=$((c + 1))
+ gc=$((gc + 1))
+
+ if [ ${c} -le 1 -o ${c} -ge ${names_every} ]
+ then
+ c=1
+ fix_names="YES"
+ find_tc_devices
+ fi
+
+ for d in ${tc_devices}
+ do
+ show_tc ${d}
+ done
+
+ echo "WORKTIME ${LOOPSLEEPMS_LASTWORK}"
+
+ loopsleepms ${update_every}
+
+ [ ${gc} -gt ${exit_after} ] && exit 0
+done