mirror of
https://github.com/prometheus-community/smartctl_exporter.git
synced 2024-12-21 02:21:55 +01:00
Refactor exporter config (#68)
Switch exporter over to standard Prometheus exporter flags and logging. This eliminates the need for a configuraion file. Signed-off-by: SuperQ <superq@gmail.com>
This commit is contained in:
parent
ca94177954
commit
c8d3e48f3d
10 changed files with 221 additions and 249 deletions
10
.golangci.yml
Normal file
10
.golangci.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
issues:
|
||||
exclude-rules:
|
||||
- path: _test.go
|
||||
linters:
|
||||
- errcheck
|
||||
|
||||
linters-settings:
|
||||
errcheck:
|
||||
exclude: scripts/errcheck_excludes.txt
|
48
README.md
48
README.md
|
@ -15,26 +15,34 @@ smartmontools >= 7.0, because export to json [released in 7.0](https://www.smart
|
|||
|
||||
# Configuration
|
||||
## Command line options
|
||||
* `--config=/path/to/file.yaml`: Path to configuration file, default `/etc/smartctl_exporter.yaml`
|
||||
* `--verbose`: verbosed log, default no
|
||||
* `--debug`: Debug logging, default no
|
||||
* `--version`: Show version and exit
|
||||
|
||||
## Configuration file
|
||||
Example content:
|
||||
The exporter will scan the system for available devices if no `--smartctl.device` flags are used.
|
||||
|
||||
```
|
||||
smartctl_exporter:
|
||||
bind_to: "[::1]:9633"
|
||||
url_path: "/metrics"
|
||||
fake_json: no
|
||||
smartctl_location: /usr/sbin/smartctl
|
||||
collect_not_more_than_period: 120s
|
||||
devices:
|
||||
- /dev/sda
|
||||
- /dev/sdb
|
||||
- /dev/sdc
|
||||
- /dev/sdd
|
||||
- /dev/sde
|
||||
- /dev/sdf
|
||||
usage: smartctl_exporter [<flags>]
|
||||
|
||||
Flags:
|
||||
-h, --help Show context-sensitive help (also try --help-long and --help-man).
|
||||
--smartctl.path="/usr/sbin/smartctl"
|
||||
The path to the smartctl binary
|
||||
--smartctl.interval=60s The interval between smarctl polls
|
||||
--smartctl.device=SMARTCTL.DEVICE ...
|
||||
The device to monitor (repeatable)
|
||||
--web.listen-address=":9633"
|
||||
Address to listen on for web interface and telemetry
|
||||
--web.telemetry-path="/metrics"
|
||||
Path under which to expose metrics
|
||||
--web.config.file="" [EXPERIMENTAL] Path to configuration file that can enable TLS or authentication.
|
||||
--log.level=info Only log messages with the given severity or above. One of: [debug, info, warn,
|
||||
error]
|
||||
--log.format=logfmt Output format of log messages. One of: [logfmt, json]
|
||||
--version Show application version.
|
||||
```
|
||||
`fake_json` used for debugging.
|
||||
|
||||
## TLS and basic authentication
|
||||
|
||||
This exporter supports TLS and basic authentication.
|
||||
|
||||
To use TLS and/or basic authentication, you need to pass a configuration file
|
||||
using the `--web.config.file` parameter. The format of the file is described
|
||||
[in the exporter-toolkit repository](https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md).
|
||||
|
|
18
go.mod
18
go.mod
|
@ -3,21 +3,35 @@ module github.com/prometheus-community/smartctl_exporter
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/go-kit/log v0.2.1
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/prometheus/common v0.37.0
|
||||
github.com/prometheus/exporter-toolkit v0.7.1
|
||||
github.com/tidwall/gjson v1.14.3
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/jpillora/backoff v1.0.0 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/appengine v1.6.6 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
|
22
go.sum
22
go.sum
|
@ -34,9 +34,11 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
|
@ -52,6 +54,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
|
@ -64,9 +67,12 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
|
@ -127,6 +133,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
|||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
|
@ -153,10 +160,13 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
|
@ -173,9 +183,12 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T
|
|||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
|
||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/exporter-toolkit v0.7.1 h1:c6RXaK8xBVercEeUQ4tRNL8UGWzDHfvj9dseo1FcK1Y=
|
||||
github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
|
@ -191,6 +204,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
|
||||
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
|
@ -212,6 +226,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -270,8 +286,10 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
|
|||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -279,6 +297,7 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
|
|||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -339,6 +358,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -408,6 +428,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
|||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
@ -464,6 +485,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
|||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
68
logging.go
68
logging.go
|
@ -1,68 +0,0 @@
|
|||
// Copyright 2022 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Logger is logger
|
||||
type Logger struct {
|
||||
verbose bool
|
||||
debug bool
|
||||
}
|
||||
|
||||
func newLogger(verbose bool, debug bool) Logger {
|
||||
logger := Logger{verbose: verbose, debug: debug}
|
||||
return logger
|
||||
}
|
||||
|
||||
// Msg formatted message
|
||||
func (i Logger) print(prefix string, format string, values ...interface{}) {
|
||||
fmt.Printf(fmt.Sprintf("[%s] %s\n", prefix, format), values...)
|
||||
}
|
||||
|
||||
// Info log message
|
||||
func (i Logger) Info(format string, values ...interface{}) {
|
||||
i.print("Info", format, values...)
|
||||
}
|
||||
|
||||
// Warning log message
|
||||
func (i Logger) Warning(format string, values ...interface{}) {
|
||||
i.print("Warning", format, values...)
|
||||
}
|
||||
|
||||
// Error log message
|
||||
func (i Logger) Error(format string, values ...interface{}) {
|
||||
i.print("Error", format, values...)
|
||||
}
|
||||
|
||||
// Panic log message
|
||||
func (i Logger) Panic(format string, values ...interface{}) {
|
||||
i.print("Panic", format, values...)
|
||||
}
|
||||
|
||||
// Verbose log message
|
||||
func (i Logger) Verbose(format string, values ...interface{}) {
|
||||
if i.verbose {
|
||||
i.print("Verbose", format, values...)
|
||||
}
|
||||
}
|
||||
|
||||
// Debug log message
|
||||
func (i Logger) Debug(format string, values ...interface{}) {
|
||||
if i.debug {
|
||||
i.print("Debug", format, values...)
|
||||
}
|
||||
}
|
123
main.go
123
main.go
|
@ -14,21 +14,30 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/collectors"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
var (
|
||||
options Options
|
||||
logger Logger
|
||||
"github.com/prometheus/common/promlog"
|
||||
"github.com/prometheus/common/promlog/flag"
|
||||
"github.com/prometheus/common/version"
|
||||
"github.com/prometheus/exporter-toolkit/web"
|
||||
webflag "github.com/prometheus/exporter-toolkit/web/kingpinflag"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
// SMARTctlManagerCollector implements the Collector interface.
|
||||
type SMARTctlManagerCollector struct {
|
||||
CollectPeriod string
|
||||
CollectPeriodDuration time.Duration
|
||||
Devices []string
|
||||
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// Describe sends the super-set of all possible descriptors of metrics
|
||||
|
@ -39,43 +48,101 @@ func (i SMARTctlManagerCollector) Describe(ch chan<- *prometheus.Desc) {
|
|||
// Collect is called by the Prometheus registry when collecting metrics.
|
||||
func (i SMARTctlManagerCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
info := NewSMARTctlInfo(ch)
|
||||
for _, device := range options.SMARTctl.Devices {
|
||||
if json, err := readData(device); err == nil {
|
||||
for _, device := range i.Devices {
|
||||
if json, err := readData(i.logger, device); err == nil {
|
||||
info.SetJSON(json)
|
||||
smart := NewSMARTctl(json, ch)
|
||||
smart := NewSMARTctl(i.logger, json, ch)
|
||||
smart.Collect()
|
||||
} else {
|
||||
logger.Error(err.Error())
|
||||
level.Error(i.logger).Log("msg", "Error collecting SMART data", "err", err.Error())
|
||||
}
|
||||
}
|
||||
info.Collect()
|
||||
}
|
||||
|
||||
func init() {
|
||||
options = loadOptions()
|
||||
|
||||
if len(options.SMARTctl.Devices) == 0 {
|
||||
logger.Debug("No devices specified, trying to load them automatically")
|
||||
json := readSMARTctlDevices()
|
||||
devices := json.Get("devices").Array()
|
||||
for _, d := range devices {
|
||||
device := d.Get("name").String()
|
||||
logger.Debug("Found device: %s", device)
|
||||
options.SMARTctl.Devices = append(options.SMARTctl.Devices, device)
|
||||
}
|
||||
}
|
||||
}
|
||||
var (
|
||||
smartctlPath = kingpin.Flag("smartctl.path",
|
||||
"The path to the smartctl binary",
|
||||
).Default("/usr/sbin/smartctl").String()
|
||||
smartctlInterval = kingpin.Flag("smartctl.interval",
|
||||
"The interval between smarctl polls",
|
||||
).Default("60s").Duration()
|
||||
smartctlDevices = kingpin.Flag("smartctl.device",
|
||||
"The device to monitor (repeatable)",
|
||||
).Strings()
|
||||
smartctlFakeData = kingpin.Flag("smartctl.fake-data",
|
||||
"The device to monitor (repeatable)",
|
||||
).Default("false").Hidden().Bool()
|
||||
)
|
||||
|
||||
func main() {
|
||||
listenAddress := kingpin.Flag("web.listen-address",
|
||||
"Address to listen on for web interface and telemetry",
|
||||
).Default(":9633").String()
|
||||
metricsPath := kingpin.Flag(
|
||||
"web.telemetry-path", "Path under which to expose metrics",
|
||||
).Default("/metrics").String()
|
||||
webConfig := webflag.AddFlags(kingpin.CommandLine)
|
||||
|
||||
promlogConfig := &promlog.Config{}
|
||||
flag.AddFlags(kingpin.CommandLine, promlogConfig)
|
||||
kingpin.Version(version.Print("smartctl_exporter"))
|
||||
kingpin.HelpFlag.Short('h')
|
||||
kingpin.Parse()
|
||||
logger := promlog.New(promlogConfig)
|
||||
|
||||
level.Info(logger).Log("msg", "Starting systemd_exporter", "version", version.Info())
|
||||
level.Info(logger).Log("msg", "Build context", "build_context", version.BuildContext())
|
||||
|
||||
devices := *smartctlDevices
|
||||
|
||||
if len(devices) == 0 {
|
||||
level.Info(logger).Log("msg", "No devices specified, trying to load them automatically")
|
||||
json := readSMARTctlDevices(logger)
|
||||
scannedDevices := json.Get("devices").Array()
|
||||
for _, d := range scannedDevices {
|
||||
device := d.Get("name").String()
|
||||
level.Info(logger).Log("msg", "Found device", "device", device)
|
||||
devices = append(devices, device)
|
||||
}
|
||||
}
|
||||
|
||||
if len(devices) == 0 {
|
||||
level.Error(logger).Log("msg", "No devices found")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
collector := SMARTctlManagerCollector{
|
||||
Devices: devices,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
reg := prometheus.NewPedanticRegistry()
|
||||
reg.MustRegister(
|
||||
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
|
||||
collectors.NewGoCollector(),
|
||||
)
|
||||
|
||||
prometheus.WrapRegistererWithPrefix("", reg).MustRegister(SMARTctlManagerCollector{})
|
||||
prometheus.WrapRegistererWithPrefix("", reg).MustRegister(collector)
|
||||
|
||||
logger.Info("Starting on %s%s", options.SMARTctl.BindTo, options.SMARTctl.URLPath)
|
||||
http.Handle(options.SMARTctl.URLPath, promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
|
||||
log.Fatal(http.ListenAndServe(options.SMARTctl.BindTo, nil))
|
||||
level.Info(logger).Log("msg", "Listening on", "address", *listenAddress)
|
||||
http.Handle(*metricsPath, promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, err := w.Write([]byte(`<html>
|
||||
<head><title>Smartctl Exporter</title></head>
|
||||
<body>
|
||||
<h1>Smartctl Exporter</h1>
|
||||
<p><a href="` + *metricsPath + `">Metrics</a></p>
|
||||
</body>
|
||||
</html>`))
|
||||
if err != nil {
|
||||
level.Error(logger).Log("msg", "Couldn't write response", "err", err)
|
||||
}
|
||||
})
|
||||
|
||||
srv := &http.Server{Addr: *listenAddress}
|
||||
if err := web.ListenAndServe(srv, *webConfig, logger); err != nil {
|
||||
level.Error(logger).Log("err", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
91
options.go
91
options.go
|
@ -1,91 +0,0 @@
|
|||
// Copyright 2022 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
exporterVersion = "0.5"
|
||||
)
|
||||
|
||||
// SMARTOptions is a inner representation of a options
|
||||
type SMARTOptions struct {
|
||||
BindTo string `yaml:"bind_to"`
|
||||
URLPath string `yaml:"url_path"`
|
||||
FakeJSON bool `yaml:"fake_json"`
|
||||
SMARTctlLocation string `yaml:"smartctl_location"`
|
||||
CollectPeriod string `yaml:"collect_not_more_than_period"`
|
||||
CollectPeriodDuration time.Duration
|
||||
Devices []string `yaml:"devices"`
|
||||
}
|
||||
|
||||
// Options is a representation of a options
|
||||
type Options struct {
|
||||
SMARTctl SMARTOptions `yaml:"smartctl_exporter"`
|
||||
}
|
||||
|
||||
// Parse options from yaml config file
|
||||
func loadOptions() Options {
|
||||
configFile := flag.String("config", "/etc/smartctl_exporter.yaml", "Path to smartctl_exporter config file")
|
||||
verbose := flag.Bool("verbose", false, "Verbose log output")
|
||||
debug := flag.Bool("debug", false, "Debug log output")
|
||||
version := flag.Bool("version", false, "Show application version and exit")
|
||||
flag.Parse()
|
||||
|
||||
if *version {
|
||||
fmt.Printf("smartctl_exporter version: %s\n", exporterVersion)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
logger = newLogger(*verbose, *debug)
|
||||
|
||||
logger.Verbose("Read options from %s\n", *configFile)
|
||||
yamlFile, err := ioutil.ReadFile(*configFile)
|
||||
if err != nil {
|
||||
logger.Panic("Failed read %s: %s", configFile, err)
|
||||
}
|
||||
|
||||
opts := Options{
|
||||
SMARTOptions{
|
||||
BindTo: "9633",
|
||||
URLPath: "/metrics",
|
||||
FakeJSON: false,
|
||||
SMARTctlLocation: "/usr/sbin/smartctl",
|
||||
CollectPeriod: "60s",
|
||||
Devices: []string{},
|
||||
},
|
||||
}
|
||||
|
||||
if yaml.Unmarshal(yamlFile, &opts) != nil {
|
||||
logger.Panic("Failed parse %s: %s", configFile, err)
|
||||
}
|
||||
|
||||
d, err := time.ParseDuration(opts.SMARTctl.CollectPeriod)
|
||||
if err != nil {
|
||||
logger.Panic("Failed read collect_not_more_than_period (%s): %s", opts.SMARTctl.CollectPeriod, err)
|
||||
}
|
||||
|
||||
opts.SMARTctl.CollectPeriodDuration = d
|
||||
|
||||
logger.Debug("Parsed options: %s", opts)
|
||||
return opts
|
||||
}
|
60
readjson.go
60
readjson.go
|
@ -21,6 +21,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
|
@ -47,50 +49,50 @@ func parseJSON(data string) gjson.Result {
|
|||
}
|
||||
|
||||
// Reading fake smartctl json
|
||||
func readFakeSMARTctl(device string) gjson.Result {
|
||||
func readFakeSMARTctl(logger log.Logger, device string) gjson.Result {
|
||||
s := strings.Split(device, "/")
|
||||
filename := fmt.Sprintf("debug/%s.json", s[len(s)-1])
|
||||
logger.Verbose("Read fake S.M.A.R.T. data from json: %s", filename)
|
||||
level.Debug(logger).Log("msg", "Read fake S.M.A.R.T. data from json", "filename", filename)
|
||||
jsonFile, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
logger.Error("Fake S.M.A.R.T. data reading error: %s", err)
|
||||
level.Error(logger).Log("msg", "Fake S.M.A.R.T. data reading error", "err", err)
|
||||
return parseJSON("{}")
|
||||
}
|
||||
return parseJSON(string(jsonFile))
|
||||
}
|
||||
|
||||
// Get json from smartctl and parse it
|
||||
func readSMARTctl(device string) (gjson.Result, bool) {
|
||||
logger.Debug("Collecting S.M.A.R.T. counters, device: %s", device)
|
||||
out, err := exec.Command(options.SMARTctl.SMARTctlLocation, "--json", "--xall", device).Output()
|
||||
func readSMARTctl(logger log.Logger, device string) (gjson.Result, bool) {
|
||||
level.Debug(logger).Log("msg", "Collecting S.M.A.R.T. counters", "device", device)
|
||||
out, err := exec.Command(*smartctlPath, "--json", "--xall", device).Output()
|
||||
if err != nil {
|
||||
logger.Warning("S.M.A.R.T. output reading error: %s", err)
|
||||
level.Warn(logger).Log("msg", "S.M.A.R.T. output reading", "err", err)
|
||||
}
|
||||
json := parseJSON(string(out))
|
||||
rcOk := resultCodeIsOk(json.Get("smartctl.exit_status").Int())
|
||||
jsonOk := jsonIsOk(json)
|
||||
rcOk := resultCodeIsOk(logger, json.Get("smartctl.exit_status").Int())
|
||||
jsonOk := jsonIsOk(logger, json)
|
||||
return json, rcOk && jsonOk
|
||||
}
|
||||
|
||||
func readSMARTctlDevices() gjson.Result {
|
||||
logger.Debug("Collecting devices")
|
||||
out, err := exec.Command(options.SMARTctl.SMARTctlLocation, "--json", "--scan-open").Output()
|
||||
func readSMARTctlDevices(logger log.Logger) gjson.Result {
|
||||
level.Debug(logger).Log("msg", "Collecting devices")
|
||||
out, err := exec.Command(*smartctlPath, "--json", "--scan-open").Output()
|
||||
if err != nil {
|
||||
logger.Warning("S.M.A.R.T. output reading error: %s", err)
|
||||
level.Warn(logger).Log("msg", "S.M.A.R.T. output reading error", "err", err)
|
||||
}
|
||||
return parseJSON(string(out))
|
||||
}
|
||||
|
||||
// Select json source and parse
|
||||
func readData(device string) (gjson.Result, error) {
|
||||
if options.SMARTctl.FakeJSON {
|
||||
return readFakeSMARTctl(device), nil
|
||||
func readData(logger log.Logger, device string) (gjson.Result, error) {
|
||||
if *smartctlFakeData {
|
||||
return readFakeSMARTctl(logger, device), nil
|
||||
}
|
||||
|
||||
if _, err := os.Stat(device); err == nil {
|
||||
cacheValue, cacheOk := jsonCache[device]
|
||||
if !cacheOk || time.Now().After(cacheValue.LastCollect.Add(options.SMARTctl.CollectPeriodDuration)) {
|
||||
json, ok := readSMARTctl(device)
|
||||
if !cacheOk || time.Now().After(cacheValue.LastCollect.Add(*smartctlInterval)) {
|
||||
json, ok := readSMARTctl(logger, device)
|
||||
if ok {
|
||||
jsonCache[device] = JSONCache{JSON: json, LastCollect: time.Now()}
|
||||
return jsonCache[device].JSON, nil
|
||||
|
@ -103,48 +105,48 @@ func readData(device string) (gjson.Result, error) {
|
|||
}
|
||||
|
||||
// Parse smartctl return code
|
||||
func resultCodeIsOk(SMARTCtlResult int64) bool {
|
||||
func resultCodeIsOk(logger log.Logger, SMARTCtlResult int64) bool {
|
||||
result := true
|
||||
if SMARTCtlResult > 0 {
|
||||
b := SMARTCtlResult
|
||||
if (b & 1) != 0 {
|
||||
logger.Error("Command line did not parse.")
|
||||
level.Error(logger).Log("msg", "Command line did not parse.")
|
||||
result = false
|
||||
}
|
||||
if (b & (1 << 1)) != 0 {
|
||||
logger.Error("Device open failed, device did not return an IDENTIFY DEVICE structure, or device is in a low-power mode")
|
||||
level.Error(logger).Log("msg", "Device open failed, device did not return an IDENTIFY DEVICE structure, or device is in a low-power mode")
|
||||
result = false
|
||||
}
|
||||
if (b & (1 << 2)) != 0 {
|
||||
logger.Warning("Some SMART or other ATA command to the disk failed, or there was a checksum error in a SMART data structure")
|
||||
level.Warn(logger).Log("msg", "Some SMART or other ATA command to the disk failed, or there was a checksum error in a SMART data structure")
|
||||
}
|
||||
if (b & (1 << 3)) != 0 {
|
||||
logger.Warning("SMART status check returned 'DISK FAILING'.")
|
||||
level.Warn(logger).Log("msg", "SMART status check returned 'DISK FAILING'.")
|
||||
}
|
||||
if (b & (1 << 4)) != 0 {
|
||||
logger.Warning("We found prefail Attributes <= threshold.")
|
||||
level.Warn(logger).Log("msg", "We found prefail Attributes <= threshold.")
|
||||
}
|
||||
if (b & (1 << 5)) != 0 {
|
||||
logger.Warning("SMART status check returned 'DISK OK' but we found that some (usage or prefail) Attributes have been <= threshold at some time in the past.")
|
||||
level.Warn(logger).Log("msg", "SMART status check returned 'DISK OK' but we found that some (usage or prefail) Attributes have been <= threshold at some time in the past.")
|
||||
}
|
||||
if (b & (1 << 6)) != 0 {
|
||||
logger.Warning("The device error log contains records of errors.")
|
||||
level.Warn(logger).Log("msg", "The device error log contains records of errors.")
|
||||
}
|
||||
if (b & (1 << 7)) != 0 {
|
||||
logger.Warning("The device self-test log contains records of errors. [ATA only] Failed self-tests outdated by a newer successful extended self-test are ignored.")
|
||||
level.Warn(logger).Log("msg", "The device self-test log contains records of errors. [ATA only] Failed self-tests outdated by a newer successful extended self-test are ignored.")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Check json
|
||||
func jsonIsOk(json gjson.Result) bool {
|
||||
func jsonIsOk(logger log.Logger, json gjson.Result) bool {
|
||||
messages := json.Get("smartctl.messages")
|
||||
// logger.Debug(messages.String())
|
||||
if messages.Exists() {
|
||||
for _, message := range messages.Array() {
|
||||
if message.Get("severity").String() == "error" {
|
||||
logger.Error(message.Get("string").String())
|
||||
level.Error(logger).Log("msg", message.Get("string").String())
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
4
scripts/errcheck_excludes.txt
Normal file
4
scripts/errcheck_excludes.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
// Used in HTTP handlers, any error is handled by the server itself.
|
||||
(net/http.ResponseWriter).Write
|
||||
// Never check for logger errors.
|
||||
(github.com/go-kit/log.Logger).Log
|
26
smartctl.go
26
smartctl.go
|
@ -17,6 +17,8 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
@ -33,26 +35,28 @@ type SMARTDevice struct {
|
|||
type SMARTctl struct {
|
||||
ch chan<- prometheus.Metric
|
||||
json gjson.Result
|
||||
logger log.Logger
|
||||
device SMARTDevice
|
||||
}
|
||||
|
||||
// NewSMARTctl is smartctl constructor
|
||||
func NewSMARTctl(json gjson.Result, ch chan<- prometheus.Metric) SMARTctl {
|
||||
smart := SMARTctl{}
|
||||
smart.ch = ch
|
||||
smart.json = json
|
||||
smart.device = SMARTDevice{
|
||||
device: strings.TrimSpace(smart.json.Get("device.name").String()),
|
||||
serial: strings.TrimSpace(smart.json.Get("serial_number").String()),
|
||||
family: strings.TrimSpace(smart.json.Get("model_family").String()),
|
||||
model: strings.TrimSpace(smart.json.Get("model_name").String()),
|
||||
func NewSMARTctl(logger log.Logger, json gjson.Result, ch chan<- prometheus.Metric) SMARTctl {
|
||||
return SMARTctl{
|
||||
ch: ch,
|
||||
json: json,
|
||||
logger: logger,
|
||||
device: SMARTDevice{
|
||||
device: strings.TrimSpace(json.Get("device.name").String()),
|
||||
serial: strings.TrimSpace(json.Get("serial_number").String()),
|
||||
family: strings.TrimSpace(json.Get("model_family").String()),
|
||||
model: strings.TrimSpace(json.Get("model_name").String()),
|
||||
},
|
||||
}
|
||||
return smart
|
||||
}
|
||||
|
||||
// Collect metrics
|
||||
func (smart *SMARTctl) Collect() {
|
||||
logger.Verbose("Collecting metrics from %s: %s, %s", smart.device.device, smart.device.family, smart.device.model)
|
||||
level.Debug(smart.logger).Log("msg", "Collecting metrics from", "device", smart.device.device, "family", smart.device.family, "model", smart.device.model)
|
||||
smart.mineExitStatus()
|
||||
smart.mineDevice()
|
||||
smart.mineCapacity()
|
||||
|
|
Loading…
Reference in a new issue