collect option

This commit is contained in:
aexel90 2020-12-29 14:10:47 +01:00
parent 7c629a62f7
commit 050d40cf27
5 changed files with 238 additions and 157 deletions

View file

@ -17,20 +17,18 @@ type Collector struct {
} }
// NewHueCollector initialization // NewHueCollector initialization
func NewHueCollector(URL string, username string) (*Collector, error) { func NewHueCollector(URL string, username string, metricsFile *metric.MetricsFile) (*Collector, error) {
hueExporter := hue.Exporter{ hueExporter := hue.Exporter{
BaseURL: URL, BaseURL: URL,
Username: username, Username: username,
} }
return &Collector{&hueExporter, nil}, nil return &Collector{&hueExporter, metricsFile.Metrics}, nil
} }
// Describe for prometheus // Describe for prometheus
func (collector *Collector) Describe(ch chan<- *prometheus.Desc) { func (collector *Collector) Describe(ch chan<- *prometheus.Desc) {
collector.metrics = collector.exporter.InitMetrics()
collector.initDescAndType() collector.initDescAndType()
} }
@ -52,7 +50,6 @@ func (collector *Collector) Collect(ch chan<- prometheus.Metric) {
//Test collector metrics //Test collector metrics
func (collector *Collector) Test() { func (collector *Collector) Test() {
collector.metrics = collector.exporter.InitMetrics()
collector.initDescAndType() collector.initDescAndType()
err := collector.collect() err := collector.collect()
@ -194,10 +191,6 @@ func getLabelValues(labelNames []string, result map[string]interface{}) ([]strin
case "false": case "false":
labelValueString = "0" labelValueString = "0"
} }
if labelname != "name" {
labelValue = strings.ToLower(labelValueString)
}
labelValues = append(labelValues, labelValueString) labelValues = append(labelValues, labelValueString)
} }
return labelValues, nil return labelValues, nil

View file

@ -21,116 +21,47 @@ type collectEntry struct {
} }
const ( const (
TypeLight = "light" typeLight = "light"
TypeSensor = "sensor" typeSensor = "sensor"
LabelName = "name" labelName = "name"
LabelType = "type" labelType = "type"
LabelID = "id" labelID = "id"
LabelModelID = "model_id" labelModelID = "model_id"
LabelManufacturerName = "manufacturer_name" labelManufacturerName = "manufacturer_name"
LabelSwVersion = "sw_version" labelSwVersion = "sw_version"
LabelSwConfigID = "sw_config_id" labelSwConfigID = "sw_config_id"
LabelUniqueID = "unique_id" labelUniqueID = "unique_id"
LabelStateOn = "state_on" labelStateOn = "state_on"
LabelStateAlert = "state_alert" labelStateAlert = "state_alert"
LabelStateBri = "state_bri" labelStateBri = "state_bri"
LabelStateColorMode = "state_color_mode" labelStateColorMode = "state_color_mode"
LabelStateCT = "state_ct" labelStateCT = "state_ct"
LabelStateReachable = "state_reachable" labelStateReachable = "state_reachable"
LabelStateSaturation = "state_saturation" labelStateSaturation = "state_saturation"
LabelStateButtonEvent = "state_buttonevent" labelStateButtonEvent = "state_buttonevent"
LabelStateDaylight = "state_daylight" labelStateDaylight = "state_daylight"
LabelStateLastUpdated = "state_lastupdated" labelStateLastUpdated = "state_lastupdated"
LabelStateTemperature = "state_temperature" labelStateTemperature = "state_temperature"
LabelStateLightLevel = "state_lightlevel" labelStateLightLevel = "state_lightlevel"
LabelConfigBattery = "config_battery" labelConfigBattery = "config_battery"
LabelConfigOn = "config_on" labelConfigOn = "config_on"
LabelConfigReachable = "config_reachable" labelConfigReachable = "config_reachable"
labelAPIVersion = "api_version"
labelBridgeID = "bridge_id"
labelIPAddress = "ip_address"
labelInternetServiceInternet = "internetservice_internet"
labelInternetServiceRemoteAccess = "internetservice_remoteaccess"
labelInternetServiceSwUpdate = "internetservice_swupdate"
labelInternetServiceTime = "internetservice_time"
labelLocalTime = "local_time"
labelSwUpdate2LastChange = "sw_update_last_change"
labelZigbeeChannel = "zigbee_channel"
) )
// InitMetrics func
func (exporter *Exporter) InitMetrics() (metrics []*metric.Metric) {
metrics = append(metrics, &metric.Metric{
HueType: TypeLight,
FqName: "hue_light_info",
Help: "Non-numeric data, value is always 1",
Labels: []string{
LabelName,
LabelID,
LabelType,
LabelModelID,
LabelManufacturerName,
LabelSwVersion,
LabelSwConfigID,
LabelUniqueID,
LabelStateOn,
LabelStateAlert,
LabelStateBri,
LabelStateCT,
LabelStateReachable,
LabelStateSaturation,
},
})
metrics = append(metrics, &metric.Metric{
HueType: TypeLight,
FqName: "hue_light_state",
Help: "light status (1=ON, 0=OFF)",
Labels: []string{
LabelName,
},
ResultKey: LabelStateOn,
})
metrics = append(metrics, &metric.Metric{
HueType: TypeSensor,
FqName: "hue_sensor_info",
Help: "Non-numeric data, value is always 1",
Labels: []string{
LabelName,
LabelID,
LabelType,
LabelModelID,
LabelManufacturerName,
LabelSwVersion,
LabelUniqueID,
LabelStateButtonEvent,
LabelStateDaylight,
LabelStateLastUpdated,
LabelStateTemperature,
LabelConfigBattery,
LabelConfigOn,
LabelConfigReachable,
},
})
metrics = append(metrics, &metric.Metric{
HueType: TypeSensor,
FqName: "hue_sensor_temperature",
Help: "temperature level celsius degree",
Labels: []string{
LabelName,
},
ResultKey: LabelStateTemperature,
})
metrics = append(metrics, &metric.Metric{
HueType: TypeSensor,
FqName: "hue_sensor_lightlevel",
Help: "light level",
Labels: []string{
LabelName,
},
ResultKey: LabelStateLightLevel,
})
return metrics
}
// CollectAll available hue metrics // CollectAll available hue metrics
func CollectAll(url string, username string, fileName string) { func CollectAll(url string, username string, fileName string) {
@ -150,17 +81,20 @@ func CollectAll(url string, username string, fileName string) {
return return
} }
bridgeData, err := collectBridgeInfo(bridge)
if err != nil {
fmt.Sprintln(err)
return
}
for _, sensor := range sensorData { for _, sensor := range sensorData {
jsonContent = append(jsonContent, collectEntry{ jsonContent = append(jsonContent, collectEntry{Type: "sensor", Result: sensor})
Type: "sensor",
Result: sensor,
})
} }
for _, light := range lightData { for _, light := range lightData {
jsonContent = append(jsonContent, collectEntry{ jsonContent = append(jsonContent, collectEntry{Type: "light", Result: light})
Type: "light", }
Result: light, for _, bridge := range bridgeData {
}) jsonContent = append(jsonContent, collectEntry{Type: "bridge", Result: bridge})
} }
jsonString, err := json.MarshalIndent(jsonContent, "", "\t") jsonString, err := json.MarshalIndent(jsonContent, "", "\t")
@ -195,11 +129,14 @@ func (exporter *Exporter) Collect(metrics []*metric.Metric) (err error) {
for _, metric := range metrics { for _, metric := range metrics {
switch metric.HueType { switch metric.HueType {
case TypeLight: case typeLight:
metric.MetricResult = lightData metric.MetricResult = lightData
case TypeSensor: case typeSensor:
metric.MetricResult = sensorData metric.MetricResult = sensorData
default:
return fmt.Errorf("Type '%v' currently not supported", metric.HueType)
} }
} }
return nil return nil
@ -209,17 +146,17 @@ func collectSensors(bridge *hueAPI.Bridge) (sensorData []map[string]interface{},
sensors, err := bridge.GetSensors() sensors, err := bridge.GetSensors()
if err != nil { if err != nil {
return nil, fmt.Errorf("[error GetAllSensors()] '%v'", err) return nil, fmt.Errorf("[GetAllSensors()] '%v'", err)
} }
for _, sensor := range sensors { for _, sensor := range sensors {
result := make(map[string]interface{}) result := make(map[string]interface{})
result[LabelName] = sensor.Name result[labelName] = sensor.Name
result[LabelID] = sensor.ID result[labelID] = sensor.ID
result[LabelType] = sensor.Type result[labelType] = sensor.Type
result[LabelModelID] = sensor.ModelID result[labelModelID] = sensor.ModelID
result[LabelManufacturerName] = sensor.ManufacturerName result[labelManufacturerName] = sensor.ManufacturerName
result[LabelSwVersion] = sensor.SwVersion result[labelSwVersion] = sensor.SwVersion
result[LabelUniqueID] = sensor.UniqueID result[labelUniqueID] = sensor.UniqueID
//State //State
for stateKey, stateValue := range sensor.State { for stateKey, stateValue := range sensor.State {
@ -240,31 +177,56 @@ func collectLights(bridge *hueAPI.Bridge) (lightData []map[string]interface{}, e
lights, err := bridge.GetLights() lights, err := bridge.GetLights()
if err != nil { if err != nil {
return nil, fmt.Errorf("[error GetAllLights()] '%v'", err) return nil, fmt.Errorf("[GetAllLights()] '%v'", err)
} }
for _, light := range lights { for _, light := range lights {
result := make(map[string]interface{}) result := make(map[string]interface{})
result[LabelName] = light.Name result[labelName] = light.Name
result[LabelID] = light.ID result[labelID] = light.ID
result[LabelType] = light.Type result[labelType] = light.Type
result[LabelModelID] = light.ModelID result[labelModelID] = light.ModelID
result[LabelManufacturerName] = light.ManufacturerName result[labelManufacturerName] = light.ManufacturerName
result[LabelSwVersion] = light.SwVersion result[labelSwVersion] = light.SwVersion
result[LabelSwConfigID] = light.SwConfigID result[labelSwConfigID] = light.SwConfigID
result[LabelUniqueID] = light.UniqueID result[labelUniqueID] = light.UniqueID
// State // State
result[LabelStateOn] = light.State.On result[labelStateOn] = light.State.On
result[LabelStateAlert] = light.State.Alert result[labelStateAlert] = light.State.Alert
result[LabelStateBri] = light.State.Bri result[labelStateBri] = light.State.Bri
result[LabelStateColorMode] = light.State.ColorMode result[labelStateColorMode] = light.State.ColorMode
result[LabelStateCT] = light.State.Ct result[labelStateCT] = light.State.Ct
result[LabelStateReachable] = light.State.Reachable result[labelStateReachable] = light.State.Reachable
result[LabelStateSaturation] = light.State.Sat result[labelStateSaturation] = light.State.Sat
lightData = append(lightData, result) lightData = append(lightData, result)
} }
return lightData, nil return lightData, nil
} }
func collectBridgeInfo(bridge *hueAPI.Bridge) (bridgeData []map[string]interface{}, err error) {
config, err := bridge.GetConfig()
if err != nil {
return nil, fmt.Errorf("[GetConfig] '%v'", err)
}
result := make(map[string]interface{})
result[labelName] = config.Name
result[labelAPIVersion] = config.APIVersion
result[labelBridgeID] = config.BridgeID
result[labelIPAddress] = config.IPAddress
result[labelInternetServiceInternet] = config.InternetService.Internet
result[labelInternetServiceRemoteAccess] = config.InternetService.RemoteAccess
result[labelInternetServiceSwUpdate] = config.InternetService.SwUpdate
result[labelInternetServiceTime] = config.InternetService.Time
result[labelLocalTime] = config.LocalTime
result[labelModelID] = config.ModelID
result[labelSwVersion] = config.SwVersion
result[labelSwUpdate2LastChange] = config.SwUpdate2.LastChange
result[labelZigbeeChannel] = config.ZigbeeChannel
bridgeData = append(bridgeData, result)
return bridgeData, nil
}

33
main.go
View file

@ -1,7 +1,9 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"io/ioutil"
"log" "log"
"net/http" "net/http"
@ -11,12 +13,14 @@ import (
"github.com/aexel90/hue_exporter/collector" "github.com/aexel90/hue_exporter/collector"
"github.com/aexel90/hue_exporter/hue" "github.com/aexel90/hue_exporter/hue"
"github.com/aexel90/hue_exporter/metric"
) )
var ( var (
flagBridgeURL = flag.String("hue-url", "", "The URL of the bridge") flagBridgeURL = flag.String("hue-url", "", "The URL of the bridge")
flagUsername = flag.String("username", "", "The username token having bridge access") flagUsername = flag.String("username", "", "The username token having bridge access")
flagAddress = flag.String("listen-address", "127.0.0.1:9773", "The address to listen on for HTTP requests.") flagAddress = flag.String("listen-address", "127.0.0.1:9773", "The address to listen on for HTTP requests.")
flagMetricsFile = flag.String("metrics-file", "metrics.json", "The JSON file with the metric definitions.")
flagTest = flag.Bool("test", false, "test configured metrics") flagTest = flag.Bool("test", false, "test configured metrics")
flagCollect = flag.Bool("collect", false, "test configured metrics") flagCollect = flag.Bool("collect", false, "test configured metrics")
@ -27,13 +31,21 @@ func main() {
flag.Parse() flag.Parse()
var metricsFile *metric.MetricsFile
// collect mode // collect mode
if *flagCollect { if *flagCollect {
hue.CollectAll(*flagBridgeURL, *flagUsername, *flagCollectFile) hue.CollectAll(*flagBridgeURL, *flagUsername, *flagCollectFile)
return return
} }
hueCollector, err := collector.NewHueCollector(*flagBridgeURL, *flagUsername) err := readAndParseFile(*flagMetricsFile, &metricsFile)
if err != nil {
fmt.Println(err)
return
}
hueCollector, err := collector.NewHueCollector(*flagBridgeURL, *flagUsername, metricsFile)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
@ -48,3 +60,16 @@ func main() {
log.Fatal(http.ListenAndServe(*flagAddress, nil)) log.Fatal(http.ListenAndServe(*flagAddress, nil))
} }
} }
func readAndParseFile(file string, v interface{}) error {
jsonData, err := ioutil.ReadFile(file)
if err != nil {
return fmt.Errorf("error reading metric file: %v", err)
}
err = json.Unmarshal(jsonData, v)
if err != nil {
return fmt.Errorf("error parsing JSON: %v", err)
}
return nil
}

View file

@ -14,14 +14,20 @@ type PrometheusResult struct {
// Metric struct // Metric struct
type Metric struct { type Metric struct {
HueType string HueType string `json:"type"`
Labels []string ResultKey string `json:"resultKey"`
FqName string `json:"fqName"`
Help string `json:"help"`
Labels []string `json:"labels"`
MetricResult []map[string]interface{} MetricResult []map[string]interface{}
ResultKey string
FqName string
Help string
PromType prometheus.ValueType PromType prometheus.ValueType
PromDesc *prometheus.Desc PromDesc *prometheus.Desc
PromResult []*PrometheusResult PromResult []*PrometheusResult
} }
// MetricsFile struct
type MetricsFile struct {
Metrics []*Metric `json:"metrics"`
}

95
metrics.json Normal file
View file

@ -0,0 +1,95 @@
{
"metrics": [
{
"type": "light",
"fqname": "hue_light_info",
"help": "Non-numeric data, value is always 1",
"labels": [
"id",
"manufacturer_name",
"model_id",
"name",
"state_alert",
"state_bri",
"state_color_mode",
"state_ct",
"state_on",
"state_reachable",
"state_saturation",
"sw_config_id",
"sw_version",
"type",
"unique_id"
]
},
{
"type": "light",
"fqname": "hue_light_state",
"help": "light status (1=ON, 0=OFF)",
"resultKey": "state_on",
"labels": [
"name"
]
},
{
"type": "sesnsor",
"fqname": "hue_sensor_info",
"help": "Non-numeric data, value is always 1",
"labels": [
"config_battery",
"config_on",
"config_reachable",
"id",
"manufacturer_name",
"model_id",
"name",
"state_buttonevent",
"state_daylight",
"state_lastupdated",
"state_lightlevel",
"state_temperature",
"sw_version",
"type",
"unique_id"
]
},
{
"type": "sensor",
"fqname": "hue_sensor_temperature",
"help": "temperature level celsius degree",
"resultKey": "state_temperature",
"labels": [
"name"
]
},
{
"type": "sensor",
"fqname": "hue_sensor_lightlevel",
"help": "light level",
"resultKey": "state_lightlevel",
"labels": [
"name"
]
},
{
"type": "bridge",
"fqname": "hue_brdige_info",
"help": "Non-numeric data, value is always 1",
"labels": [
"api_version",
"bridge_id",
"internetservice_internet",
"internetservice_remoteaccess",
"internetservice_swupdate",
"internetservice_time",
"ip_address",
"local_time",
"model_id",
"name",
"sw_update_last_change",
"sw_version",
"zigbee_channel"
]
}
]
}