drive-health-metrics/exporter.go
James Coleman ddafa90a02
Some checks failed
Go package / build (push) Has been cancelled
first commit
2026-06-22 17:16:34 -05:00

83 lines
2.5 KiB
Go

package main
import (
"github.com/prometheus/client_golang/prometheus"
)
// DriveExporter is a Prometheus collector that, on each scrape, discovers the
// host's drives and emits their numeric health columns as gauges. The label set
// (the schema's string columns) is attached to every metric so the Prometheus
// and InfluxDB outputs describe each drive identically.
type DriveExporter struct {
descs map[string]*prometheus.Desc
labels []column // String columns carried as labels.
gauges []column // Numeric columns emitted as gauges.
// collect discovers the drives; a field so tests can inject a fixed set
// without touching real hardware.
collect func() ([]*Drive, int64)
}
// NewDriveExporter builds the collector with one gauge descriptor per numeric
// column, labelled with the schema's string columns.
func NewDriveExporter() *DriveExporter {
labels, gauges := labelColumns(), gaugeColumns()
labelNames := make([]string, len(labels))
for i, c := range labels {
labelNames[i] = c.name
}
descs := make(map[string]*prometheus.Desc, len(gauges))
for _, c := range gauges {
descs[c.name] = prometheus.NewDesc(namespace+"_"+c.name, "drive health metric: "+c.name, labelNames, nil)
}
return &DriveExporter{descs: descs, labels: labels, gauges: gauges, collect: collect}
}
// Reload is a no-op; the exporter holds no configurable state.
func (e *DriveExporter) Reload() {}
// Describe sends every metric descriptor to the channel.
func (e *DriveExporter) Describe(ch chan<- *prometheus.Desc) {
for _, d := range e.descs {
ch <- d
}
}
// Collect discovers the drives and emits a gauge per numeric column, with the
// shared identity label set.
func (e *DriveExporter) Collect(ch chan<- prometheus.Metric) {
drives, _ := e.collect()
for _, d := range drives {
labelValues := make([]string, len(e.labels))
for i, c := range e.labels {
labelValues[i] = format(c.raw(d))
}
for _, c := range e.gauges {
val, ok := gaugeValue(c, d)
if !ok {
continue
}
ch <- prometheus.MustNewConstMetric(e.descs[c.name], prometheus.GaugeValue, val, labelValues...)
}
}
}
// gaugeValue converts a numeric column's value to a float for Prometheus,
// reporting ok=false when the value is unknown.
func gaugeValue(c column, d *Drive) (float64, bool) {
r := c.raw(d)
switch t := r.(type) {
case nil:
return 0, false
case int:
return float64(t), true
case float64:
return t, true
case bool:
if t {
return 1, true
}
return 0, true
default:
return 0, false
}
}