From 5698d182a2c09bdb108dbfd64eef7a5f690c92b8 Mon Sep 17 00:00:00 2001 From: Richard Mitchell <richard.j.mitchell@gmail.com> Date: Mon, 24 Sep 2018 21:39:08 +0100 Subject: [PATCH] Add bridge restart metric --- README.md | 5 +++++ sensors.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f62dbf3..c50e22b 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,11 @@ Some sensor type values you might find useful: * `ZLLPresence`: the presence sensor in the Hue motion sensor * `ZLLLightLevel`: the light level sensor in the Hue motion sensor +## General metrics + +* `hue_group_scrapes_failed`, `hue_light_scrapes_failed`, `hue_sensor_scrapes_failed`: count of failures when trying to scrape from the Hue API. +* `hue_bridge_restarts`: count of times the bridge has restarted (*estimated based on sensor data*). + ## Metric structure > Hey, why didn't you combine the metrics for brightness and hue and saturation and on and reachable? diff --git a/sensors.go b/sensors.go index 660b974..766cf4b 100644 --- a/sensors.go +++ b/sensors.go @@ -1,6 +1,8 @@ package main import ( + "math" + hue "github.com/collinux/gohue" "github.com/prometheus/client_golang/prometheus" log "github.com/prometheus/common/log" @@ -16,6 +18,7 @@ type sensorCollector struct { sensorBattery *prometheus.GaugeVec sensorReachable *prometheus.GaugeVec sensorScrapesFailed prometheus.Counter + bridgeRestarts prometheus.Counter } var variableSensorLabelNames = []string{ @@ -37,6 +40,13 @@ func contains(a []string, x string) bool { return false } +func max(a, b int64) int64 { + if a > b { + return a + } + return b +} + // NewSensorCollector Create a new Hue collector for sensors func NewSensorCollector(namespace string, bridge Bridge, ignoreTypes []string, matchNames bool) prometheus.Collector { c := sensorCollector{ @@ -96,6 +106,14 @@ func NewSensorCollector(namespace string, bridge Bridge, ignoreTypes []string, m Help: "Count of scrapes of sensor data from the Hue bridge that have failed", }, ), + bridgeRestarts: prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: "bridge", + Name: "restarts", + Help: "Count of number of bridge restarts detected", + }, + ), } return c @@ -108,6 +126,7 @@ func (c sensorCollector) Describe(ch chan<- *prometheus.Desc) { c.sensorOn.Describe(ch) c.sensorReachable.Describe(ch) c.sensorScrapesFailed.Describe(ch) + c.bridgeRestarts.Describe(ch) } func (c sensorCollector) recordSensor(sensor hue.Sensor, sensorName string, deviceID string, sensorValue float64) { @@ -149,6 +168,8 @@ func (c sensorCollector) Collect(ch chan<- prometheus.Metric) { c.sensorScrapesFailed.Inc() } sensorNames := make(map[string]string) + sensorLastUpdatedHistory := make(map[string]int64) + restartDetected := false for _, sensor := range sensors { var sensorValue float64 @@ -179,7 +200,10 @@ func (c sensorCollector) Collect(ch chan<- prometheus.Metric) { } else { continue } - + if sensorLastUpdatedHistory[sensor.UniqueID] > math.MinInt64 && sensor.State.LastUpdated.Unix() == math.MinInt64 { + restartDetected = true + } + sensorLastUpdatedHistory[sensor.UniqueID] = sensor.State.LastUpdated.Unix() c.recordSensor(sensor, sensor.Name, deviceID, sensorValue) } // kinda inefficient looping over them twice, but simplies code when name matching is enabled @@ -201,13 +225,22 @@ func (c sensorCollector) Collect(ch chan<- prometheus.Metric) { sensorName = sensor.Name } } + if sensorLastUpdatedHistory[sensor.UniqueID] > math.MinInt64 && sensor.State.LastUpdated.Unix() == math.MinInt64 { + restartDetected = true + } + sensorLastUpdatedHistory[sensor.UniqueID] = sensor.State.LastUpdated.Unix() c.recordSensor(sensor, sensorName, deviceID, sensorValue) } + if restartDetected { + c.bridgeRestarts.Inc() + } + c.sensorValue.Collect(ch) c.sensorBattery.Collect(ch) c.sensorLastUpdated.Collect(ch) c.sensorOn.Collect(ch) c.sensorReachable.Collect(ch) c.sensorScrapesFailed.Collect(ch) + c.bridgeRestarts.Collect(ch) } -- GitLab