diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..70a5312 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# Build /go/bin/smartctl_exporter +FROM quay.io/prometheus/golang-builder:1.13-base AS builder +ADD . /go/src/github.com/Sheridan/smartctl_exporter/ +RUN cd /go/src/github.com/Sheridan/smartctl_exporter && make + +# Container image +FROM ubuntu:18.04 +WORKDIR / +RUN apt-get update \ + && apt-get install smartmontools/bionic-backports -y --no-install-recommends \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /go/src/github.com/Sheridan/smartctl_exporter/bin/smartctl_exporter /bin/smartctl_exporter +COPY docker-entrypoint.sh / +COPY smartctl_exporter.yaml / +RUN chmod +x /docker-entrypoint.sh +EXPOSE 9633 +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..b6b38d0 --- /dev/null +++ b/config.yaml @@ -0,0 +1,8 @@ +smartctl_exporter: + bind_to: "[0.0.0.0]:9633" + url_path: "/metrics" + fake_json: no + smartctl_location: /usr/sbin/smartctl + collect_not_more_than_period: 120s + devices: + - /dev/nvme0 diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..951db3e --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +DISKS="$(lsblk -l|egrep -oe '(sd[a-z]|nvme[0-9])'|sed -e 's/^/ - \/dev\//'| uniq)" +echo "$DISKS" >> smartctl_exporter.yaml + +/bin/smartctl_exporter -config=/smartctl_exporter.yaml diff --git a/metrics.go b/metrics.go index 1ee8708..78701e9 100644 --- a/metrics.go +++ b/metrics.go @@ -166,4 +166,48 @@ var ( }, nil, ) + metricCriticalWarning = prometheus.NewDesc( + "critical_warning", + "Critical warning counter", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricAvailableSpare = prometheus.NewDesc( + "available_spare", + "Available spare", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricMediaErrors = prometheus.NewDesc( + "media_errors", + "Media errors counter", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) + metricSmartStatus = prometheus.NewDesc( + "smart_status", + "Smart status", + []string{ + "device", + "model_family", + "model_name", + "serial_number", + }, + nil, + ) ) diff --git a/smartctl.go b/smartctl.go index 5a5c073..50af602 100644 --- a/smartctl.go +++ b/smartctl.go @@ -50,6 +50,8 @@ func (smart *SMARTctl) Collect() { smart.mineTemperatures() smart.minePowerCycleCount() smart.mineDeviceStatistics() + smart.mineNvmeSmartHealthInformationLog() + smart.mineNvmeSmartStatus() } func (smart *SMARTctl) mineExitStatus() { @@ -266,3 +268,47 @@ func (smart *SMARTctl) mineLongFlags(json gjson.Result, flags []string) string { } return strings.Join(result, ",") } + +func (smart *SMARTctl) mineNvmeSmartHealthInformationLog() { + iHealth := smart.json.Get("nvme_smart_health_information_log") + smart.ch <- prometheus.MustNewConstMetric( + metricCriticalWarning, + prometheus.GaugeValue, + iHealth.Get("critical_warning").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) + smart.ch <- prometheus.MustNewConstMetric( + metricAvailableSpare, + prometheus.GaugeValue, + iHealth.Get("available_spare").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) + smart.ch <- prometheus.MustNewConstMetric( + metricMediaErrors, + prometheus.GaugeValue, + iHealth.Get("media_errors").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +} + +func (smart *SMARTctl) mineNvmeSmartStatus() { + iStatus := smart.json.Get("smart_status") + smart.ch <- prometheus.MustNewConstMetric( + metricSmartStatus, + prometheus.GaugeValue, + iStatus.Get("passed").Float(), + smart.device.device, + smart.device.family, + smart.device.model, + smart.device.serial, + ) +}