Remove obsolete python modules (#5659)
##### Summary Fixes: #5647 ___ Remove obolete python modules: - cpuidle (moved to proc plugin #4635) - cpufreq (moved to proc plugin #4562) - mdstat (moved to proc plugin #4768) - linux_power_supply (moved to proc plugin #4960) ##### Component Name [/collectors/python.d.plugin/](https://github.com/netdata/netdata/tree/master/collectors/python.d.plugin) ##### Additional Information
Ilya Mashchenko committed
Mar 19, 2019 at 13:39 UTC
3777b91736bfadb7c659ceb74e3c48c4054b8b27
20 files changed
+6
-1041
README.md
+5
-5
@@ -186,7 +186,7 @@ The key improvements are:
186
187
- Improved internal database to support values above 64bit.
188
- New data collection plugins: [`openldap`](collectors/python.d.plugin/openldap/), [`tor`](collectors/python.d.plugin/tor/), [`nvidia_smi`](collectors/python.d.plugin/nvidia_smi/).
189
-- Improved data collection plugins: netdata now supports monitoring network interface aliases, [`smartd_log`](collectors/python.d.plugin/smartd_log/), [`cpufreq`](collectors/python.d.plugin/cpufreq/), [`sensors`](collectors/python.d.plugin/sensors/).
189
+- Improved data collection plugins: netdata now supports monitoring network interface aliases, [`smartd_log`](collectors/python.d.plugin/smartd_log/), [`cpufreq`](collectors/proc.plugin/README.md#cpu-frequency), [`sensors`](collectors/python.d.plugin/sensors/).
190
- Health monitoring improvements: network interface congestion alarm restored, [`alerta.io`](health/notifications/alerta/), `conntrack_max`.
191
- `my-netdata`menu has been refactored.
192
- Packaging: `openrc` service definition got a few improvements.
@@ -317,8 +317,8 @@ Its [Plugin API](collectors/plugins.d/) supports all programing languages (anyth
317
- **[SoftIRQs](collectors/proc.plugin/)** - total and per core SoftIRQs.
318
- **[SoftNet](collectors/proc.plugin/)** - total and per core SoftIRQs related to network activity.
319
- **[CPU Throttling](collectors/proc.plugin/)** - collects per core CPU throttling.
320
-- **[CPU Frequency](collectors/python.d.plugin/couchdb/)** - collects the current CPU frequency.
321
-- **[CPU Idle](collectors/python.d.plugin/cpuidle/)** - collects the time spent per processor state.
320
+- **[CPU Frequency](collectors/proc.plugin/)** - collects the current CPU frequency.
321
+- **[CPU Idle](collectors/proc.plugin/)** - collects the time spent per processor state.
322
- **[IdleJitter](collectors/idlejitter.plugin/)** - measures CPU latency.
323
- **[Entropy](collectors/proc.plugin/)** - random numbers pool, using in cryptography.
324
- **[Interprocess Communication - IPC](collectors/proc.plugin/)** - such as semaphores and semaphores arrays.
@@ -339,7 +339,7 @@ Its [Plugin API](collectors/plugins.d/) supports all programing languages (anyth
339
- **[block devices](collectors/proc.plugin/)** - per disk: I/O, operations, backlog, utilization, space, etc.
340
- **[BCACHE](collectors/proc.plugin/)** - detailed performance of SSD caching devices.
341
- **[DiskSpace](collectors/proc.plugin/)** - monitors disk space usage.
342
-- **[mdstat](collectors/python.d.plugin/mdstat/)** - software RAID.
342
+- **[mdstat](collectors/proc.plugin/)** - software RAID.
343
- **[hddtemp](collectors/python.d.plugin/hddtemp/)** - disk temperatures.
344
- **[smartd](collectors/python.d.plugin/smartd_log/)** - disk S.M.A.R.T. values.
345
- **[device mapper](collectors/proc.plugin/)** - naming disks.
@@ -448,7 +448,7 @@ Its [Plugin API](collectors/plugins.d/) supports all programing languages (anyth
448
#### UPSes
449
- **[apcupsd](collectors/charts.d.plugin/apcupsd/)** - load, charge, battery voltage, temperature, utility metrics, output metrics
450
- **[NUT](collectors/charts.d.plugin/nut/)** - load, charge, battery voltage, temperature, utility metrics, output metrics
451
-- **[Linux Power Supply](collectors/python.d.plugin/linux_power_supply/)** - collects metrics reported by power supply drivers on Linux.
451
+- **[Linux Power Supply](collectors/proc.plugin/)** - collects metrics reported by power supply drivers on Linux.
452
453
#### Social Sharing Servers
454
- **[RetroShare](collectors/python.d.plugin/retroshare/)** - connects to multiple retroshare servers (local or remote) to collect real-time performance metrics.
collectors/python.d.plugin/Makefile.am
-4
@@ -44,8 +44,6 @@ include boinc/Makefile.inc
44
include ceph/Makefile.inc
45
include chrony/Makefile.inc
46
include couchdb/Makefile.inc
47
-include cpufreq/Makefile.inc
48
-include cpuidle/Makefile.inc
47
include dnsdist/Makefile.inc
48
include dns_query_time/Makefile.inc
49
include dockerd/Makefile.inc
@@ -62,10 +60,8 @@ include httpcheck/Makefile.inc
60
include icecast/Makefile.inc
61
include ipfs/Makefile.inc
62
include isc_dhcpd/Makefile.inc
65
-include linux_power_supply/Makefile.inc
63
include litespeed/Makefile.inc
64
include logind/Makefile.inc
68
-include mdstat/Makefile.inc
65
include megacli/Makefile.inc
66
include memcached/Makefile.inc
67
include mongodb/Makefile.inc
collectors/python.d.plugin/cpufreq/Makefile.inc
deleted
-13
@@ -1,13 +0,0 @@
1
-# SPDX-License-Identifier: GPL-3.0-or-later
2
-
3
-# THIS IS NOT A COMPLETE Makefile
4
-# IT IS INCLUDED BY ITS PARENT'S Makefile.am
5
-# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
6
-
7
-# install these files
8
-dist_python_DATA += cpufreq/cpufreq.chart.py
9
-dist_pythonconfig_DATA += cpufreq/cpufreq.conf
10
-
11
-# do not install these files, but include them in the distribution
12
-dist_noinst_DATA += cpufreq/README.md cpufreq/Makefile.inc
13
-
collectors/python.d.plugin/cpufreq/README.md
deleted
-37
@@ -1,37 +0,0 @@
1
-# cpufreq
2
-
3
-> THIS MODULE IS OBSOLETE.
4
-> USE THE [PROC PLUGIN](../../proc.plugin) - IT IS MORE EFFICIENT
5
-
6
----
7
-
8
-This module shows the current CPU frequency as set by the cpufreq kernel
9
-module.
10
-
11
-**Requirement:**
12
-You need to have `CONFIG_CPU_FREQ` and (optionally) `CONFIG_CPU_FREQ_STAT`
13
-enabled in your kernel.
14
-
15
-This module tries to read from one of two possible locations. On
16
-initialization, it tries to read the `time_in_state` files provided by
17
-cpufreq\_stats. If this file does not exist, or doesn't contain valid data, it
18
-falls back to using the more inaccurate `scaling_cur_freq` file (which only
19
-represents the **current** CPU frequency, and doesn't account for any state
20
-changes which happen between updates).
21
-
22
-It produces one chart with multiple lines (one line per core).
23
-
24
-### configuration
25
-
26
-Sample:
27
-
28
-```yaml
29
-sys_dir: "/sys/devices"
30
-```
31
-
32
-If no configuration is given, module will search for cpufreq files in `/sys/devices` directory.
33
-Directory is also prefixed with `NETDATA_HOST_PREFIX` if specified.
34
-
35
----
36
-
37
-[]()
collectors/python.d.plugin/cpufreq/cpufreq.chart.py
deleted
-115
@@ -1,115 +0,0 @@
1
-# -*- coding: utf-8 -*-
2
-# Description: cpufreq netdata python.d module
3
-# Author: Pawel Krupa (paulfantom)
4
-# Author: Steven Noonan (tycho)
5
-# SPDX-License-Identifier: GPL-3.0-or-later
6
-
7
-import glob
8
-import os
9
-
10
-from bases.FrameworkServices.SimpleService import SimpleService
11
-
12
-# default module values (can be overridden per job in `config`)
13
-# update_every = 2
14
-
15
-ORDER = ['cpufreq']
16
-
17
-CHARTS = {
18
- 'cpufreq': {
19
- 'options': [None, 'CPU Clock', 'MHz', 'cpufreq', 'cpufreq.cpufreq', 'line'],
20
- 'lines': [
21
- # lines are created dynamically in `check()` method
22
- ]
23
- }
24
-}
25
-
26
-
27
-class Service(SimpleService):
28
- def __init__(self, configuration=None, name=None):
29
- prefix = os.getenv('NETDATA_HOST_PREFIX', "")
30
- if prefix.endswith('/'):
31
- prefix = prefix[:-1]
32
- self.sys_dir = prefix + "/sys/devices"
33
- SimpleService.__init__(self, configuration=configuration, name=name)
34
- self.order = ORDER
35
- self.definitions = CHARTS
36
- self.fake_name = 'cpu'
37
- self.assignment = {}
38
- self.accurate_exists = True
39
- self.accurate_last = {}
40
-
41
- def _get_data(self):
42
- data = {}
43
-
44
- if self.accurate_exists:
45
- accurate_ok = True
46
-
47
- for name, paths in self.assignment.items():
48
- last = self.accurate_last[name]
49
-
50
- current = {}
51
- deltas = {}
52
- ticks_since_last = 0
53
-
54
- for line in open(paths['accurate'], 'r'):
55
- line = list(map(int, line.split()))
56
- current[line[0]] = line[1]
57
- ticks = line[1] - last.get(line[0], 0)
58
- ticks_since_last += ticks
59
- deltas[line[0]] = line[1] - last.get(line[0], 0)
60
-
61
- avg_freq = 0
62
- if ticks_since_last != 0:
63
- for frequency, ticks in deltas.items():
64
- avg_freq += frequency * ticks
65
- avg_freq /= ticks_since_last
66
-
67
- data[name] = avg_freq
68
- self.accurate_last[name] = current
69
- if avg_freq == 0 or ticks_since_last == 0:
70
- # Delta is either too large or nonexistent, fall back to
71
- # less accurate reading. This can happen if we switch
72
- # to/from the 'schedutil' governor, which doesn't report
73
- # stats.
74
- accurate_ok = False
75
-
76
- if accurate_ok:
77
- return data
78
-
79
- for name, paths in self.assignment.items():
80
- data[name] = open(paths['inaccurate'], 'r').read()
81
-
82
- return data
83
-
84
- def check(self):
85
- try:
86
- self.sys_dir = str(self.configuration['sys_dir'])
87
- except (KeyError, TypeError):
88
- self.error("No path specified. Using: '" + self.sys_dir + "'")
89
-
90
- for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/stats/time_in_state'):
91
- path_elem = path.split('/')
92
- cpu = path_elem[-4]
93
- if cpu not in self.assignment:
94
- self.assignment[cpu] = {}
95
- self.assignment[cpu]['accurate'] = path
96
- self.accurate_last[cpu] = {}
97
-
98
- if not self.assignment:
99
- self.accurate_exists = False
100
-
101
- for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/scaling_cur_freq'):
102
- path_elem = path.split('/')
103
- cpu = path_elem[-3]
104
- if cpu not in self.assignment:
105
- self.assignment[cpu] = {}
106
- self.assignment[cpu]['inaccurate'] = path
107
-
108
- if not self.assignment:
109
- self.error("couldn't find a method to read cpufreq statistics")
110
- return False
111
-
112
- for name in sorted(self.assignment, key=lambda v: int(v[3:])):
113
- self.definitions[ORDER[0]]['lines'].append([name, name, 'absolute', 1, 1000])
114
-
115
- return True
collectors/python.d.plugin/cpufreq/cpufreq.conf
deleted
-41
@@ -1,41 +0,0 @@
1
-# netdata python.d.plugin configuration for cpufreq
2
-#
3
-# This file is in YaML format. Generally the format is:
4
-#
5
-# name: value
6
-#
7
-# There are 2 sections:
8
-# - global variables
9
-# - one or more JOBS
10
-#
11
-# JOBS allow you to collect values from multiple sources.
12
-# Each source will have its own set of charts.
13
-#
14
-# JOB parameters have to be indented (using spaces only, example below).
15
-
16
-# ----------------------------------------------------------------------
17
-# Global Variables
18
-# These variables set the defaults for all JOBs, however each JOB
19
-# may define its own, overriding the defaults.
20
-
21
-# update_every sets the default data collection frequency.
22
-# If unset, the python.d.plugin default is used.
23
-# update_every: 1
24
-
25
-# priority controls the order of charts at the netdata dashboard.
26
-# Lower numbers move the charts towards the top of the page.
27
-# If unset, the default for python.d.plugin is used.
28
-# priority: 60000
29
-
30
-# penalty indicates whether to apply penalty to update_every in case of failures.
31
-# Penalty will increase every 5 failed updates in a row. Maximum penalty is 10 minutes.
32
-# penalty: yes
33
-
34
-# autodetection_retry sets the job re-check interval in seconds.
35
-# The job is not deleted if check fails.
36
-# Attempts to start the job are made once every autodetection_retry.
37
-# This feature is disabled by default.
38
-# autodetection_retry: 0
39
-
40
-# The directory to search for the file scaling_cur_freq
41
-sys_dir: "/sys/devices"
collectors/python.d.plugin/cpuidle/Makefile.inc
deleted
-13
@@ -1,13 +0,0 @@
1
-# SPDX-License-Identifier: GPL-3.0-or-later
2
-
3
-# THIS IS NOT A COMPLETE Makefile
4
-# IT IS INCLUDED BY ITS PARENT'S Makefile.am
5
-# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
6
-
7
-# install these files
8
-dist_python_DATA += cpuidle/cpuidle.chart.py
9
-dist_pythonconfig_DATA += cpuidle/cpuidle.conf
10
-
11
-# do not install these files, but include them in the distribution
12
-dist_noinst_DATA += cpuidle/README.md cpuidle/Makefile.inc
13
-
collectors/python.d.plugin/cpuidle/README.md
deleted
-13
@@ -1,13 +0,0 @@
1
-# cpuidle
2
-
3
-This module monitors the usage of CPU idle states.
4
-
5
-**Requirement:**
6
-Your kernel needs to have `CONFIG_CPU_IDLE` enabled.
7
-
8
-It produces one stacked chart per CPU, showing the percentage of time spent in
9
-each state.
10
-
11
----
12
-
13
-[]()
collectors/python.d.plugin/cpuidle/cpuidle.chart.py
deleted
-148
@@ -1,148 +0,0 @@
1
-# -*- coding: utf-8 -*-
2
-# Description: cpuidle netdata python.d module
3
-# Author: Steven Noonan (tycho)
4
-# SPDX-License-Identifier: GPL-3.0-or-later
5
-
6
-import ctypes
7
-import glob
8
-import os
9
-import platform
10
-
11
-from bases.FrameworkServices.SimpleService import SimpleService
12
-
13
-syscall = ctypes.CDLL('libc.so.6').syscall
14
-
15
-# default module values (can be overridden per job in `config`)
16
-# update_every = 2
17
-
18
-
19
-class Service(SimpleService):
20
- def __init__(self, configuration=None, name=None):
21
- prefix = os.getenv('NETDATA_HOST_PREFIX', "")
22
- if prefix.endswith('/'):
23
- prefix = prefix[:-1]
24
- self.sys_dir = prefix + "/sys/devices/system/cpu"
25
- self.schedstat_path = prefix + "/proc/schedstat"
26
- SimpleService.__init__(self, configuration=configuration, name=name)
27
- self.order = []
28
- self.definitions = {}
29
- self.fake_name = 'cpu'
30
- self.assignment = {}
31
- self.last_schedstat = None
32
-
33
- @staticmethod
34
- def __gettid():
35
- # This is horrendous. We need the *thread id* (not the *process id*),
36
- # but there's no Python standard library way of doing that. If you need
37
- # to enable this module on a non-x86 machine type, you'll have to find
38
- # the Linux syscall number for gettid() and add it to the dictionary
39
- # below.
40
- syscalls = {
41
- 'i386': 224,
42
- 'x86_64': 186,
43
- }
44
- if platform.machine() not in syscalls:
45
- return None
46
- tid = syscall(syscalls[platform.machine()])
47
- return tid
48
-
49
- def __wake_cpus(self, cpus):
50
- # Requires Python 3.3+. This will "tickle" each CPU to force it to
51
- # update its idle counters.
52
- if hasattr(os, 'sched_setaffinity'):
53
- pid = self.__gettid()
54
- save_affinity = os.sched_getaffinity(pid)
55
- for idx in cpus:
56
- os.sched_setaffinity(pid, [idx])
57
- os.sched_getaffinity(pid)
58
- os.sched_setaffinity(pid, save_affinity)
59
-
60
- def __read_schedstat(self):
61
- cpus = {}
62
- for line in open(self.schedstat_path, 'r'):
63
- if not line.startswith('cpu'):
64
- continue
65
- line = line.rstrip().split()
66
- cpu = line[0]
67
- active_time = line[7]
68
- cpus[cpu] = int(active_time) // 1000
69
- return cpus
70
-
71
- def _get_data(self):
72
- results = {}
73
-
74
- # Use the kernel scheduler stats to determine how much time was spent
75
- # in C0 (active).
76
- schedstat = self.__read_schedstat()
77
-
78
- # Determine if any of the CPUs are idle. If they are, then we need to
79
- # tickle them in order to update their C-state residency statistics.
80
- if self.last_schedstat is None:
81
- needs_tickle = list(self.assignment.keys())
82
- else:
83
- needs_tickle = []
84
- for cpu, active_time in self.last_schedstat.items():
85
- delta = schedstat[cpu] - active_time
86
- if delta < 1:
87
- needs_tickle.append(cpu)
88
-
89
- if needs_tickle:
90
- # This line is critical for the stats to update. If we don't "tickle"
91
- # idle CPUs, then the counters for those CPUs stop counting.
92
- self.__wake_cpus([int(cpu[3:]) for cpu in needs_tickle])
93
-
94
- # Re-read schedstat now that we've tickled any idlers.
95
- schedstat = self.__read_schedstat()
96
-
97
- self.last_schedstat = schedstat
98
-
99
- for cpu, metrics in self.assignment.items():
100
- update_time = schedstat[cpu]
101
- results[cpu + '_active_time'] = update_time
102
-
103
- for metric, path in metrics.items():
104
- residency = int(open(path, 'r').read())
105
- results[metric] = residency
106
-
107
- return results
108
-
109
- def check(self):
110
- if self.__gettid() is None:
111
- self.error('Cannot get thread ID. Stats would be completely broken.')
112
- return False
113
-
114
- for path in sorted(glob.glob(self.sys_dir + '/cpu*/cpuidle/state*/name')):
115
- # ['', 'sys', 'devices', 'system', 'cpu', 'cpu0', 'cpuidle', 'state3', 'name']
116
- path_elem = path.split('/')
117
- cpu = path_elem[-4]
118
- state = path_elem[-2]
119
- statename = open(path, 'rt').read().rstrip()
120
-
121
- orderid = '%s_cpuidle' % (cpu,)
122
- if orderid not in self.definitions:
123
- self.order.append(orderid)
124
- active_name = '%s_active_time' % (cpu,)
125
- self.definitions[orderid] = {
126
- 'options': [None, 'C-state residency', 'time%', 'cpuidle', 'cpuidle.cpuidle', 'stacked'],
127
- 'lines': [
128
- [active_name, 'C0 (active)', 'percentage-of-incremental-row', 1, 1],
129
- ],
130
- }
131
- self.assignment[cpu] = {}
132
-
133
- defid = '%s_%s_time' % (orderid, state)
134
-
135
- self.definitions[orderid]['lines'].append(
136
- [defid, statename, 'percentage-of-incremental-row', 1, 1]
137
- )
138
-
139
- self.assignment[cpu][defid] = '/'.join(path_elem[:-1] + ['time'])
140
-
141
- # Sort order by kernel-specified CPU index
142
- self.order.sort(key=lambda x: int(x.split('_')[0][3:]))
143
-
144
- if not self.definitions:
145
- self.error("couldn't find cstate stats")
146
- return False
147
-
148
- return True
collectors/python.d.plugin/cpuidle/cpuidle.conf
deleted
-38
@@ -1,38 +0,0 @@
1
-# netdata python.d.plugin configuration for cpuidle
2
-#
3
-# This file is in YaML format. Generally the format is:
4
-#
5
-# name: value
6
-#
7
-# There are 2 sections:
8
-# - global variables
9
-# - one or more JOBS
10
-#
11
-# JOBS allow you to collect values from multiple sources.
12
-# Each source will have its own set of charts.
13
-#
14
-# JOB parameters have to be indented (using spaces only, example below).
15
-
16
-# ----------------------------------------------------------------------
17
-# Global Variables
18
-# These variables set the defaults for all JOBs, however each JOB
19
-# may define its own, overriding the defaults.
20
-
21
-# update_every sets the default data collection frequency.
22
-# If unset, the python.d.plugin default is used.
23
-# update_every: 1
24
-
25
-# priority controls the order of charts at the netdata dashboard.
26
-# Lower numbers move the charts towards the top of the page.
27
-# If unset, the default for python.d.plugin is used.
28
-# priority: 60000
29
-
30
-# penalty indicates whether to apply penalty to update_every in case of failures.
31
-# Penalty will increase every 5 failed updates in a row. Maximum penalty is 10 minutes.
32
-# penalty: yes
33
-
34
-# autodetection_retry sets the job re-check interval in seconds.
35
-# The job is not deleted if check fails.
36
-# Attempts to start the job are made once every autodetection_retry.
37
-# This feature is disabled by default.
38
-# autodetection_retry: 0
collectors/python.d.plugin/linux_power_supply/Makefile.inc
deleted
-13
@@ -1,13 +0,0 @@
1
-# SPDX-License-Identifier: GPL-3.0-or-later
2
-
3
-# THIS IS NOT A COMPLETE Makefile
4
-# IT IS INCLUDED BY ITS PARENT'S Makefile.am
5
-# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
6
-
7
-# install these files
8
-dist_python_DATA += linux_power_supply/linux_power_supply.chart.py
9
-dist_pythonconfig_DATA += linux_power_supply/linux_power_supply.conf
10
-
11
-# do not install these files, but include them in the distribution
12
-dist_noinst_DATA += linux_power_supply/README.md linux_power_supply/Makefile.inc
13
-
collectors/python.d.plugin/linux_power_supply/README.md
deleted
-74
@@ -1,74 +0,0 @@
1
-# Linux power supply
2
-
3
-> THIS MODULE IS OBSOLETE.
4
-> USE THE [PROC PLUGIN](../../proc.plugin) - IT IS MORE EFFICIENT
5
-
6
----
7
-
8
-This module monitors variosu metrics reported by power supply drivers
9
-on Linux. This allows tracking and alerting on things like remaining
10
-battery capacity.
11
-
12
-Depending on the uderlying driver, it may provide the following charts
13
-and metrics:
14
-
15
-1. Capacity: The power supply capacity expressed as a percentage.
16
- * capacity\_now
17
-
18
-2. Charge: The charge for the power supply, expressed as microamphours.
19
- * charge\_full\_design
20
- * charge\_full
21
- * charge\_now
22
- * charge\_empty
23
- * charge\_empty\_design
24
-
25
-3. Energy: The energy for the power supply, expressed as microwatthours.
26
- * energy\_full\_design
27
- * energy\_full
28
- * energy\_now
29
- * energy\_empty
30
- * energy\_empty\_design
31
-
32
-2. Voltage: The voltage for the power supply, expressed as microvolts.
33
- * voltage\_max\_design
34
- * voltage\_max
35
- * voltage\_now
36
- * voltage\_min
37
- * voltage\_min\_design
38
-
39
-### configuration
40
-
41
-Sample:
42
-
43
-```yaml
44
-battery:
45
- supply: 'BAT0'
46
- charts: 'capacity charge energy voltage'
47
-```
48
-
49
-The `supply` key specifies the name of the power supply device to monitor.
50
-You can use `ls /sys/class/power_supply` to get a list of such devices
51
-on your system.
52
-
53
-The `charts` key is a space separated list of which charts to try
54
-to display. It defaults to trying to display everything.
55
-
56
-### notes
57
-
58
-* Most drivers provide at least the first chart. Battery powered ACPI
59
-compliant systems (like most laptops) provide all but the third, but do
60
-not provide all of the metrics for each chart.
61
-
62
-* Current, energy, and voltages are reported with a _very_ high precision
63
-by the power\_supply framework. Usually, this is far higher than the
64
-actual hardware supports reporting, so expect to see changes in these
65
-charts jump instead of scaling smoothly.
66
-
67
-* If `max` or `full` attribute is defined by the driver, but not a
68
-corresponding `min or `empty` attribute, then netdata will still provide
69
-the corresponding `min` or `empty`, which will then always read as zero.
70
-This way, alerts which match on these will still work.
71
-
72
----
73
-
74
-[]()
collectors/python.d.plugin/linux_power_supply/linux_power_supply.chart.py
deleted
-160
@@ -1,160 +0,0 @@
1
-# -*- coding: utf-8 -*-
2
-# Description: Linux power_supply netdata python.d module
3
-# Author: Austin S. Hemmelgarn (Ferroin)
4
-
5
-import os
6
-import platform
7
-
8
-from bases.FrameworkServices.SimpleService import SimpleService
9
-
10
-# Everything except percentages is reported as µ units.
11
-PRECISION = 10 ** 6
12
-
13
-# A priority of 90000 places us next to the other PSU related stuff.
14
-PRIORITY = 90000
15
-
16
-# We add our charts dynamically when we probe for the device attributes,
17
-# so these are empty by default.
18
-ORDER = []
19
-
20
-CHARTS = {}
21
-
22
-
23
-def get_capacity_chart(syspath):
24
- # Capacity is measured in percent. We track one value.
25
- options = [None, 'Capacity', '%', 'power_supply', 'power_supply.capacity', 'line']
26
- lines = list()
27
- attr_now = 'capacity'
28
- if get_sysfs_value(os.path.join(syspath, attr_now)) is not None:
29
- lines.append([attr_now, attr_now, 'absolute', 1, 1])
30
- return {'capacity': {'options': options, 'lines': lines}}, [attr_now]
31
- else:
32
- return None, None
33
-
34
-
35
-def get_generic_chart(syspath, name, unit, maxname, minname):
36
- # Used to generate charts for energy, charge, and voltage.
37
- options = [None, name.title(), unit, 'power_supply', 'power_supply.{0}'.format(name), 'line']
38
- lines = list()
39
- attrlist = list()
40
- attr_max_design = '{0}_{1}_design'.format(name, maxname)
41
- attr_max = '{0}_{1}'.format(name, maxname)
42
- attr_now = '{0}_now'.format(name)
43
- attr_min = '{0}_{1}'.format(name, minname)
44
- attr_min_design = '{0}_{1}_design'.format(name, minname)
45
- if get_sysfs_value(os.path.join(syspath, attr_now)) is not None:
46
- lines.append([attr_now, attr_now, 'absolute', 1, PRECISION])
47
- attrlist.append(attr_now)
48
- else:
49
- return None, None
50
- if get_sysfs_value(os.path.join(syspath, attr_max)) is not None:
51
- lines.insert(0, [attr_max, attr_max, 'absolute', 1, PRECISION])
52
- lines.append([attr_min, attr_min, 'absolute', 1, PRECISION])
53
- attrlist.append(attr_max)
54
- attrlist.append(attr_min)
55
- elif get_sysfs_value(os.path.join(syspath, attr_min)) is not None:
56
- lines.append([attr_min, attr_min, 'absolute', 1, PRECISION])
57
- attrlist.append(attr_min)
58
- if get_sysfs_value(os.path.join(syspath, attr_max_design)) is not None:
59
- lines.insert(0, [attr_max_design, attr_max_design, 'absolute', 1, PRECISION])
60
- lines.append([attr_min_design, attr_min_design, 'absolute', 1, PRECISION])
61
- attrlist.append(attr_max_design)
62
- attrlist.append(attr_min_design)
63
- elif get_sysfs_value(os.path.join(syspath, attr_min_design)) is not None:
64
- lines.append([attr_min_design, attr_min_design, 'absolute', 1, PRECISION])
65
- attrlist.append(attr_min_design)
66
- return {name: {'options': options, 'lines': lines}}, attrlist
67
-
68
-
69
-def get_charge_chart(syspath):
70
- # Charge is measured in microamphours. We track up to five
71
- # attributes.
72
- return get_generic_chart(syspath, 'charge', 'µAh', 'full', 'empty')
73
-
74
-
75
-def get_energy_chart(syspath):
76
- # Energy is measured in microwatthours. We track up to five
77
- # attributes.
78
- return get_generic_chart(syspath, 'energy', 'µWh', 'full', 'empty')
79
-
80
-
81
-def get_voltage_chart(syspath):
82
- # Voltage is measured in microvolts. We track up to five attributes.
83
- return get_generic_chart(syspath, 'voltage', 'µV', 'min', 'max')
84
-
85
-
86
-# This is a list of functions for generating charts. Used below to save
87
-# a bit of code (and to make it a bit easier to add new charts).
88
-GET_CHART = {
89
- 'capacity': get_capacity_chart,
90
- 'charge': get_charge_chart,
91
- 'energy': get_energy_chart,
92
- 'voltage': get_voltage_chart
93
-}
94
-
95
-
96
-# This opens the specified file and returns the value in it or None if
97
-# the file doesn't exist.
98
-def get_sysfs_value(filepath):
99
- try:
100
- with open(filepath, 'r') as datasource:
101
- return int(datasource.read())
102
- except (OSError, IOError):
103
- return None
104
-
105
-
106
-class Service(SimpleService):
107
- def __init__(self, configuration=None, name=None):
108
- SimpleService.__init__(self, configuration=configuration, name=name)
109
- self.definitions = dict()
110
- self.order = list()
111
- self.attrlist = list()
112
- self.supply = self.configuration.get('supply', None)
113
- if self.supply is not None:
114
- self.syspath = '/sys/class/power_supply/{0}'.format(self.supply)
115
- self.types = self.configuration.get('charts', 'capacity').split()
116
-
117
- def check(self):
118
- if platform.system() != 'Linux':
119
- self.error('Only supported on Linux.')
120
- return False
121
- if self.supply is None:
122
- self.error('No power supply specified for monitoring.')
123
- return False
124
- if not self.types:
125
- self.error('No attributes requested for monitoring.')
126
- return False
127
- if not os.access(self.syspath, os.R_OK):
128
- self.error('Unable to access {0}'.format(self.syspath))
129
- return False
130
- return self.create_charts()
131
-
132
- def create_charts(self):
133
- chartset = set(GET_CHART).intersection(set(self.types))
134
- if not chartset:
135
- self.error('No valid attributes requested for monitoring.')
136
- return False
137
- charts = dict()
138
- attrlist = list()
139
- for item in chartset:
140
- chart, attrs = GET_CHART[item](self.syspath)
141
- if chart is not None:
142
- charts.update(chart)
143
- attrlist.extend(attrs)
144
- if len(charts) == 0:
145
- self.error('No charts can be created.')
146
- return False
147
- self.definitions.update(charts)
148
- self.order.extend(sorted(charts))
149
- self.attrlist.extend(attrlist)
150
- return True
151
-
152
- def _get_data(self):
153
- data = dict()
154
- for attr in self.attrlist:
155
- attrpath = os.path.join(self.syspath, attr)
156
- if attr.endswith(('_min', '_min_design', '_empty', '_empty_design')):
157
- data[attr] = get_sysfs_value(attrpath) or 0
158
- else:
159
- data[attr] = get_sysfs_value(attrpath)
160
- return data
collectors/python.d.plugin/linux_power_supply/linux_power_supply.conf
deleted
-79
@@ -1,79 +0,0 @@
1
-# netdata python.d.plugin configuration for linux_power_supply
2
-#
3
-# This file is in YaML format. Generally the format is:
4
-#
5
-# name: value
6
-#
7
-# There are 2 sections:
8
-# - global variables
9
-# - one or more JOBS
10
-#
11
-# JOBS allow you to collect values from multiple sources.
12
-# Each source will have its own set of charts.
13
-#
14
-# JOB parameters have to be indented (using spaces only, example below).
15
-
16
-# ----------------------------------------------------------------------
17
-# Global Variables
18
-# These variables set the defaults for all JOBs, however each JOB
19
-# may define its own, overriding the defaults.
20
-
21
-# update_every sets the default data collection frequency.
22
-# If unset, the python.d.plugin default is used.
23
-# update_every: 1
24
-
25
-# priority controls the order of charts at the netdata dashboard.
26
-# Lower numbers move the charts towards the top of the page.
27
-# If unset, the default for python.d.plugin is used.
28
-# priority: 60000
29
-
30
-# penalty indicates whether to apply penalty to update_every in case of failures.
31
-# Penalty will increase every 5 failed updates in a row. Maximum penalty is 10 minutes.
32
-# penalty: yes
33
-
34
-# autodetection_retry sets the job re-check interval in seconds.
35
-# The job is not deleted if check fails.
36
-# Attempts to start the job are made once every autodetection_retry.
37
-# This feature is disabled by default.
38
-# autodetection_retry: 0
39
-
40
-# ----------------------------------------------------------------------
41
-# JOBS (data collection sources)
42
-#
43
-# The default JOBS share the same *name*. JOBS with the same name
44
-# are mutually exclusive. Only one of them will be allowed running at
45
-# any time. This allows autodetection to try several alternatives and
46
-# pick the one that works.
47
-#
48
-# Any number of jobs is supported.
49
-#
50
-# All python.d.plugin JOBS (for all its modules) support a set of
51
-# predefined parameters. These are:
52
-#
53
-# job_name:
54
-# name: myname # the JOB's name as it will appear at the
55
-# # dashboard (by default is the job_name)
56
-# # JOBs sharing a name are mutually exclusive
57
-# update_every: 1 # the JOB's data collection frequency
58
-# priority: 60000 # the JOB's order on the dashboard
59
-# penalty: yes # the JOB's penalty
60
-# autodetection_retry: 0 # the JOB's re-check interval in seconds
61
-#
62
-# In addition to the above parameters, linux_power_supply also supports
63
-# the following extra parameters.
64
-#
65
-# supply: '' # the name of the power supply to monitor
66
-# charts: 'capacity' # a space separated list of the charts to try
67
-# # and generate valid charts are 'capacity',
68
-# # 'charge', 'current', and 'voltage'
69
-#
70
-# Note that linux_power_supply will not automatically detect power
71
-# supplies in the system, you have to manually specify which ones you
72
-# want it to monitor.
73
-#
74
-# The following config will work to monitor the first battery in most
75
-# ACPI compliant battery powered systems (such as most laptops).
76
-#
77
-# battery:
78
-# name: battery
79
-# supply: BAT0
collectors/python.d.plugin/mdstat/Makefile.inc
deleted
-13
@@ -1,13 +0,0 @@
1
-# SPDX-License-Identifier: GPL-3.0-or-later
2
-
3
-# THIS IS NOT A COMPLETE Makefile
4
-# IT IS INCLUDED BY ITS PARENT'S Makefile.am
5
-# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
6
-
7
-# install these files
8
-dist_python_DATA += mdstat/mdstat.chart.py
9
-dist_pythonconfig_DATA += mdstat/mdstat.conf
10
-
11
-# do not install these files, but include them in the distribution
12
-dist_noinst_DATA += mdstat/README.md mdstat/Makefile.inc
13
-
collectors/python.d.plugin/mdstat/README.md
deleted
-33
@@ -1,33 +0,0 @@
1
-# mdstat
2
-
3
-> THIS MODULE IS OBSOLETE.
4
-> USE THE [PROC PLUGIN](../../proc.plugin) - IT IS MORE EFFICIENT
5
-
6
----
7
-
8
-Module monitor /proc/mdstat
9
-
10
-It produces:
11
-
12
-1. **Health** Number of failed disks in every array (aggregate chart).
13
-
14
-2. **Disks stats**
15
- * total (number of devices array ideally would have)
16
- * inuse (number of devices currently are in use)
17
-
18
-3. **Current status**
19
- * resync in percent
20
- * recovery in percent
21
- * reshape in percent
22
- * check in percent
23
-
24
-4. **Operation status** (if resync/recovery/reshape/check is active)
25
- * finish in minutes
26
- * speed in megabytes/s
27
-
28
-### configuration
29
-No configuration is needed.
30
-
31
----
32
-
33
-[]()
collectors/python.d.plugin/mdstat/mdstat.chart.py
deleted
-205
@@ -1,205 +0,0 @@
1
-# -*- coding: utf-8 -*-
2
-# Description: mdstat netdata python.d module
3
-# Author: Ilya Mashchenko (l2isbad)
4
-# SPDX-License-Identifier: GPL-3.0-or-later
5
-
6
-import re
7
-
8
-from collections import defaultdict
9
-
10
-from bases.FrameworkServices.SimpleService import SimpleService
11
-
12
-MDSTAT = '/proc/mdstat'
13
-MISMATCH_CNT = '/sys/block/{0}/md/mismatch_cnt'
14
-
15
-ORDER = ['mdstat_health']
16
-
17
-CHARTS = {
18
- 'mdstat_health': {
19
- 'options': [None, 'Faulty Devices In MD', 'failed disks', 'health', 'md.health', 'line'],
20
- 'lines': []
21
- }
22
-}
23
-
24
-RE_DISKS = re.compile(r' (?P<array>[a-zA-Z_0-9]+) : active .+\['
25
- r'(?P<total_disks>[0-9]+)/'
26
- r'(?P<inuse_disks>[0-9]+)\]')
27
-
28
-RE_STATUS = re.compile(r' (?P<array>[a-zA-Z_0-9]+) : active .+ '
29
- r'(?P<operation>[a-z]+) =[ ]{1,2}'
30
- r'(?P<operation_status>[0-9.]+).+finish='
31
- r'(?P<finish_in>([0-9.]+))min speed='
32
- r'(?P<speed>[0-9]+)')
33
-
34
-
35
-def md_charts(name):
36
- order = [
37
- '{0}_disks'.format(name),
38
- '{0}_operation'.format(name),
39
- '{0}_mismatch_cnt'.format(name),
40
- '{0}_finish'.format(name),
41
- '{0}_speed'.format(name)
42
- ]
43
-
44
- charts = dict()
45
- charts[order[0]] = {
46
- 'options': [None, 'Disks Stats', 'disks', name, 'md.disks', 'stacked'],
47
- 'lines': [
48
- ['{0}_total_disks'.format(name), 'total', 'absolute'],
49
- ['{0}_inuse_disks'.format(name), 'inuse', 'absolute']
50
- ]
51
- }
52
-
53
- charts[order[1]] = {
54
- 'options': [None, 'Current Status', 'percent', name, 'md.status', 'line'],
55
- 'lines': [
56
- ['{0}_resync'.format(name), 'resync', 'absolute', 1, 100],
57
- ['{0}_recovery'.format(name), 'recovery', 'absolute', 1, 100],
58
- ['{0}_reshape'.format(name), 'reshape', 'absolute', 1, 100],
59
- ['{0}_check'.format(name), 'check', 'absolute', 1, 100],
60
- ]
61
- }
62
-
63
- charts[order[2]] = {
64
- 'options': [None, 'Mismatch Count', 'unsynchronized blocks', name, 'md.mismatch_cnt', 'line'],
65
- 'lines': [
66
- ['{0}_mismatch_cnt'.format(name), 'count', 'absolute']
67
- ]
68
- }
69
-
70
- charts[order[3]] = {
71
- 'options': [None, 'Approximate Time Until Finish', 'seconds', name, 'md.rate', 'line'],
72
- 'lines': [
73
- ['{0}_finish_in'.format(name), 'finish in', 'absolute', 1, 1000]
74
- ]
75
- }
76
-
77
- charts[order[4]] = {
78
- 'options': [None, 'Operation Speed', 'KB/s', name, 'md.rate', 'line'],
79
- 'lines': [
80
- ['{0}_speed'.format(name), 'speed', 'absolute', 1, 1000]
81
- ]
82
- }
83
-
84
- return order, charts
85
-
86
-
87
-class MD:
88
- def __init__(self, raw_data):
89
- self.name = raw_data['array']
90
- self.d = raw_data
91
-
92
- def data(self):
93
- rv = {
94
- 'total_disks': self.d['total_disks'],
95
- 'inuse_disks': self.d['inuse_disks'],
96
- 'health': int(self.d['total_disks']) - int(self.d['inuse_disks']),
97
- 'resync': 0,
98
- 'recovery': 0,
99
- 'reshape': 0,
100
- 'check': 0,
101
- 'finish_in': 0,
102
- 'speed': 0,
103
- }
104
-
105
- v = read_lines(MISMATCH_CNT.format(self.name))
106
- if v:
107
- rv['mismatch_cnt'] = v
108
-
109
- if self.d.get('operation'):
110
- rv[self.d['operation']] = float(self.d['operation_status']) * 100
111
- rv['finish_in'] = float(self.d['finish_in']) * 1000 * 60
112
- rv['speed'] = float(self.d['speed']) * 1000
113
-
114
- return dict(('{0}_{1}'.format(self.name, k), v) for k, v in rv.items())
115
-
116
-
117
-class Service(SimpleService):
118
- def __init__(self, configuration=None, name=None):
119
- SimpleService.__init__(self, configuration=configuration, name=name)
120
- self.order = ORDER
121
- self.definitions = CHARTS
122
- self.mds = list()
123
-
124
- @staticmethod
125
- def get_mds():
126
- raw = read_lines(MDSTAT)
127
-
128
- if not raw:
129
- return None
130
-
131
- return find_mds(raw)
132
-
133
- def get_data(self):
134
- """
135
- Parse data from _get_raw_data()
136
- :return: dict
137
- """
138
- mds = self.get_mds()
139
-
140
- if not mds:
141
- return None
142
-
143
- data = dict()
144
- for md in mds:
145
- if md.name not in self.mds:
146
- self.mds.append(md.name)
147
- self.add_new_md_charts(md.name)
148
- data.update(md.data())
149
- return data
150
-
151
- def check(self):
152
- if not self.get_mds():
153
- self.error('Failed to read data from {0} or there is no active arrays'.format(MDSTAT))
154
- return False
155
- return True
156
-
157
- def add_new_md_charts(self, name):
158
- order, charts = md_charts(name)
159
-
160
- self.charts['mdstat_health'].add_dimension(['{0}_health'.format(name), name])
161
-
162
- for chart_name in order:
163
- params = [chart_name] + charts[chart_name]['options']
164
- dims = charts[chart_name]['lines']
165
-
166
- chart = self.charts.add_chart(params)
167
- for dim in dims:
168
- chart.add_dimension(dim)
169
-
170
-
171
-def find_mds(raw_data):
172
- data = defaultdict(str)
173
- counter = 1
174
-
175
- for row in (elem.strip() for elem in raw_data):
176
- if not row:
177
- counter += 1
178
- continue
179
- data[counter] = ' '.join([data[counter], row])
180
-
181
- mds = list()
182
-
183
- for v in data.values():
184
- m = RE_DISKS.search(v)
185
-
186
- if not m:
187
- continue
188
-
189
- d = m.groupdict()
190
-
191
- m = RE_STATUS.search(v)
192
- if m:
193
- d.update(m.groupdict())
194
-
195
- mds.append(MD(d))
196
-
197
- return sorted(mds, key=lambda md: md.name)
198
-
199
-
200
-def read_lines(path):
201
- try:
202
- with open(path) as f:
203
- return f.readlines()
204
- except (IOError, OSError):
205
- return None
collectors/python.d.plugin/mdstat/mdstat.conf
deleted
-30
@@ -1,30 +0,0 @@
1
-# netdata python.d.plugin configuration for mdstat
2
-#
3
-# This file is in YaML format. Generally the format is:
4
-#
5
-# name: value
6
-#
7
-
8
-# ----------------------------------------------------------------------
9
-# Global Variables
10
-# These variables set the defaults for all JOBs, however each JOB
11
-# may define its own, overriding the defaults.
12
-
13
-# update_every sets the default data collection frequency.
14
-# If unset, the python.d.plugin default is used.
15
-# update_every: 1
16
-
17
-# priority controls the order of charts at the netdata dashboard.
18
-# Lower numbers move the charts towards the top of the page.
19
-# If unset, the default for python.d.plugin is used.
20
-# priority: 60000
21
-
22
-# penalty indicates whether to apply penalty to update_every in case of failures.
23
-# Penalty will increase every 5 failed updates in a row. Maximum penalty is 10 minutes.
24
-# penalty: yes
25
-
26
-# autodetection_retry sets the job re-check interval in seconds.
27
-# The job is not deleted if check fails.
28
-# Attempts to start the job are made once every autodetection_retry.
29
-# This feature is disabled by default.
30
-# autodetection_retry: 0
collectors/python.d.plugin/python.d.conf
-4
@@ -36,8 +36,6 @@ apache_cache: no
36
# ceph: yes
37
chrony: no
38
# couchdb: yes
39
-# cpufreq: yes
40
-# cpuidle: yes
39
# dns_query_time: yes
40
# dnsdist: yes
41
# dockerd: yes
@@ -60,10 +58,8 @@ gunicorn_log: no
58
# icecast: yes
59
# ipfs: yes
60
# isc_dhcpd: yes
63
-# linux_power_supply: yes
61
# litespeed: yes
62
logind: no
66
-# mdstat: yes
63
# megacli: yes
64
# memcached: yes
65
# mongodb: yes
docs/Add-more-charts-to-netdata.md
+1
-3
@@ -16,7 +16,7 @@ To collect non-system metrics, netdata supports a plugin architecture. The follo
16
- **[Name Servers](#name-servers)** (DNS), like bind, nsd, powerdns, dnsdist
17
- **[DHCP Servers](#dhcp-servers)**, like ISC DHCP
18
- **[UPS](#ups)**, such as APC UPS, NUT
19
-- **[RAID](#raid)**, such as linux software raid (mdadm), MegaRAID
19
+- **[RAID](#raid)**, such as MegaRAID
20
- **[Mail Servers](#mail-servers)**, like postfix, exim, dovecot
21
- **[File Servers](#file-servers)**, like samba, NFS, ftp, sftp, WebDAV
22
- **[Print Servers](#print-servers)**, like CUPS
@@ -268,7 +268,6 @@ nut|BASH<br/>Shell Script|Connects to a nut server (upsd) to collect real-time U
268
269
application|language|notes|
270
:---------:|:------:|:----|
271
-mdstat|python<br/>v2 or v3|Parses `/proc/mdstat` to get mds health metrics.<br/> <br/>netdata plugin: [python.d.plugin](../collectors/python.d.plugin)<br/>plugin module: [mdstat.chart.py](../collectors/python.d.plugin/mdstat)<br/>configuration file: [python.d/mdstat.conf](../collectors/python.d.plugin/mdstat)|
271
megacli|python<br/>v2 or v3|Collects adapter, physical drives and battery stats..<br/> <br/>netdata plugin: [python.d.plugin](../collectors/python.d.plugin)<br/>plugin module: [megacli.chart.py](../collectors/python.d.plugin/megacli)<br/>configuration file: [python.d/megacli.conf](../collectors/python.d.plugin/megacli)|
272
273
---
@@ -318,7 +317,6 @@ mem_apps|BASH<br/>Shell Script|Collects the memory footprint of select applicati
317
318
application|language|notes|
319
:---------:|:------:|:----|
321
-cpufreq|python<br/>v2 or v3|Collects the current CPU frequency from `/sys/devices`.<br/> <br/>netdata plugin: [python.d.plugin](../collectors/python.d.plugin)<br/>plugin module: [cpufreq.chart.py](../collectors/python.d.plugin/cpufreq)<br/>configuration file: [python.d/cpufreq.conf](../collectors/python.d.plugin/cpufreq)|
320
cpufreq|BASH<br/>Shell Script|Collects current CPU frequency from `/sys/devices`.<br/><br/>DEPRECATED IN FAVOR OF THE PYTHON ONE. It is still supplied only as an example module to shell scripting plugins.<br/> <br/>netdata plugin: [charts.d.plugin](../collectors/charts.d.plugin#chartsdplugin)<br/>plugin module: [cpufreq.chart.sh](../collectors/charts.d.plugin/cpufreq)<br/>configuration file: [charts.d/cpufreq.conf](../collectors/charts.d.plugin/cpufreq)|
321
IPMI|C|Collects temperatures, voltages, currents, power, fans and `SEL` events from IPMI using `libipmimonitoring`.<br/>Check [Monitoring IPMI](../collectors/freeipmi.plugin/) for more information<br/> <br/>netdata plugin: [freeipmi.plugin](../collectors/freeipmi.plugin)<br/>configuration file: none required - to enable it, compile/install netdata with `--enable-plugin-freeipmi`|
322
hddtemp|python<br/>v2 or v3|Connects to multiple hddtemp servers (local or remote) to collect real-time performance metrics.<br/> <br/>netdata plugin: [python.d.plugin](../collectors/python.d.plugin)<br/>plugin module: [hddtemp.chart.py](../collectors/python.d.plugin/hddtemp)<br/>configuration file: [python.d/hddtemp.conf](../collectors/python.d.plugin/hddtemp)|