@cryptotaxi247 / netdata-1 / commits / 1b549b1dd

remove python.d/smartd_log (#17600)

Ilya Mashchenko committed May 6, 2024 at 18:04 UTC 1b549b1dd79c951ee8f23e6d13f525061adc8df2
6 files changed -1521
CMakeLists.txt
-2
@@ -2750,7 +2750,6 @@ install(FILES
2750 src/collectors/python.d.plugin/retroshare/retroshare.conf
2751 src/collectors/python.d.plugin/riakkv/riakkv.conf
2752 src/collectors/python.d.plugin/samba/samba.conf
2753 - src/collectors/python.d.plugin/smartd_log/smartd_log.conf
2753 src/collectors/python.d.plugin/spigotmc/spigotmc.conf
2754 src/collectors/python.d.plugin/squid/squid.conf
2755 src/collectors/python.d.plugin/tomcat/tomcat.conf
@@ -2795,7 +2794,6 @@ install(FILES
2794 src/collectors/python.d.plugin/retroshare/retroshare.chart.py
2795 src/collectors/python.d.plugin/riakkv/riakkv.chart.py
2796 src/collectors/python.d.plugin/samba/samba.chart.py
2798 - src/collectors/python.d.plugin/smartd_log/smartd_log.chart.py
2797 src/collectors/python.d.plugin/spigotmc/spigotmc.chart.py
2798 src/collectors/python.d.plugin/squid/squid.chart.py
2799 src/collectors/python.d.plugin/tomcat/tomcat.chart.py
src/collectors/python.d.plugin/smartd_log/README.md deleted
-1
@@ -1 +0,0 @@
1 -integrations/s.m.a.r.t..md
\ No newline at end of file
src/collectors/python.d.plugin/smartd_log/integrations/s.m.a.r.t..md deleted
-223
@@ -1,223 +0,0 @@
1 -<!--startmeta
2 -custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/collectors/python.d.plugin/smartd_log/README.md"
3 -meta_yaml: "https://github.com/netdata/netdata/edit/master/src/collectors/python.d.plugin/smartd_log/metadata.yaml"
4 -sidebar_label: "S.M.A.R.T."
5 -learn_status: "Published"
6 -learn_rel_path: "Collecting Metrics/Hardware Devices and Sensors"
7 -most_popular: False
8 -message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE"
9 -endmeta-->
10 -
11 -# S.M.A.R.T.
12 -
13 -
14 -<img src="https://netdata.cloud/img/smart.png" width="150"/>
15 -
16 -
17 -Plugin: python.d.plugin
18 -Module: smartd_log
19 -
20 -<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />
21 -
22 -## Overview
23 -
24 -This collector monitors HDD/SSD S.M.A.R.T. metrics about drive health and performance.
25 -
26 -
27 -It reads `smartd` log files to collect the metrics.
28 -
29 -
30 -This collector is supported on all platforms.
31 -
32 -This collector only supports collecting metrics from a single instance of this integration.
33 -
34 -
35 -### Default Behavior
36 -
37 -#### Auto-Detection
38 -
39 -Upon satisfying the prerequisites, the collector will auto-detect metrics if written in either `/var/log/smartd/` or `/var/lib/smartmontools/`.
40 -
41 -#### Limits
42 -
43 -The default configuration for this integration does not impose any limits on data collection.
44 -
45 -#### Performance Impact
46 -
47 -The default configuration for this integration is not expected to impose a significant performance impact on the system.
48 -
49 -
50 -## Metrics
51 -
52 -Metrics grouped by *scope*.
53 -
54 -The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels.
55 -
56 -The metrics listed below are split in terms of availability on device type, SCSI or ATA.
57 -
58 -### Per S.M.A.R.T. instance
59 -
60 -These metrics refer to the entire monitored application.
61 -
62 -This scope has no labels.
63 -
64 -Metrics:
65 -
66 -| Metric | Dimensions | Unit | SCSI | ATA |
67 -|:------|:----------|:----|:---:|:---:|
68 -| smartd_log.read_error_rate | a dimension per device | value | | • |
69 -| smartd_log.seek_error_rate | a dimension per device | value | | • |
70 -| smartd_log.soft_read_error_rate | a dimension per device | errors | | • |
71 -| smartd_log.write_error_rate | a dimension per device | value | | • |
72 -| smartd_log.read_total_err_corrected | a dimension per device | errors | • | |
73 -| smartd_log.read_total_unc_errors | a dimension per device | errors | • | |
74 -| smartd_log.write_total_err_corrected | a dimension per device | errors | • | |
75 -| smartd_log.write_total_unc_errors | a dimension per device | errors | • | |
76 -| smartd_log.verify_total_err_corrected | a dimension per device | errors | • | |
77 -| smartd_log.verify_total_unc_errors | a dimension per device | errors | • | |
78 -| smartd_log.sata_interface_downshift | a dimension per device | events | | • |
79 -| smartd_log.udma_crc_error_count | a dimension per device | errors | | • |
80 -| smartd_log.throughput_performance | a dimension per device | value | | • |
81 -| smartd_log.seek_time_performance | a dimension per device | value | | • |
82 -| smartd_log.start_stop_count | a dimension per device | events | | • |
83 -| smartd_log.power_on_hours_count | a dimension per device | hours | | • |
84 -| smartd_log.power_cycle_count | a dimension per device | events | | • |
85 -| smartd_log.unexpected_power_loss | a dimension per device | events | | • |
86 -| smartd_log.spin_up_time | a dimension per device | ms | | • |
87 -| smartd_log.spin_up_retries | a dimension per device | retries | | • |
88 -| smartd_log.calibration_retries | a dimension per device | retries | | • |
89 -| smartd_log.airflow_temperature_celsius | a dimension per device | celsius | | • |
90 -| smartd_log.temperature_celsius | a dimension per device | celsius | • | • |
91 -| smartd_log.reallocated_sectors_count | a dimension per device | sectors | | • |
92 -| smartd_log.reserved_block_count | a dimension per device | percentage | | • |
93 -| smartd_log.program_fail_count | a dimension per device | errors | | • |
94 -| smartd_log.erase_fail_count | a dimension per device | failures | | • |
95 -| smartd_log.wear_leveller_worst_case_erase_count | a dimension per device | erases | | • |
96 -| smartd_log.unused_reserved_nand_blocks | a dimension per device | blocks | | • |
97 -| smartd_log.reallocation_event_count | a dimension per device | events | | • |
98 -| smartd_log.current_pending_sector_count | a dimension per device | sectors | | • |
99 -| smartd_log.offline_uncorrectable_sector_count | a dimension per device | sectors | | • |
100 -| smartd_log.percent_lifetime_used | a dimension per device | percentage | | • |
101 -| smartd_log.media_wearout_indicator | a dimension per device | percentage | | • |
102 -| smartd_log.nand_writes_1gib | a dimension per device | GiB | | • |
103 -
104 -
105 -
106 -## Alerts
107 -
108 -There are no alerts configured by default for this integration.
109 -
110 -
111 -## Setup
112 -
113 -### Prerequisites
114 -
115 -#### Configure `smartd` to write attribute information to files.
116 -
117 -`smartd` must be running with `-A` option to write `smartd` attribute information to files.
118 -
119 -For this you need to set `smartd_opts` (or `SMARTD_ARGS`, check _smartd.service_ content) in `/etc/default/smartmontools`:
120 -
121 -```
122 -# dump smartd attrs info every 600 seconds
123 -smartd_opts="-A /var/log/smartd/ -i 600"
124 -```
125 -
126 -You may need to create the smartd directory before smartd will write to it:
127 -
128 -```sh
129 -mkdir -p /var/log/smartd
130 -```
131 -
132 -Otherwise, all the smartd `.csv` files may get written to `/var/lib/smartmontools` (default location). See also <https://linux.die.net/man/8/smartd> for more info on the `-A --attributelog=PREFIX` command.
133 -
134 -`smartd` appends logs at every run. It's strongly recommended to use `logrotate` for smartd files.
135 -
136 -
137 -
138 -### Configuration
139 -
140 -#### File
141 -
142 -The configuration file name for this integration is `python.d/smartd_log.conf`.
143 -
144 -
145 -You can edit the configuration file using the `edit-config` script from the
146 -Netdata [config directory](https://github.com/netdata/netdata/blob/master/docs/netdata-agent/configuration.md#the-netdata-config-directory).
147 -
148 -```bash
149 -cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
150 -sudo ./edit-config python.d/smartd_log.conf
151 -```
152 -#### Options
153 -
154 -This particular collector does not need further configuration to work if permissions are satisfied, but you can always customize it's data collection behavior.
155 -
156 -There are 2 sections:
157 -
158 -* Global variables
159 -* One or more JOBS that can define multiple different instances to monitor.
160 -
161 -The following options can be defined globally: priority, penalty, autodetection_retry, update_every, but can also be defined per JOB to override the global values.
162 -
163 -Additionally, the following collapsed table contains all the options that can be configured inside a JOB definition.
164 -
165 -Every configuration JOB starts with a `job_name` value which will appear in the dashboard, unless a `name` parameter is specified.
166 -
167 -
168 -<details><summary>Config options</summary>
169 -
170 -| Name | Description | Default | Required |
171 -|:----|:-----------|:-------|:--------:|
172 -| log_path | path to smartd log files. | /var/log/smartd | yes |
173 -| exclude_disks | Space-separated patterns. If the pattern is in the drive name, the module will not collect data for it. | | no |
174 -| age | Time in minutes since the last dump to file. | 30 | no |
175 -| update_every | Sets the default data collection frequency. | 1 | no |
176 -| priority | Controls the order of charts at the netdata dashboard. | 60000 | no |
177 -| autodetection_retry | Sets the job re-check interval in seconds. | 0 | no |
178 -| penalty | Indicates whether to apply penalty to update_every in case of failures. | yes | no |
179 -| name | Job name. This value will overwrite the `job_name` value. 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. | | no |
180 -
181 -</details>
182 -
183 -#### Examples
184 -
185 -##### Basic
186 -
187 -A basic configuration example.
188 -
189 -```yaml
190 -custom:
191 - name: smartd_log
192 - log_path: '/var/log/smartd/'
193 -
194 -```
195 -
196 -
197 -## Troubleshooting
198 -
199 -### Debug Mode
200 -
201 -To troubleshoot issues with the `smartd_log` collector, run the `python.d.plugin` with the debug option enabled. The output
202 -should give you clues as to why the collector isn't working.
203 -
204 -- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on
205 - your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`.
206 -
207 - ```bash
208 - cd /usr/libexec/netdata/plugins.d/
209 - ```
210 -
211 -- Switch to the `netdata` user.
212 -
213 - ```bash
214 - sudo -u netdata -s
215 - ```
216 -
217 -- Run the `python.d.plugin` to debug the collector:
218 -
219 - ```bash
220 - ./python.d.plugin smartd_log debug trace
221 - ```
222 -
223 -
src/collectors/python.d.plugin/smartd_log/metadata.yaml deleted
-429
@@ -1,429 +0,0 @@
1 -plugin_name: python.d.plugin
2 -modules:
3 - - meta:
4 - plugin_name: python.d.plugin
5 - module_name: smartd_log
6 - monitored_instance:
7 - name: S.M.A.R.T.
8 - link: "https://linux.die.net/man/8/smartd"
9 - categories:
10 - - data-collection.hardware-devices-and-sensors
11 - icon_filename: "smart.png"
12 - related_resources:
13 - integrations:
14 - list: []
15 - info_provided_to_referring_integrations:
16 - description: ""
17 - keywords:
18 - - smart
19 - - S.M.A.R.T.
20 - - SCSI devices
21 - - ATA devices
22 - most_popular: false
23 - overview:
24 - data_collection:
25 - metrics_description: |
26 - This collector monitors HDD/SSD S.M.A.R.T. metrics about drive health and performance.
27 - method_description: |
28 - It reads `smartd` log files to collect the metrics.
29 - supported_platforms:
30 - include: []
31 - exclude: []
32 - multi_instance: false
33 - additional_permissions:
34 - description: ""
35 - default_behavior:
36 - auto_detection:
37 - description: Upon satisfying the prerequisites, the collector will auto-detect metrics if written in either `/var/log/smartd/` or `/var/lib/smartmontools/`.
38 - limits:
39 - description: ""
40 - performance_impact:
41 - description: ""
42 - setup:
43 - prerequisites:
44 - list:
45 - - title: Configure `smartd` to write attribute information to files.
46 - description: |
47 - `smartd` must be running with `-A` option to write `smartd` attribute information to files.
48 -
49 - For this you need to set `smartd_opts` (or `SMARTD_ARGS`, check _smartd.service_ content) in `/etc/default/smartmontools`:
50 -
51 - ```
52 - # dump smartd attrs info every 600 seconds
53 - smartd_opts="-A /var/log/smartd/ -i 600"
54 - ```
55 -
56 - You may need to create the smartd directory before smartd will write to it:
57 -
58 - ```sh
59 - mkdir -p /var/log/smartd
60 - ```
61 -
62 - Otherwise, all the smartd `.csv` files may get written to `/var/lib/smartmontools` (default location). See also <https://linux.die.net/man/8/smartd> for more info on the `-A --attributelog=PREFIX` command.
63 -
64 - `smartd` appends logs at every run. It's strongly recommended to use `logrotate` for smartd files.
65 - configuration:
66 - file:
67 - name: "python.d/smartd_log.conf"
68 - options:
69 - description: |
70 - This particular collector does not need further configuration to work if permissions are satisfied, but you can always customize it's data collection behavior.
71 -
72 - There are 2 sections:
73 -
74 - * Global variables
75 - * One or more JOBS that can define multiple different instances to monitor.
76 -
77 - The following options can be defined globally: priority, penalty, autodetection_retry, update_every, but can also be defined per JOB to override the global values.
78 -
79 - Additionally, the following collapsed table contains all the options that can be configured inside a JOB definition.
80 -
81 - Every configuration JOB starts with a `job_name` value which will appear in the dashboard, unless a `name` parameter is specified.
82 - folding:
83 - title: "Config options"
84 - enabled: true
85 - list:
86 - - name: log_path
87 - description: path to smartd log files.
88 - default_value: /var/log/smartd
89 - required: true
90 - - name: exclude_disks
91 - description: Space-separated patterns. If the pattern is in the drive name, the module will not collect data for it.
92 - default_value: ""
93 - required: false
94 - - name: age
95 - description: Time in minutes since the last dump to file.
96 - default_value: 30
97 - required: false
98 - - name: update_every
99 - description: Sets the default data collection frequency.
100 - default_value: 1
101 - required: false
102 - - name: priority
103 - description: Controls the order of charts at the netdata dashboard.
104 - default_value: 60000
105 - required: false
106 - - name: autodetection_retry
107 - description: Sets the job re-check interval in seconds.
108 - default_value: 0
109 - required: false
110 - - name: penalty
111 - description: Indicates whether to apply penalty to update_every in case of failures.
112 - default_value: yes
113 - required: false
114 - - name: name
115 - description: >
116 - Job name. This value will overwrite the `job_name` value. 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.
117 - default_value: ""
118 - required: false
119 - examples:
120 - folding:
121 - enabled: true
122 - title: "Config"
123 - list:
124 - - name: Basic
125 - description: A basic configuration example.
126 - folding:
127 - enabled: false
128 - config: |
129 - custom:
130 - name: smartd_log
131 - log_path: '/var/log/smartd/'
132 - troubleshooting:
133 - problems:
134 - list: []
135 - alerts: []
136 - metrics:
137 - folding:
138 - title: Metrics
139 - enabled: false
140 - description: "The metrics listed below are split in terms of availability on device type, SCSI or ATA."
141 - availability:
142 - - "SCSI"
143 - - "ATA"
144 - scopes:
145 - - name: global
146 - description: "These metrics refer to the entire monitored application."
147 - labels: []
148 - metrics:
149 - - name: smartd_log.read_error_rate
150 - description: Read Error Rate
151 - availability:
152 - - ATA
153 - unit: "value"
154 - chart_type: line
155 - dimensions:
156 - - name: a dimension per device
157 - - name: smartd_log.seek_error_rate
158 - description: Seek Error Rate
159 - availability:
160 - - ATA
161 - unit: "value"
162 - chart_type: line
163 - dimensions:
164 - - name: a dimension per device
165 - - name: smartd_log.soft_read_error_rate
166 - description: Soft Read Error Rate
167 - availability:
168 - - ATA
169 - unit: "errors"
170 - chart_type: line
171 - dimensions:
172 - - name: a dimension per device
173 - - name: smartd_log.write_error_rate
174 - description: Write Error Rate
175 - availability:
176 - - ATA
177 - unit: "value"
178 - chart_type: line
179 - dimensions:
180 - - name: a dimension per device
181 - - name: smartd_log.read_total_err_corrected
182 - description: Read Error Corrected
183 - availability:
184 - - SCSI
185 - unit: "errors"
186 - chart_type: line
187 - dimensions:
188 - - name: a dimension per device
189 - - name: smartd_log.read_total_unc_errors
190 - description: Read Error Uncorrected
191 - availability:
192 - - SCSI
193 - unit: "errors"
194 - chart_type: line
195 - dimensions:
196 - - name: a dimension per device
197 - - name: smartd_log.write_total_err_corrected
198 - description: Write Error Corrected
199 - availability:
200 - - SCSI
201 - unit: "errors"
202 - chart_type: line
203 - dimensions:
204 - - name: a dimension per device
205 - - name: smartd_log.write_total_unc_errors
206 - description: Write Error Uncorrected
207 - availability:
208 - - SCSI
209 - unit: "errors"
210 - chart_type: line
211 - dimensions:
212 - - name: a dimension per device
213 - - name: smartd_log.verify_total_err_corrected
214 - description: Verify Error Corrected
215 - availability:
216 - - SCSI
217 - unit: "errors"
218 - chart_type: line
219 - dimensions:
220 - - name: a dimension per device
221 - - name: smartd_log.verify_total_unc_errors
222 - description: Verify Error Uncorrected
223 - availability:
224 - - SCSI
225 - unit: "errors"
226 - chart_type: line
227 - dimensions:
228 - - name: a dimension per device
229 - - name: smartd_log.sata_interface_downshift
230 - description: SATA Interface Downshift
231 - availability:
232 - - ATA
233 - unit: "events"
234 - chart_type: line
235 - dimensions:
236 - - name: a dimension per device
237 - - name: smartd_log.udma_crc_error_count
238 - description: UDMA CRC Error Count
239 - availability:
240 - - ATA
241 - unit: "errors"
242 - chart_type: line
243 - dimensions:
244 - - name: a dimension per device
245 - - name: smartd_log.throughput_performance
246 - description: Throughput Performance
247 - availability:
248 - - ATA
249 - unit: "value"
250 - chart_type: line
251 - dimensions:
252 - - name: a dimension per device
253 - - name: smartd_log.seek_time_performance
254 - description: Seek Time Performance
255 - availability:
256 - - ATA
257 - unit: "value"
258 - chart_type: line
259 - dimensions:
260 - - name: a dimension per device
261 - - name: smartd_log.start_stop_count
262 - description: Start/Stop Count
263 - availability:
264 - - ATA
265 - unit: "events"
266 - chart_type: line
267 - dimensions:
268 - - name: a dimension per device
269 - - name: smartd_log.power_on_hours_count
270 - description: Power-On Hours Count
271 - availability:
272 - - ATA
273 - unit: "hours"
274 - chart_type: line
275 - dimensions:
276 - - name: a dimension per device
277 - - name: smartd_log.power_cycle_count
278 - description: Power Cycle Count
279 - availability:
280 - - ATA
281 - unit: "events"
282 - chart_type: line
283 - dimensions:
284 - - name: a dimension per device
285 - - name: smartd_log.unexpected_power_loss
286 - description: Unexpected Power Loss
287 - availability:
288 - - ATA
289 - unit: "events"
290 - chart_type: line
291 - dimensions:
292 - - name: a dimension per device
293 - - name: smartd_log.spin_up_time
294 - description: Spin-Up Time
295 - availability:
296 - - ATA
297 - unit: "ms"
298 - chart_type: line
299 - dimensions:
300 - - name: a dimension per device
301 - - name: smartd_log.spin_up_retries
302 - description: Spin-up Retries
303 - availability:
304 - - ATA
305 - unit: "retries"
306 - chart_type: line
307 - dimensions:
308 - - name: a dimension per device
309 - - name: smartd_log.calibration_retries
310 - description: Calibration Retries
311 - availability:
312 - - ATA
313 - unit: "retries"
314 - chart_type: line
315 - dimensions:
316 - - name: a dimension per device
317 - - name: smartd_log.airflow_temperature_celsius
318 - description: Airflow Temperature Celsius
319 - availability:
320 - - ATA
321 - unit: "celsius"
322 - chart_type: line
323 - dimensions:
324 - - name: a dimension per device
325 - - name: smartd_log.temperature_celsius
326 - description: Temperature
327 - availability:
328 - - SCSI
329 - - ATA
330 - unit: "celsius"
331 - chart_type: line
332 - dimensions:
333 - - name: a dimension per device
334 - - name: smartd_log.reallocated_sectors_count
335 - description: Reallocated Sectors Count
336 - availability:
337 - - ATA
338 - unit: "sectors"
339 - chart_type: line
340 - dimensions:
341 - - name: a dimension per device
342 - - name: smartd_log.reserved_block_count
343 - description: Reserved Block Count
344 - availability:
345 - - ATA
346 - unit: "percentage"
347 - chart_type: line
348 - dimensions:
349 - - name: a dimension per device
350 - - name: smartd_log.program_fail_count
351 - description: Program Fail Count
352 - availability:
353 - - ATA
354 - unit: "errors"
355 - chart_type: line
356 - dimensions:
357 - - name: a dimension per device
358 - - name: smartd_log.erase_fail_count
359 - description: Erase Fail Count
360 - availability:
361 - - ATA
362 - unit: "failures"
363 - chart_type: line
364 - dimensions:
365 - - name: a dimension per device
366 - - name: smartd_log.wear_leveller_worst_case_erase_count
367 - description: Wear Leveller Worst Case Erase Count
368 - availability:
369 - - ATA
370 - unit: "erases"
371 - chart_type: line
372 - dimensions:
373 - - name: a dimension per device
374 - - name: smartd_log.unused_reserved_nand_blocks
375 - description: Unused Reserved NAND Blocks
376 - availability:
377 - - ATA
378 - unit: "blocks"
379 - chart_type: line
380 - dimensions:
381 - - name: a dimension per device
382 - - name: smartd_log.reallocation_event_count
383 - description: Reallocation Event Count
384 - availability:
385 - - ATA
386 - unit: "events"
387 - chart_type: line
388 - dimensions:
389 - - name: a dimension per device
390 - - name: smartd_log.current_pending_sector_count
391 - description: Current Pending Sector Count
392 - availability:
393 - - ATA
394 - unit: "sectors"
395 - chart_type: line
396 - dimensions:
397 - - name: a dimension per device
398 - - name: smartd_log.offline_uncorrectable_sector_count
399 - description: Offline Uncorrectable Sector Count
400 - availability:
401 - - ATA
402 - unit: "sectors"
403 - chart_type: line
404 - dimensions:
405 - - name: a dimension per device
406 - - name: smartd_log.percent_lifetime_used
407 - description: Percent Lifetime Used
408 - availability:
409 - - ATA
410 - unit: "percentage"
411 - chart_type: line
412 - dimensions:
413 - - name: a dimension per device
414 - - name: smartd_log.media_wearout_indicator
415 - description: Media Wearout Indicator
416 - availability:
417 - - ATA
418 - unit: "percentage"
419 - chart_type: line
420 - dimensions:
421 - - name: a dimension per device
422 - - name: smartd_log.nand_writes_1gib
423 - description: NAND Writes
424 - availability:
425 - - ATA
426 - unit: "GiB"
427 - chart_type: line
428 - dimensions:
429 - - name: a dimension per device
src/collectors/python.d.plugin/smartd_log/smartd_log.chart.py deleted
-790
@@ -1,790 +0,0 @@
1 -# -*- coding: utf-8 -*-
2 -# Description: smart netdata python.d module
3 -# Author: ilyam8, vorph1
4 -# SPDX-License-Identifier: GPL-3.0-or-later
5 -
6 -import os
7 -import re
8 -from copy import deepcopy
9 -from time import time
10 -
11 -from bases.FrameworkServices.SimpleService import SimpleService
12 -from bases.collection import read_last_line
13 -
14 -INCREMENTAL = 'incremental'
15 -ABSOLUTE = 'absolute'
16 -
17 -ATA = 'ata'
18 -SCSI = 'scsi'
19 -CSV = '.csv'
20 -
21 -DEF_RESCAN_INTERVAL = 60
22 -DEF_AGE = 30
23 -DEF_PATH = '/var/log/smartd'
24 -
25 -ATTR1 = '1'
26 -ATTR2 = '2'
27 -ATTR3 = '3'
28 -ATTR4 = '4'
29 -ATTR5 = '5'
30 -ATTR7 = '7'
31 -ATTR8 = '8'
32 -ATTR9 = '9'
33 -ATTR10 = '10'
34 -ATTR11 = '11'
35 -ATTR12 = '12'
36 -ATTR13 = '13'
37 -ATTR170 = '170'
38 -ATTR171 = '171'
39 -ATTR172 = '172'
40 -ATTR173 = '173'
41 -ATTR174 = '174'
42 -ATTR177 = '177'
43 -ATTR180 = '180'
44 -ATTR183 = '183'
45 -ATTR190 = '190'
46 -ATTR194 = '194'
47 -ATTR196 = '196'
48 -ATTR197 = '197'
49 -ATTR198 = '198'
50 -ATTR199 = '199'
51 -ATTR202 = '202'
52 -ATTR206 = '206'
53 -ATTR233 = '233'
54 -ATTR241 = '241'
55 -ATTR242 = '242'
56 -ATTR249 = '249'
57 -ATTR_READ_ERR_COR = 'read-total-err-corrected'
58 -ATTR_READ_ERR_UNC = 'read-total-unc-errors'
59 -ATTR_WRITE_ERR_COR = 'write-total-err-corrected'
60 -ATTR_WRITE_ERR_UNC = 'write-total-unc-errors'
61 -ATTR_VERIFY_ERR_COR = 'verify-total-err-corrected'
62 -ATTR_VERIFY_ERR_UNC = 'verify-total-unc-errors'
63 -ATTR_TEMPERATURE = 'temperature'
64 -
65 -RE_ATA = re.compile(
66 - '(\d+);' # attribute
67 - '(\d+);' # normalized value
68 - '(\d+)', # raw value
69 - re.X
70 -)
71 -
72 -RE_SCSI = re.compile(
73 - '([a-z-]+);' # attribute
74 - '([0-9.]+)', # raw value
75 - re.X
76 -)
77 -
78 -ORDER = [
79 - # errors
80 - 'read_error_rate',
81 - 'seek_error_rate',
82 - 'soft_read_error_rate',
83 - 'write_error_rate',
84 - 'read_total_err_corrected',
85 - 'read_total_unc_errors',
86 - 'write_total_err_corrected',
87 - 'write_total_unc_errors',
88 - 'verify_total_err_corrected',
89 - 'verify_total_unc_errors',
90 - # external failure
91 - 'sata_interface_downshift',
92 - 'udma_crc_error_count',
93 - # performance
94 - 'throughput_performance',
95 - 'seek_time_performance',
96 - # power
97 - 'start_stop_count',
98 - 'power_on_hours_count',
99 - 'power_cycle_count',
100 - 'unexpected_power_loss',
101 - # spin
102 - 'spin_up_time',
103 - 'spin_up_retries',
104 - 'calibration_retries',
105 - # temperature
106 - 'airflow_temperature_celsius',
107 - 'temperature_celsius',
108 - # wear
109 - 'reallocated_sectors_count',
110 - 'reserved_block_count',
111 - 'program_fail_count',
112 - 'erase_fail_count',
113 - 'wear_leveller_worst_case_erase_count',
114 - 'unused_reserved_nand_blocks',
115 - 'reallocation_event_count',
116 - 'current_pending_sector_count',
117 - 'offline_uncorrectable_sector_count',
118 - 'percent_lifetime_used',
119 - 'media_wearout_indicator',
120 - 'total_lbas_written',
121 - 'total_lbas_read',
122 -]
123 -
124 -CHARTS = {
125 - 'read_error_rate': {
126 - 'options': [None, 'Read Error Rate', 'value', 'errors', 'smartd_log.read_error_rate', 'line'],
127 - 'lines': [],
128 - 'attrs': [ATTR1],
129 - 'algo': ABSOLUTE,
130 - },
131 - 'seek_error_rate': {
132 - 'options': [None, 'Seek Error Rate', 'value', 'errors', 'smartd_log.seek_error_rate', 'line'],
133 - 'lines': [],
134 - 'attrs': [ATTR7],
135 - 'algo': ABSOLUTE,
136 - },
137 - 'soft_read_error_rate': {
138 - 'options': [None, 'Soft Read Error Rate', 'errors', 'errors', 'smartd_log.soft_read_error_rate', 'line'],
139 - 'lines': [],
140 - 'attrs': [ATTR13],
141 - 'algo': INCREMENTAL,
142 - },
143 - 'write_error_rate': {
144 - 'options': [None, 'Write Error Rate', 'value', 'errors', 'smartd_log.write_error_rate', 'line'],
145 - 'lines': [],
146 - 'attrs': [ATTR206],
147 - 'algo': ABSOLUTE,
148 - },
149 - 'read_total_err_corrected': {
150 - 'options': [None, 'Read Error Corrected', 'errors', 'errors', 'smartd_log.read_total_err_corrected', 'line'],
151 - 'lines': [],
152 - 'attrs': [ATTR_READ_ERR_COR],
153 - 'algo': INCREMENTAL,
154 - },
155 - 'read_total_unc_errors': {
156 - 'options': [None, 'Read Error Uncorrected', 'errors', 'errors', 'smartd_log.read_total_unc_errors', 'line'],
157 - 'lines': [],
158 - 'attrs': [ATTR_READ_ERR_UNC],
159 - 'algo': INCREMENTAL,
160 - },
161 - 'write_total_err_corrected': {
162 - 'options': [None, 'Write Error Corrected', 'errors', 'errors', 'smartd_log.write_total_err_corrected', 'line'],
163 - 'lines': [],
164 - 'attrs': [ATTR_WRITE_ERR_COR],
165 - 'algo': INCREMENTAL,
166 - },
167 - 'write_total_unc_errors': {
168 - 'options': [None, 'Write Error Uncorrected', 'errors', 'errors', 'smartd_log.write_total_unc_errors', 'line'],
169 - 'lines': [],
170 - 'attrs': [ATTR_WRITE_ERR_UNC],
171 - 'algo': INCREMENTAL,
172 - },
173 - 'verify_total_err_corrected': {
174 - 'options': [None, 'Verify Error Corrected', 'errors', 'errors', 'smartd_log.verify_total_err_corrected',
175 - 'line'],
176 - 'lines': [],
177 - 'attrs': [ATTR_VERIFY_ERR_COR],
178 - 'algo': INCREMENTAL,
179 - },
180 - 'verify_total_unc_errors': {
181 - 'options': [None, 'Verify Error Uncorrected', 'errors', 'errors', 'smartd_log.verify_total_unc_errors', 'line'],
182 - 'lines': [],
183 - 'attrs': [ATTR_VERIFY_ERR_UNC],
184 - 'algo': INCREMENTAL,
185 - },
186 - 'sata_interface_downshift': {
187 - 'options': [None, 'SATA Interface Downshift', 'events', 'external failure',
188 - 'smartd_log.sata_interface_downshift', 'line'],
189 - 'lines': [],
190 - 'attrs': [ATTR183],
191 - 'algo': INCREMENTAL,
192 - },
193 - 'udma_crc_error_count': {
194 - 'options': [None, 'UDMA CRC Error Count', 'errors', 'external failure', 'smartd_log.udma_crc_error_count',
195 - 'line'],
196 - 'lines': [],
197 - 'attrs': [ATTR199],
198 - 'algo': INCREMENTAL,
199 - },
200 - 'throughput_performance': {
201 - 'options': [None, 'Throughput Performance', 'value', 'performance', 'smartd_log.throughput_performance',
202 - 'line'],
203 - 'lines': [],
204 - 'attrs': [ATTR2],
205 - 'algo': ABSOLUTE,
206 - },
207 - 'seek_time_performance': {
208 - 'options': [None, 'Seek Time Performance', 'value', 'performance', 'smartd_log.seek_time_performance', 'line'],
209 - 'lines': [],
210 - 'attrs': [ATTR8],
211 - 'algo': ABSOLUTE,
212 - },
213 - 'start_stop_count': {
214 - 'options': [None, 'Start/Stop Count', 'events', 'power', 'smartd_log.start_stop_count', 'line'],
215 - 'lines': [],
216 - 'attrs': [ATTR4],
217 - 'algo': ABSOLUTE,
218 - },
219 - 'power_on_hours_count': {
220 - 'options': [None, 'Power-On Hours Count', 'hours', 'power', 'smartd_log.power_on_hours_count', 'line'],
221 - 'lines': [],
222 - 'attrs': [ATTR9],
223 - 'algo': ABSOLUTE,
224 - },
225 - 'power_cycle_count': {
226 - 'options': [None, 'Power Cycle Count', 'events', 'power', 'smartd_log.power_cycle_count', 'line'],
227 - 'lines': [],
228 - 'attrs': [ATTR12],
229 - 'algo': ABSOLUTE,
230 - },
231 - 'unexpected_power_loss': {
232 - 'options': [None, 'Unexpected Power Loss', 'events', 'power', 'smartd_log.unexpected_power_loss', 'line'],
233 - 'lines': [],
234 - 'attrs': [ATTR174],
235 - 'algo': ABSOLUTE,
236 - },
237 - 'spin_up_time': {
238 - 'options': [None, 'Spin-Up Time', 'ms', 'spin', 'smartd_log.spin_up_time', 'line'],
239 - 'lines': [],
240 - 'attrs': [ATTR3],
241 - 'algo': ABSOLUTE,
242 - },
243 - 'spin_up_retries': {
244 - 'options': [None, 'Spin-up Retries', 'retries', 'spin', 'smartd_log.spin_up_retries', 'line'],
245 - 'lines': [],
246 - 'attrs': [ATTR10],
247 - 'algo': INCREMENTAL,
248 - },
249 - 'calibration_retries': {
250 - 'options': [None, 'Calibration Retries', 'retries', 'spin', 'smartd_log.calibration_retries', 'line'],
251 - 'lines': [],
252 - 'attrs': [ATTR11],
253 - 'algo': INCREMENTAL,
254 - },
255 - 'airflow_temperature_celsius': {
256 - 'options': [None, 'Airflow Temperature Celsius', 'celsius', 'temperature',
257 - 'smartd_log.airflow_temperature_celsius', 'line'],
258 - 'lines': [],
259 - 'attrs': [ATTR190],
260 - 'algo': ABSOLUTE,
261 - },
262 - 'temperature_celsius': {
263 - 'options': [None, 'Temperature', 'celsius', 'temperature', 'smartd_log.temperature_celsius', 'line'],
264 - 'lines': [],
265 - 'attrs': [ATTR194, ATTR_TEMPERATURE],
266 - 'algo': ABSOLUTE,
267 - },
268 - 'reallocated_sectors_count': {
269 - 'options': [None, 'Reallocated Sectors Count', 'sectors', 'wear', 'smartd_log.reallocated_sectors_count',
270 - 'line'],
271 - 'lines': [],
272 - 'attrs': [ATTR5],
273 - 'algo': ABSOLUTE,
274 - },
275 - 'reserved_block_count': {
276 - 'options': [None, 'Reserved Block Count', 'percentage', 'wear', 'smartd_log.reserved_block_count', 'line'],
277 - 'lines': [],
278 - 'attrs': [ATTR170],
279 - 'algo': ABSOLUTE,
280 - },
281 - 'program_fail_count': {
282 - 'options': [None, 'Program Fail Count', 'errors', 'wear', 'smartd_log.program_fail_count', 'line'],
283 - 'lines': [],
284 - 'attrs': [ATTR171],
285 - 'algo': INCREMENTAL,
286 - },
287 - 'erase_fail_count': {
288 - 'options': [None, 'Erase Fail Count', 'failures', 'wear', 'smartd_log.erase_fail_count', 'line'],
289 - 'lines': [],
290 - 'attrs': [ATTR172],
291 - 'algo': INCREMENTAL,
292 - },
293 - 'wear_leveller_worst_case_erase_count': {
294 - 'options': [None, 'Wear Leveller Worst Case Erase Count', 'erases', 'wear',
295 - 'smartd_log.wear_leveller_worst_case_erase_count', 'line'],
296 - 'lines': [],
297 - 'attrs': [ATTR173],
298 - 'algo': ABSOLUTE,
299 - },
300 - 'unused_reserved_nand_blocks': {
301 - 'options': [None, 'Unused Reserved NAND Blocks', 'blocks', 'wear', 'smartd_log.unused_reserved_nand_blocks',
302 - 'line'],
303 - 'lines': [],
304 - 'attrs': [ATTR180],
305 - 'algo': ABSOLUTE,
306 - },
307 - 'reallocation_event_count': {
308 - 'options': [None, 'Reallocation Event Count', 'events', 'wear', 'smartd_log.reallocation_event_count', 'line'],
309 - 'lines': [],
310 - 'attrs': [ATTR196],
311 - 'algo': INCREMENTAL,
312 - },
313 - 'current_pending_sector_count': {
314 - 'options': [None, 'Current Pending Sector Count', 'sectors', 'wear', 'smartd_log.current_pending_sector_count',
315 - 'line'],
316 - 'lines': [],
317 - 'attrs': [ATTR197],
318 - 'algo': ABSOLUTE,
319 - },
320 - 'offline_uncorrectable_sector_count': {
321 - 'options': [None, 'Offline Uncorrectable Sector Count', 'sectors', 'wear',
322 - 'smartd_log.offline_uncorrectable_sector_count', 'line'],
323 - 'lines': [],
324 - 'attrs': [ATTR198],
325 - 'algo': ABSOLUTE,
326 -
327 - },
328 - 'percent_lifetime_used': {
329 - 'options': [None, 'Percent Lifetime Used', 'percentage', 'wear', 'smartd_log.percent_lifetime_used', 'line'],
330 - 'lines': [],
331 - 'attrs': [ATTR202],
332 - 'algo': ABSOLUTE,
333 - },
334 - 'media_wearout_indicator': {
335 - 'options': [None, 'Media Wearout Indicator', 'percentage', 'wear', 'smartd_log.media_wearout_indicator', 'line'],
336 - 'lines': [],
337 - 'attrs': [ATTR233, ATTR177],
338 - 'algo': ABSOLUTE,
339 - },
340 - 'nand_writes_1gib': {
341 - 'options': [None, 'NAND Writes', 'GiB', 'wear', 'smartd_log.nand_writes_1gib', 'line'],
342 - 'lines': [],
343 - 'attrs': [ATTR249],
344 - 'algo': ABSOLUTE,
345 - },
346 - 'total_lbas_written': {
347 - 'options': [None, 'Total LBAs Written', 'sectors', 'wear', 'smartd_log.total_lbas_written', 'line'],
348 - 'lines': [],
349 - 'attrs': [ATTR241],
350 - 'algo': ABSOLUTE,
351 - },
352 - 'total_lbas_read': {
353 - 'options': [None, 'Total LBAs Read', 'sectors', 'wear', 'smartd_log.total_lbas_read', 'line'],
354 - 'lines': [],
355 - 'attrs': [ATTR242],
356 - 'algo': ABSOLUTE,
357 - },
358 -}
359 -
360 -# NOTE: 'parse_temp' decodes ATA 194 raw value. Not heavily tested. Written by @Ferroin
361 -# C code:
362 -# https://github.com/smartmontools/smartmontools/blob/master/smartmontools/atacmds.cpp#L2051
363 -#
364 -# Calling 'parse_temp' on the raw value will return a 4-tuple, containing
365 -# * temperature
366 -# * minimum
367 -# * maximum
368 -# * over-temperature count
369 -# substituting None for values it can't decode.
370 -#
371 -# Example:
372 -# >>> parse_temp(42952491042)
373 -# >>> (34, 10, 43, None)
374 -#
375 -#
376 -# def check_temp_word(i):
377 -# if i <= 0x7F:
378 -# return 0x11
379 -# elif i <= 0xFF:
380 -# return 0x01
381 -# elif 0xFF80 <= i:
382 -# return 0x10
383 -# return 0x00
384 -#
385 -#
386 -# def check_temp_range(t, b0, b1):
387 -# if b0 > b1:
388 -# t0, t1 = b1, b0
389 -# else:
390 -# t0, t1 = b0, b1
391 -#
392 -# if all([
393 -# -60 <= t0,
394 -# t0 <= t,
395 -# t <= t1,
396 -# t1 <= 120,
397 -# not (t0 == -1 and t1 <= 0)
398 -# ]):
399 -# return t0, t1
400 -# return None, None
401 -#
402 -#
403 -# def parse_temp(raw):
404 -# byte = list()
405 -# word = list()
406 -# for i in range(0, 6):
407 -# byte.append(0xFF & (raw >> (i * 8)))
408 -# for i in range(0, 3):
409 -# word.append(0xFFFF & (raw >> (i * 16)))
410 -#
411 -# ctwd = check_temp_word(word[0])
412 -#
413 -# if not word[2]:
414 -# if ctwd and not word[1]:
415 -# # byte[0] is temp, no other data
416 -# return byte[0], None, None, None
417 -#
418 -# if ctwd and all(check_temp_range(byte[0], byte[2], byte[3])):
419 -# # byte[0] is temp, byte[2] is max or min, byte[3] is min or max
420 -# trange = check_temp_range(byte[0], byte[2], byte[3])
421 -# return byte[0], trange[0], trange[1], None
422 -#
423 -# if ctwd and all(check_temp_range(byte[0], byte[1], byte[2])):
424 -# # byte[0] is temp, byte[1] is max or min, byte[2] is min or max
425 -# trange = check_temp_range(byte[0], byte[1], byte[2])
426 -# return byte[0], trange[0], trange[1], None
427 -#
428 -# return None, None, None, None
429 -#
430 -# if ctwd:
431 -# if all(
432 -# [
433 -# ctwd & check_temp_word(word[1]) & check_temp_word(word[2]) != 0x00,
434 -# all(check_temp_range(byte[0], byte[2], byte[4])),
435 -# ]
436 -# ):
437 -# # byte[0] is temp, byte[2] is max or min, byte[4] is min or max
438 -# trange = check_temp_range(byte[0], byte[2], byte[4])
439 -# return byte[0], trange[0], trange[1], None
440 -# else:
441 -# trange = check_temp_range(byte[0], byte[2], byte[3])
442 -# if word[2] < 0x7FFF and all(trange) and trange[1] >= 40:
443 -# # byte[0] is temp, byte[2] is max or min, byte[3] is min or max, word[2] is overtemp count
444 -# return byte[0], trange[0], trange[1], word[2]
445 -# # no data
446 -# return None, None, None, None
447 -
448 -
449 -CHARTED_ATTRS = dict((attr, k) for k, v in CHARTS.items() for attr in v['attrs'])
450 -
451 -
452 -class BaseAtaSmartAttribute:
453 - def __init__(self, name, normalized_value, raw_value):
454 - self.name = name
455 - self.normalized_value = normalized_value
456 - self.raw_value = raw_value
457 -
458 - def value(self):
459 - raise NotImplementedError
460 -
461 -
462 -class AtaRaw(BaseAtaSmartAttribute):
463 - def value(self):
464 - return self.raw_value
465 -
466 -
467 -class AtaNormalized(BaseAtaSmartAttribute):
468 - def value(self):
469 - return self.normalized_value
470 -
471 -
472 -class Ata3(BaseAtaSmartAttribute):
473 - def value(self):
474 - value = int(self.raw_value)
475 - # https://github.com/netdata/netdata/issues/5919
476 - #
477 - # 3;151;38684000679;
478 - # 423 (Average 447)
479 - # 38684000679 & 0xFFF -> 423
480 - # (38684000679 & 0xFFF0000) >> 16 -> 447
481 - if value > 1e6:
482 - return value & 0xFFF
483 - return value
484 -
485 -
486 -class Ata9(BaseAtaSmartAttribute):
487 - def value(self):
488 - value = int(self.raw_value)
489 - if value > 1e6:
490 - return value & 0xFFFF
491 - return value
492 -
493 -
494 -class Ata190(BaseAtaSmartAttribute):
495 - def value(self):
496 - return 100 - int(self.normalized_value)
497 -
498 -
499 -class Ata194(BaseAtaSmartAttribute):
500 - # https://github.com/netdata/netdata/issues/3041
501 - # https://github.com/netdata/netdata/issues/5919
502 - #
503 - # The low byte is the current temperature, the third lowest is the maximum, and the fifth lowest is the minimum
504 - def value(self):
505 - value = int(self.raw_value)
506 - if value > 1e6:
507 - return value & 0xFF
508 - return min(int(self.normalized_value), int(self.raw_value))
509 -
510 -
511 -class BaseSCSISmartAttribute:
512 - def __init__(self, name, raw_value):
513 - self.name = name
514 - self.raw_value = raw_value
515 -
516 - def value(self):
517 - raise NotImplementedError
518 -
519 -
520 -class SCSIRaw(BaseSCSISmartAttribute):
521 - def value(self):
522 - return self.raw_value
523 -
524 -
525 -def ata_attribute_factory(value):
526 - name = value[0]
527 -
528 - if name == ATTR3:
529 - return Ata3(*value)
530 - elif name == ATTR9:
531 - return Ata9(*value)
532 - elif name == ATTR190:
533 - return Ata190(*value)
534 - elif name == ATTR194:
535 - return Ata194(*value)
536 - elif name in [
537 - ATTR1,
538 - ATTR7,
539 - ATTR177,
540 - ATTR202,
541 - ATTR206,
542 - ATTR233,
543 - ]:
544 - return AtaNormalized(*value)
545 -
546 - return AtaRaw(*value)
547 -
548 -
549 -def scsi_attribute_factory(value):
550 - return SCSIRaw(*value)
551 -
552 -
553 -def attribute_factory(value):
554 - name = value[0]
555 - if name.isdigit():
556 - return ata_attribute_factory(value)
557 - return scsi_attribute_factory(value)
558 -
559 -
560 -def handle_error(*errors):
561 - def on_method(method):
562 - def on_call(*args):
563 - try:
564 - return method(*args)
565 - except errors:
566 - return None
567 -
568 - return on_call
569 -
570 - return on_method
571 -
572 -
573 -class DiskLogFile:
574 - def __init__(self, full_path):
575 - self.path = full_path
576 - self.size = os.path.getsize(full_path)
577 -
578 - @handle_error(OSError)
579 - def is_changed(self):
580 - return self.size != os.path.getsize(self.path)
581 -
582 - @handle_error(OSError)
583 - def is_active(self, current_time, limit):
584 - return (current_time - os.path.getmtime(self.path)) / 60 < limit
585 -
586 - @handle_error(OSError)
587 - def read(self):
588 - self.size = os.path.getsize(self.path)
589 - return read_last_line(self.path)
590 -
591 -
592 -class BaseDisk:
593 - def __init__(self, name, log_file):
594 - self.raw_name = name
595 - self.name = re.sub(r'_+', '_', name)
596 - self.log_file = log_file
597 - self.attrs = list()
598 - self.alive = True
599 - self.charted = False
600 -
601 - def __eq__(self, other):
602 - if isinstance(other, BaseDisk):
603 - return self.raw_name == other.raw_name
604 - return self.raw_name == other
605 -
606 - def __ne__(self, other):
607 - return not self == other
608 -
609 - def __hash__(self):
610 - return hash(repr(self))
611 -
612 - def parser(self, data):
613 - raise NotImplementedError
614 -
615 - @handle_error(TypeError)
616 - def populate_attrs(self):
617 - self.attrs = list()
618 - line = self.log_file.read()
619 - for value in self.parser(line):
620 - self.attrs.append(attribute_factory(value))
621 -
622 - return len(self.attrs)
623 -
624 - def data(self):
625 - data = dict()
626 - for attr in self.attrs:
627 - data['{0}_{1}'.format(self.name, attr.name)] = attr.value()
628 - return data
629 -
630 -
631 -class ATADisk(BaseDisk):
632 - def parser(self, data):
633 - return RE_ATA.findall(data)
634 -
635 -
636 -class SCSIDisk(BaseDisk):
637 - def parser(self, data):
638 - return RE_SCSI.findall(data)
639 -
640 -
641 -class Service(SimpleService):
642 - def __init__(self, configuration=None, name=None):
643 - SimpleService.__init__(self, configuration=configuration, name=name)
644 - self.order = ORDER
645 - self.definitions = deepcopy(CHARTS)
646 - self.log_path = configuration.get('log_path', DEF_PATH)
647 - self.age = configuration.get('age', DEF_AGE)
648 - self.exclude = configuration.get('exclude_disks', str()).split()
649 - self.disks = list()
650 - self.runs = 0
651 - self.do_force_rescan = False
652 -
653 - def check(self):
654 - return self.scan() > 0
655 -
656 - def get_data(self):
657 - self.runs += 1
658 -
659 - if self.do_force_rescan or self.runs % DEF_RESCAN_INTERVAL == 0:
660 - self.cleanup()
661 - self.scan()
662 - self.do_force_rescan = False
663 -
664 - data = dict()
665 -
666 - for disk in self.disks:
667 - if not disk.alive:
668 - continue
669 -
670 - if not disk.charted:
671 - self.add_disk_to_charts(disk)
672 -
673 - changed = disk.log_file.is_changed()
674 -
675 - if changed is None:
676 - disk.alive = False
677 - self.do_force_rescan = True
678 - continue
679 -
680 - if changed and disk.populate_attrs() is None:
681 - disk.alive = False
682 - self.do_force_rescan = True
683 - continue
684 -
685 - data.update(disk.data())
686 -
687 - return data
688 -
689 - def cleanup(self):
690 - current_time = time()
691 - for disk in self.disks[:]:
692 - if any(
693 - [
694 - not disk.alive,
695 - not disk.log_file.is_active(current_time, self.age),
696 - ]
697 - ):
698 - self.disks.remove(disk.raw_name)
699 - self.remove_disk_from_charts(disk)
700 -
701 - def scan(self):
702 - self.debug('scanning {0}'.format(self.log_path))
703 - current_time = time()
704 -
705 - for full_name in os.listdir(self.log_path):
706 - disk = self.create_disk_from_file(full_name, current_time)
707 - if not disk:
708 - continue
709 - self.disks.append(disk)
710 -
711 - return len(self.disks)
712 -
713 - def create_disk_from_file(self, full_name, current_time):
714 - if not full_name.endswith(CSV):
715 - self.debug('skipping {0}: not a csv file'.format(full_name))
716 - return None
717 -
718 - name = os.path.basename(full_name).split('.')[-3]
719 - path = os.path.join(self.log_path, full_name)
720 -
721 - if name in self.disks:
722 - self.debug('skipping {0}: already in disks'.format(full_name))
723 - return None
724 -
725 - if [p for p in self.exclude if p in name]:
726 - self.debug('skipping {0}: filtered by `exclude` option'.format(full_name))
727 - return None
728 -
729 - if not os.access(path, os.R_OK):
730 - self.debug('skipping {0}: not readable'.format(full_name))
731 - return None
732 -
733 - if os.path.getsize(path) == 0:
734 - self.debug('skipping {0}: zero size'.format(full_name))
735 - return None
736 -
737 - if (current_time - os.path.getmtime(path)) / 60 > self.age:
738 - self.debug('skipping {0}: haven\'t been updated for last {1} minutes'.format(full_name, self.age))
739 - return None
740 -
741 - if ATA in full_name:
742 - disk = ATADisk(name, DiskLogFile(path))
743 - elif SCSI in full_name:
744 - disk = SCSIDisk(name, DiskLogFile(path))
745 - else:
746 - self.debug('skipping {0}: unknown type'.format(full_name))
747 - return None
748 -
749 - disk.populate_attrs()
750 - if not disk.attrs:
751 - self.error('skipping {0}: parsing failed'.format(full_name))
752 - return None
753 -
754 - self.debug('added {0}'.format(full_name))
755 - return disk
756 -
757 - def add_disk_to_charts(self, disk):
758 - if len(self.charts) == 0 or disk.charted:
759 - return
760 - disk.charted = True
761 -
762 - for attr in disk.attrs:
763 - chart_id = CHARTED_ATTRS.get(attr.name)
764 -
765 - if not chart_id or chart_id not in self.charts:
766 - continue
767 -
768 - chart = self.charts[chart_id]
769 - dim = [
770 - '{0}_{1}'.format(disk.name, attr.name),
771 - disk.name,
772 - CHARTS[chart_id]['algo'],
773 - ]
774 -
775 - if dim[0] in self.charts[chart_id].dimensions:
776 - chart.hide_dimension(dim[0], reverse=True)
777 - else:
778 - chart.add_dimension(dim)
779 -
780 - def remove_disk_from_charts(self, disk):
781 - if len(self.charts) == 0 or not disk.charted:
782 - return
783 -
784 - for attr in disk.attrs:
785 - chart_id = CHARTED_ATTRS.get(attr.name)
786 -
787 - if not chart_id or chart_id not in self.charts:
788 - continue
789 -
790 - self.charts[chart_id].del_dimension('{0}_{1}'.format(disk.name, attr.name))
src/collectors/python.d.plugin/smartd_log/smartd_log.conf deleted
-76
@@ -1,76 +0,0 @@
1 -# netdata python.d.plugin configuration for smartd log
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 -# Additionally to the above, smartd_log also supports the following:
63 -#
64 -# log_path: '/path/to/smartd_logs' # path to smartd log files. Default is /var/log/smartd
65 -# exclude_disks: 'PATTERN1 PATTERN2' # space separated patterns. If the pattern is in the drive name, the module will not collect data for it.
66 -# age: 30 # time in minutes since the last dump to file. If smartd has not dumped data within this time the job exits.
67 -#
68 -# ----------------------------------------------------------------------
69 -
70 -custom:
71 - name: smartd_log
72 - log_path: '/var/log/smartd/'
73 -
74 -debian:
75 - name: smartd_log
76 - log_path: '/var/lib/smartmontools/'