Produce metrics for XOnBattery, XOffBattery and LastSelftest.

This commit is contained in:
Rolf Schäuble 2017-04-14 14:37:19 +02:00
parent 31b4b80693
commit 2400f7fb14
2 changed files with 89 additions and 1 deletions

View File

@ -5,6 +5,7 @@ import (
"github.com/mdlayher/apcupsd"
"github.com/prometheus/client_golang/prometheus"
"time"
)
var _ StatusSource = &apcupsd.Client{}
@ -27,6 +28,9 @@ type UPSCollector struct {
BatteryTimeLeftSeconds *prometheus.Desc
BatteryTimeOnSeconds *prometheus.Desc
BatteryCumulativeTimeOnSecondsTotal *prometheus.Desc
LastTransferOnBattery *prometheus.Desc
LastTransferOffBattery *prometheus.Desc
LastSelftest *prometheus.Desc
ss StatusSource
}
@ -110,6 +114,27 @@ func NewUPSCollector(ss StatusSource) *UPSCollector {
nil,
),
LastTransferOnBattery: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "", "apcupsd_last_transfer_on_battery"),
"Time of last transfer to battery since apcupsd startup",
labels,
nil,
),
LastTransferOffBattery: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "", "apcupsd_last_transfer_off_battery"),
"Time of last transfer from battery since apcupsd startup",
labels,
nil,
),
LastSelftest: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "", "apcupsd_last_selftest"),
"Time of last selftest since apcupsd startup",
labels,
nil,
),
ss: ss,
}
}
@ -198,9 +223,46 @@ func (c *UPSCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, e
labels...,
)
collectTimestamp(
ch,
c.LastTransferOnBattery,
s.XOnBattery,
labels...
)
collectTimestamp(
ch,
c.LastTransferOffBattery,
s.XOffBattery,
labels...
)
collectTimestamp(
ch,
c.LastSelftest,
s.LastSelftest,
labels...
)
return nil, nil
}
// collectTimestamp collects timestamp metrics.
// Timestamps that are zero (time.IsZero() == true) are ignored, as such a timestamp indicates
// 'information not available', which is best expressed in Prometheus by not having the metric at all.
func collectTimestamp(ch chan<- prometheus.Metric, desc *prometheus.Desc, time time.Time, labelValues ...string) {
if time.IsZero() {
return
}
ch <- prometheus.MustNewConstMetric(
desc,
prometheus.GaugeValue,
float64(time.Unix()),
labelValues...
)
}
// Describe sends the descriptors of each metric over to the provided channel.
// The corresponding metric values are sent separately.
func (c *UPSCollector) Describe(ch chan<- *prometheus.Desc) {

View File

@ -42,6 +42,9 @@ func TestUPSCollector(t *testing.T) {
LineVoltage: 121.1,
LoadPercent: 16.0,
NumberTransfers: 1,
XOnBattery: time.Unix(100001, 0),
XOffBattery: time.Unix(100002, 0),
LastSelftest: time.Unix(100003, 0),
},
},
matches: []*regexp.Regexp{
@ -55,6 +58,9 @@ func TestUPSCollector(t *testing.T) {
regexp.MustCompile(`apcupsd_line_nominal_volts{hostname="a",model="b",ups_name="c"} 120`),
regexp.MustCompile(`apcupsd_line_volts{hostname="a",model="b",ups_name="c"} 121.1`),
regexp.MustCompile(`apcupsd_ups_load_percent{hostname="a",model="b",ups_name="c"} 16`),
regexp.MustCompile(`apcupsd_last_transfer_on_battery{hostname="a",model="b",ups_name="c"} 100001`),
regexp.MustCompile(`apcupsd_last_transfer_off_battery{hostname="a",model="b",ups_name="c"} 100002`),
regexp.MustCompile(`apcupsd_last_selftest{hostname="a",model="b",ups_name="c"} 100003`),
},
},
}
@ -68,7 +74,7 @@ func TestUPSCollector(t *testing.T) {
t.Run(name, func(t *testing.T) {
if !m.Match(out) {
t.Fatal("\toutput failed to match regex")
t.Fatalf("\toutput failed to match regex (regexp: %v)", m)
}
})
}
@ -76,6 +82,26 @@ func TestUPSCollector(t *testing.T) {
}
}
// TestZeroTimesAreIgnored tests that times with a zero value (time.IsZero() == true)
// are not collected.
func TestZeroTimesAreIgnored(t *testing.T) {
ss := &testStatusSource{
s: &apcupsd.Status{
XOnBattery: time.Unix(123456, 0),
XOffBattery: time.Time{},
},
}
out := testCollector(t, NewUPSCollector(ss))
// Test that in general timestamps are collected.
if !regexp.MustCompile(`apcupsd_last_transfer_on_battery.* 123456`).Match(out) {
t.Error("non-zero timestamp is not reported properly")
}
// Test that zero timestamps, however, are ignored.
if regexp.MustCompile(`apcupsd_last_transfer_off_battery`).Match(out) {
t.Error("Zero time is reported")
}
}
func metricName(t *testing.T, metric string) string {
ss := strings.Split(metric, " ")
if len(ss) != 2 {