extend self-test log processing

Signed-off-by: Aritas1 <mail@aritas.de>
This commit is contained in:
Aritas1 2023-08-20 16:56:09 +02:00
parent 75c76b363f
commit 9e14bc2ef2
3 changed files with 58 additions and 1 deletions

View File

@ -242,6 +242,17 @@ var (
}, },
nil, nil,
) )
metricDeviceSelfTest = prometheus.NewDesc(
"smartctl_device_self_test_log_seconds",
"Device SMART self test log execution lifetime seconds",
[]string{
"device",
"self_test_log_type",
"self_test_passed",
},
nil,
)
metricDeviceSelfTestLogCount = prometheus.NewDesc( metricDeviceSelfTestLogCount = prometheus.NewDesc(
"smartctl_device_self_test_log_count", "smartctl_device_self_test_log_count",
"Device SMART self test log count", "Device SMART self test log count",

View File

@ -64,7 +64,7 @@ func readFakeSMARTctl(logger log.Logger, device string) gjson.Result {
// Get json from smartctl and parse it // Get json from smartctl and parse it
func readSMARTctl(logger log.Logger, device string) (gjson.Result, bool) { func readSMARTctl(logger log.Logger, device string) (gjson.Result, bool) {
level.Debug(logger).Log("msg", "Collecting S.M.A.R.T. counters", "device", device) level.Debug(logger).Log("msg", "Collecting S.M.A.R.T. counters", "device", device)
out, err := exec.Command(*smartctlPath, "--json", "--info", "--health", "--attributes", "--tolerance=verypermissive", "--nocheck=standby", "--format=brief", "--log=error", device).Output() out, err := exec.Command(*smartctlPath, "--json", "--info", "--health", "--attributes", "--tolerance=verypermissive", "--nocheck=standby", "--format=brief", "--log=error", "--log=selftest", device).Output()
if err != nil { if err != nil {
level.Warn(logger).Log("msg", "S.M.A.R.T. output reading", "err", err, "device", device) level.Warn(logger).Log("msg", "S.M.A.R.T. output reading", "err", err, "device", device)
} }

View File

@ -15,6 +15,7 @@ package main
import ( import (
"fmt" "fmt"
"strconv"
"strings" "strings"
"github.com/go-kit/log" "github.com/go-kit/log"
@ -69,6 +70,7 @@ func (smart *SMARTctl) Collect() {
smart.mineDeviceSCTStatus() smart.mineDeviceSCTStatus()
smart.mineDeviceStatistics() smart.mineDeviceStatistics()
smart.mineDeviceErrorLog() smart.mineDeviceErrorLog()
smart.mineDeviceSelfTest()
smart.mineDeviceSelfTestLog() smart.mineDeviceSelfTestLog()
smart.mineDeviceERC() smart.mineDeviceERC()
smart.minePercentageUsed() smart.minePercentageUsed()
@ -399,6 +401,50 @@ func (smart *SMARTctl) mineDeviceErrorLog() {
} }
} }
func (smart *SMARTctl) mineDeviceSelfTest() {
validTypes := map[int]string{
255: "vendor",
129: "short_captive",
2: "long",
1: "short",
}
// assume the table will always be in descending order
processedTypes := make(map[string]bool)
for _, logEntry := range smart.json.Get("ata_smart_self_test_log.standard.table").Array() {
testType := int(logEntry.Get("type.value").Int())
testTime := float64(logEntry.Get("lifetime_hours").Int())
testRunningIndicator := int(logEntry.Get("status.value").Int())
testStatus := strconv.FormatBool(logEntry.Get("status.passed").Bool())
// stick with seconds
testTime = testTime * 60 * 60
// skip running tests
if testRunningIndicator != 0 {
continue
}
logTestType, exists := validTypes[testType]
if !exists {
logTestType = "unknown"
}
if !processedTypes[logTestType] {
smart.ch <- prometheus.MustNewConstMetric(
metricDeviceSelfTest,
prometheus.GaugeValue,
testTime,
smart.device.device,
logTestType,
testStatus,
)
processedTypes[logTestType] = true
}
}
}
func (smart *SMARTctl) mineDeviceSelfTestLog() { func (smart *SMARTctl) mineDeviceSelfTestLog() {
for logType, status := range smart.json.Get("ata_smart_self_test_log").Map() { for logType, status := range smart.json.Get("ata_smart_self_test_log").Map() {
smart.ch <- prometheus.MustNewConstMetric( smart.ch <- prometheus.MustNewConstMetric(