From 774dee601257b79b5a081ec80a0fb1fc84ae4a25 Mon Sep 17 00:00:00 2001 From: Octavian Cerna Date: Sun, 26 Jul 2020 21:08:03 +0300 Subject: [PATCH 01/12] Convert to Go module. --- go.mod | 9 +++++ go.sum | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7c9be18 --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module github.com/tavyc/smartctl_exporter + +go 1.14 + +require ( + github.com/prometheus/client_golang v1.7.1 + github.com/tidwall/gjson v1.6.0 + gopkg.in/yaml.v2 v2.3.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..881c698 --- /dev/null +++ b/go.sum @@ -0,0 +1,118 @@ +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +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/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= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/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/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= +github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +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 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +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.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= +github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +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-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From 81e49a31c391689e762e68125c5f51bb0cc0043e Mon Sep 17 00:00:00 2001 From: Octavian Cerna Date: Sun, 26 Jul 2020 21:10:56 +0300 Subject: [PATCH 02/12] Adjust the Makefile for the conversion to a Go module. --- Makefile | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index fb57953..1a3855b 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,24 @@ -GOPATH=$(shell pwd)/vendor:$(shell pwd) -GOBIN=$(shell pwd)/bin -GOFILES=$(wildcard *.go) -GONAME=$(shell basename "$(PWD)") - build: get - @echo "Building $(GOFILES) to ./bin" - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build -v -o bin/$(GONAME) $(GOFILES) + @go build -v get: - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go get -v . + @go get -v install: - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go install $(GOFILES) + @go install run: build - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go run $(GOFILES) --config=$(shell pwd)/smartctl_exporter.yaml --debug --verbose + @go run . --config=$(shell pwd)/smartctl_exporter.yaml --debug --verbose run-sudo: build - sudo bin/$(GONAME) --config=$(shell pwd)/smartctl_exporter.yaml --debug --verbose + sudo smartctl_exporter --config=$(shell pwd)/smartctl_exporter.yaml --debug --verbose clear: @clear clean: @echo "Cleaning" - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go clean + @go clean example: @echo "# Example output" > EXAMPLE.md From 9e10465744108b69308add786decfb1b4c82601c Mon Sep 17 00:00:00 2001 From: Octavian Cerna Date: Sun, 26 Jul 2020 22:31:04 +0300 Subject: [PATCH 03/12] Add a new metric smartctl_device_status for the SMART health status. --- metrics.go | 11 +++++++++++ smartctl.go | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/metrics.go b/metrics.go index 1ee8708..3b773eb 100644 --- a/metrics.go +++ b/metrics.go @@ -166,4 +166,15 @@ var ( }, nil, ) + metricDeviceStatus = prometheus.NewDesc( + "smartctl_device_status", + "Device status", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) ) diff --git a/smartctl.go b/smartctl.go index 5a5c073..0f800c7 100644 --- a/smartctl.go +++ b/smartctl.go @@ -50,6 +50,7 @@ func (smart *SMARTctl) Collect() { smart.mineTemperatures() smart.minePowerCycleCount() smart.mineDeviceStatistics() + smart.mineDeviceStatus() } func (smart *SMARTctl) mineExitStatus() { @@ -266,3 +267,16 @@ func (smart *SMARTctl) mineLongFlags(json gjson.Result, flags []string) string { } return strings.Join(result, ",") } + +func (smart *SMARTctl) mineDeviceStatus() { + status := smart.json.Get("smart_status") + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceStatus, + prometheus.GaugeValue, + status.Get("passed").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} From 3feff84fbbb5c6ae57d6097fdd6f078ef73ae747 Mon Sep 17 00:00:00 2001 From: Octavian Cerna Date: Sun, 26 Jul 2020 22:54:54 +0300 Subject: [PATCH 04/12] Add a new metric smartctl_device_state for the device state from ATA SCT. --- metrics.go | 11 +++++++++++ smartctl.go | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/metrics.go b/metrics.go index 3b773eb..a0a2f37 100644 --- a/metrics.go +++ b/metrics.go @@ -151,6 +151,17 @@ var ( }, nil, ) + metricDeviceState = prometheus.NewDesc( + "smartctl_device_state", + "Device state (0=active, 1=standby, 2=sleep, 3=dst, 4=offline, 5=sct)", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) metricDeviceStatistics = prometheus.NewDesc( "smartctl_device_statistics", "Device statistics", diff --git a/smartctl.go b/smartctl.go index 0f800c7..3a0a409 100644 --- a/smartctl.go +++ b/smartctl.go @@ -49,6 +49,7 @@ func (smart *SMARTctl) Collect() { smart.mineRotationRate() smart.mineTemperatures() smart.minePowerCycleCount() + smart.mineDeviceSCTStatus() smart.mineDeviceStatistics() smart.mineDeviceStatus() } @@ -231,6 +232,21 @@ func (smart *SMARTctl) minePowerCycleCount() { ) } +func (smart *SMARTctl) mineDeviceSCTStatus() { + status := smart.json.Get("ata_sct_status") + if status.Exists() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceState, + prometheus.GaugeValue, + status.Get("device_state").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) + } +} + func (smart *SMARTctl) mineDeviceStatistics() { for _, page := range smart.json.Get("ata_device_statistics.pages").Array() { table := strings.TrimSpace(page.Get("name").String()) From e8d95208d7df55959facb0f892a4a00c94243844 Mon Sep 17 00:00:00 2001 From: Octavian Cerna Date: Sun, 26 Jul 2020 23:35:22 +0300 Subject: [PATCH 05/12] Report SATA PHY stats to smartctl_device_statistics. --- smartctl.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/smartctl.go b/smartctl.go index 3a0a409..5d0c977 100644 --- a/smartctl.go +++ b/smartctl.go @@ -271,6 +271,22 @@ func (smart *SMARTctl) mineDeviceStatistics() { ) } } + + for _, statistic := range smart.json.Get("sata_phy_event_counters.table").Array() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceStatistics, + prometheus.GaugeValue, + statistic.Get("value").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + "SATA PHY Event Counters", + strings.TrimSpace(statistic.Get("name").String()), + "", + "", + ) + } } func (smart *SMARTctl) mineLongFlags(json gjson.Result, flags []string) string { From 3e177068398fa3aa41484ddc7e0b0fc50fdb9eec Mon Sep 17 00:00:00 2001 From: Octavian Cerna Date: Sun, 26 Jul 2020 23:48:49 +0300 Subject: [PATCH 06/12] Add a new metric smartctl_device_error_log_count for the SMART error log counts. --- metrics.go | 12 ++++++++++++ smartctl.go | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/metrics.go b/metrics.go index a0a2f37..f08298b 100644 --- a/metrics.go +++ b/metrics.go @@ -188,4 +188,16 @@ var ( }, nil, ) + metricDeviceErrorLogCount = prometheus.NewDesc( + "smartctl_device_error_log_count", + "Device SMART error log count", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + "error_log_type", + }, + nil, + ) ) diff --git a/smartctl.go b/smartctl.go index 5d0c977..0958cf7 100644 --- a/smartctl.go +++ b/smartctl.go @@ -52,6 +52,7 @@ func (smart *SMARTctl) Collect() { smart.mineDeviceSCTStatus() smart.mineDeviceStatistics() smart.mineDeviceStatus() + smart.mineDeviceErrorLog() } func (smart *SMARTctl) mineExitStatus() { @@ -312,3 +313,18 @@ func (smart *SMARTctl) mineDeviceStatus() { smart.device.serial, ) } + +func (smart *SMARTctl) mineDeviceErrorLog() { + for logType, status := range smart.json.Get("ata_smart_error_log").Map() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceErrorLogCount, + prometheus.GaugeValue, + status.Get("count").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + logType, + ) + } +} From 53399a5e7335e40f13e0cd31ca38618b1d41b479 Mon Sep 17 00:00:00 2001 From: Octavian Cerna Date: Mon, 27 Jul 2020 00:16:08 +0300 Subject: [PATCH 07/12] Add a new metrics smartctl_device_self_test_log_count and smartctl_device_self_test_log_error_count for the device SMART Self-Test Logs. --- metrics.go | 24 ++++++++++++++++++++++++ smartctl.go | 26 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/metrics.go b/metrics.go index f08298b..fd694b7 100644 --- a/metrics.go +++ b/metrics.go @@ -200,4 +200,28 @@ var ( }, nil, ) + metricDeviceSelfTestLogCount = prometheus.NewDesc( + "smartctl_device_self_test_log_count", + "Device SMART self test log count", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + "self_test_log_type", + }, + nil, + ) + metricDeviceSelfTestLogErrorCount = prometheus.NewDesc( + "smartctl_device_self_test_log_error_count", + "Device SMART self test log error count", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + "self_test_log_type", + }, + nil, + ) ) diff --git a/smartctl.go b/smartctl.go index 0958cf7..d8aab2d 100644 --- a/smartctl.go +++ b/smartctl.go @@ -53,6 +53,7 @@ func (smart *SMARTctl) Collect() { smart.mineDeviceStatistics() smart.mineDeviceStatus() smart.mineDeviceErrorLog() + smart.mineDeviceSelfTestLog() } func (smart *SMARTctl) mineExitStatus() { @@ -328,3 +329,28 @@ func (smart *SMARTctl) mineDeviceErrorLog() { ) } } + +func (smart *SMARTctl) mineDeviceSelfTestLog() { + for logType, status := range smart.json.Get("ata_smart_self_test_log").Map() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceSelfTestLogCount, + prometheus.GaugeValue, + status.Get("count").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + logType, + ) + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceSelfTestLogErrorCount, + prometheus.GaugeValue, + status.Get("error_count_total").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + logType, + ) + } +} From 9e58dd6fd2430b03962b19b03d482169c5d6bf22 Mon Sep 17 00:00:00 2001 From: Octavian Cerna Date: Mon, 27 Jul 2020 00:37:43 +0300 Subject: [PATCH 08/12] Add a new metric smartctl_device_erc_seconds for reporting the device Error Recovery Control (TLER) setting. --- metrics.go | 12 ++++++++++++ smartctl.go | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/metrics.go b/metrics.go index fd694b7..5edbcc9 100644 --- a/metrics.go +++ b/metrics.go @@ -224,4 +224,16 @@ var ( }, nil, ) + metricDeviceERCSeconds = prometheus.NewDesc( + "smartctl_device_erc_seconds", + "Device SMART Error Recovery Control Seconds", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + "op_type", + }, + nil, + ) ) diff --git a/smartctl.go b/smartctl.go index d8aab2d..96eee23 100644 --- a/smartctl.go +++ b/smartctl.go @@ -54,6 +54,7 @@ func (smart *SMARTctl) Collect() { smart.mineDeviceStatus() smart.mineDeviceErrorLog() smart.mineDeviceSelfTestLog() + smart.mineDeviceERC() } func (smart *SMARTctl) mineExitStatus() { @@ -354,3 +355,18 @@ func (smart *SMARTctl) mineDeviceSelfTestLog() { ) } } + +func (smart *SMARTctl) mineDeviceERC() { + for ercType, status := range smart.json.Get("ata_sct_erc").Map() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceERCSeconds, + prometheus.GaugeValue, + status.Get("deciseconds").Float()/10.0, + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ercType, + ) + } +} From 6e30737bc343b35279bba9fa41080eaa9826d3ab Mon Sep 17 00:00:00 2001 From: Octavian Cerna Date: Mon, 27 Jul 2020 00:40:18 +0300 Subject: [PATCH 09/12] mineDeviceStatistics: Flag the SATA PHY stats as valid. --- smartctl.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smartctl.go b/smartctl.go index 96eee23..62d026f 100644 --- a/smartctl.go +++ b/smartctl.go @@ -286,8 +286,8 @@ func (smart *SMARTctl) mineDeviceStatistics() { smart.device.serial, "SATA PHY Event Counters", strings.TrimSpace(statistic.Get("name").String()), - "", - "", + "V---", + "valid", ) } } From 1b15cbbec2d89ad2d64aa68ad507968503be0ccd Mon Sep 17 00:00:00 2001 From: Christian Pedersen Date: Fri, 2 Oct 2020 13:30:09 +0200 Subject: [PATCH 10/12] Add NVMe metrics --- .gitignore | 2 + Makefile | 18 +++---- go.mod | 9 ++++ go.sum | 118 ++++++++++++++++++++++++++++++++++++++++ metrics.go | 99 ++++++++++++++++++++++++++++++++++ smartctl.go | 120 +++++++++++++++++++++++++++++++++++++++++ smartctl_exporter.yaml | 12 ++--- 7 files changed, 359 insertions(+), 19 deletions(-) create mode 100644 go.mod create mode 100644 go.sum mode change 100644 => 100755 smartctl_exporter.yaml diff --git a/.gitignore b/.gitignore index 4e0aca0..d854cb7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ bin *.json Manifest +.idea +smartctl_exporter diff --git a/Makefile b/Makefile index fb57953..509a469 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,24 @@ -GOPATH=$(shell pwd)/vendor:$(shell pwd) -GOBIN=$(shell pwd)/bin -GOFILES=$(wildcard *.go) -GONAME=$(shell basename "$(PWD)") - build: get - @echo "Building $(GOFILES) to ./bin" - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build -v -o bin/$(GONAME) $(GOFILES) + @go build -v get: - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go get -v . + @go get -v install: - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go install $(GOFILES) + @go install run: build - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go run $(GOFILES) --config=$(shell pwd)/smartctl_exporter.yaml --debug --verbose + @go run . --config=$(shell pwd)/smartctl_exporter.yaml --debug --verbose run-sudo: build - sudo bin/$(GONAME) --config=$(shell pwd)/smartctl_exporter.yaml --debug --verbose + sudo ./smartctl_exporter --config=$(shell pwd)/smartctl_exporter.yaml --debug --verbose clear: @clear clean: @echo "Cleaning" - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go clean + @go clean example: @echo "# Example output" > EXAMPLE.md diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..706a203 --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module github.com/tavyc/smartctl_exporter + +go 1.14 + +require ( + github.com/prometheus/client_golang v1.7.1 + github.com/tidwall/gjson v1.6.0 + gopkg.in/yaml.v2 v2.3.0 +) \ No newline at end of file diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..881c698 --- /dev/null +++ b/go.sum @@ -0,0 +1,118 @@ +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +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/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= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/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/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= +github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +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 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +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.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= +github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +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-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/metrics.go b/metrics.go index 1ee8708..8040a39 100644 --- a/metrics.go +++ b/metrics.go @@ -140,6 +140,105 @@ var ( }, nil, ) + metricDevicePercentageUsed = prometheus.NewDesc( + "smartctl_device_percentage_used", + "Device write percentage used", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricDeviceAvailableSpare = prometheus.NewDesc( + "smartctl_device_available_spare", + "Normalized percentage (0 to 100%) of the remaining spare capacity available", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricDeviceAvailableSpareThreshold = prometheus.NewDesc( + "smartctl_device_available_spare_threshold", + "When the Available Spare falls below the threshold indicated in this field, an asynchronous event completion may occur. The value is indicated as a normalized percentage (0 to 100%)", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricDeviceCriticalWarning = prometheus.NewDesc( + "smartctl_device_critical_warning", + "This field indicates critical warnings for the state of the controller", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricDeviceMediaErrors = prometheus.NewDesc( + "smartctl_device_media_errors", + "Contains the number of occurrences where the controller detected an unrecovered data integrity error. Errors such as uncorrectable ECC, CRC checksum failure, or LBA tag mismatch are included in this field", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricDeviceNumErrLogEntries = prometheus.NewDesc( + "smartctl_device_num_err_log_entries", + "Contains the number of Error Information log entries over the life of the controller", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricDeviceDataUnitsRead = prometheus.NewDesc( + "smartctl_device_data_units_read", + "", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricDeviceDataUnitsWritten = prometheus.NewDesc( + "smartctl_device_data_units_written", + "", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricDeviceSmartStatus = prometheus.NewDesc( + "smartctl_device_smart_status", + "General smart status", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) metricDeviceExitStatus = prometheus.NewDesc( "smartctl_device_smartctl_exit_status", "Exit status of smartctl on device", diff --git a/smartctl.go b/smartctl.go index 5a5c073..5708557 100644 --- a/smartctl.go +++ b/smartctl.go @@ -50,6 +50,16 @@ func (smart *SMARTctl) Collect() { smart.mineTemperatures() smart.minePowerCycleCount() smart.mineDeviceStatistics() + smart.minePercentageUsed() + smart.mineAvailableSpare() + smart.mineAvailableSpareThreshold() + smart.mineCriticalWarning() + smart.mineMediaErrors() + smart.mineNumErrLogEntries() + smart.mineDataUnitsRead() + smart.mineDataUnitsWritten() + smart.mineSmartStatus() + } func (smart *SMARTctl) mineExitStatus() { @@ -230,6 +240,116 @@ func (smart *SMARTctl) minePowerCycleCount() { ) } +func (smart *SMARTctl) minePercentageUsed() { + smart.ch <- prometheus.MustNewConstMetric( + metricDevicePercentageUsed, + prometheus.CounterValue, + smart.json.Get("nvme_smart_health_information_log.percentage_used").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} + +func (smart *SMARTctl) mineAvailableSpare() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceAvailableSpare, + prometheus.CounterValue, + smart.json.Get("nvme_smart_health_information_log.available_spare").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} + +func (smart *SMARTctl) mineAvailableSpareThreshold() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceAvailableSpareThreshold, + prometheus.CounterValue, + smart.json.Get("nvme_smart_health_information_log.available_spare_threshold").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} + +func (smart *SMARTctl) mineCriticalWarning() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceCriticalWarning, + prometheus.CounterValue, + smart.json.Get("nvme_smart_health_information_log.critical_warning").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} + +func (smart *SMARTctl) mineMediaErrors() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceMediaErrors, + prometheus.CounterValue, + smart.json.Get("nvme_smart_health_information_log.media_errors").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} + +func (smart *SMARTctl) mineNumErrLogEntries() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceNumErrLogEntries, + prometheus.CounterValue, + smart.json.Get("nvme_smart_health_information_log.num_err_log_entries").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} + +func (smart *SMARTctl) mineDataUnitsRead() { + blockSize := smart.json.Get("logical_block_size").Float() + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceDataUnitsRead, + prometheus.CounterValue, + smart.json.Get("nvme_smart_health_information_log.data_units_read").Float() * blockSize, + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} + +func (smart *SMARTctl) mineDataUnitsWritten() { + blockSize := smart.json.Get("logical_block_size").Float() + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceDataUnitsWritten, + prometheus.CounterValue, + smart.json.Get("nvme_smart_health_information_log.data_units_written").Float() * blockSize, + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} + +func (smart *SMARTctl) mineSmartStatus() { + smart.ch <- prometheus.MustNewConstMetric( + metricDeviceSmartStatus, + prometheus.GaugeValue, + smart.json.Get("smart_status.passed").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} + func (smart *SMARTctl) mineDeviceStatistics() { for _, page := range smart.json.Get("ata_device_statistics.pages").Array() { table := strings.TrimSpace(page.Get("name").String()) diff --git a/smartctl_exporter.yaml b/smartctl_exporter.yaml old mode 100644 new mode 100755 index 7740083..02a236d --- a/smartctl_exporter.yaml +++ b/smartctl_exporter.yaml @@ -1,13 +1,11 @@ smartctl_exporter: - bind_to: "[::1]:9633" + bind_to: "0.0.0.0:9633" url_path: "/metrics" fake_json: no smartctl_location: /usr/sbin/smartctl collect_not_more_than_period: 20s devices: - - /dev/sda - - /dev/sdb - - /dev/sdc - - /dev/sdd - - /dev/sde - - /dev/sdf + - /dev/nvme0 + - /dev/nvme1 + - /dev/nvme2 + - /dev/nvme3 From 315d1538aad55a5382253e6d49e9c52c321fb355 Mon Sep 17 00:00:00 2001 From: Christian Pedersen Date: Fri, 2 Oct 2020 15:14:40 +0200 Subject: [PATCH 11/12] Calculate bytes read/written --- metrics.go | 8 ++++---- smartctl.go | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/metrics.go b/metrics.go index 8040a39..49fcbbb 100644 --- a/metrics.go +++ b/metrics.go @@ -206,8 +206,8 @@ var ( }, nil, ) - metricDeviceDataUnitsRead = prometheus.NewDesc( - "smartctl_device_data_units_read", + metricDeviceBytesRead = prometheus.NewDesc( + "smartctl_device_bytes_read", "", []string{ "device", @@ -217,8 +217,8 @@ var ( }, nil, ) - metricDeviceDataUnitsWritten = prometheus.NewDesc( - "smartctl_device_data_units_written", + metricDeviceBytesWritten = prometheus.NewDesc( + "smartctl_device_bytes_written", "", []string{ "device", diff --git a/smartctl.go b/smartctl.go index 5708557..eb20fb5 100644 --- a/smartctl.go +++ b/smartctl.go @@ -56,8 +56,8 @@ func (smart *SMARTctl) Collect() { smart.mineCriticalWarning() smart.mineMediaErrors() smart.mineNumErrLogEntries() - smart.mineDataUnitsRead() - smart.mineDataUnitsWritten() + smart.mineBytesRead() + smart.mineBytesWritten() smart.mineSmartStatus() } @@ -312,10 +312,10 @@ func (smart *SMARTctl) mineNumErrLogEntries() { ) } -func (smart *SMARTctl) mineDataUnitsRead() { - blockSize := smart.json.Get("logical_block_size").Float() +func (smart *SMARTctl) mineBytesRead() { + blockSize := smart.json.Get("logical_block_size").Float() * 1024 smart.ch <- prometheus.MustNewConstMetric( - metricDeviceDataUnitsRead, + metricDeviceBytesRead, prometheus.CounterValue, smart.json.Get("nvme_smart_health_information_log.data_units_read").Float() * blockSize, smart.device.device, @@ -325,10 +325,10 @@ func (smart *SMARTctl) mineDataUnitsRead() { ) } -func (smart *SMARTctl) mineDataUnitsWritten() { - blockSize := smart.json.Get("logical_block_size").Float() +func (smart *SMARTctl) mineBytesWritten() { + blockSize := smart.json.Get("logical_block_size").Float() * 1024 smart.ch <- prometheus.MustNewConstMetric( - metricDeviceDataUnitsWritten, + metricDeviceBytesWritten, prometheus.CounterValue, smart.json.Get("nvme_smart_health_information_log.data_units_written").Float() * blockSize, smart.device.device, From 593ca96a991aadaa0722bb8ed98455431650af37 Mon Sep 17 00:00:00 2001 From: Christian Pedersen Date: Tue, 6 Oct 2020 13:05:00 +0200 Subject: [PATCH 12/12] Automatically load the available devices --- main.go | 11 +++++++++++ readjson.go | 9 +++++++++ smartctl_exporter.yaml | 10 +++++----- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 4c769b4..9cea81c 100644 --- a/main.go +++ b/main.go @@ -36,6 +36,17 @@ func (i SMARTctlManagerCollector) Collect(ch chan<- prometheus.Metric) { 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) + } + } } func main() { diff --git a/readjson.go b/readjson.go index 39141e1..50bfdc1 100644 --- a/readjson.go +++ b/readjson.go @@ -55,6 +55,15 @@ func readSMARTctl(device string) gjson.Result { return parseJSON(string(out)) } +func readSMARTctlDevices() gjson.Result { + logger.Debug("Collecting devices") + out, err := exec.Command(options.SMARTctl.SMARTctlLocation, "--json", "--scan-open").Output() + if err != nil { + logger.Warning("S.M.A.R.T. output reading error: %s", err) + } + return parseJSON(string(out)) +} + // Select json source and parse func readData(device string) gjson.Result { if options.SMARTctl.FakeJSON { diff --git a/smartctl_exporter.yaml b/smartctl_exporter.yaml index 02a236d..f0cbf2f 100755 --- a/smartctl_exporter.yaml +++ b/smartctl_exporter.yaml @@ -4,8 +4,8 @@ smartctl_exporter: fake_json: no smartctl_location: /usr/sbin/smartctl collect_not_more_than_period: 20s - devices: - - /dev/nvme0 - - /dev/nvme1 - - /dev/nvme2 - - /dev/nvme3 +# devices: +# - /dev/nvme0 +# - /dev/nvme1 +# - /dev/nvme2 +# - /dev/nvme3