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

View file

@ -21,116 +21,47 @@ type collectEntry struct {
}
const (
TypeLight = "light"
TypeSensor = "sensor"
typeLight = "light"
typeSensor = "sensor"
LabelName = "name"
LabelType = "type"
LabelID = "id"
LabelModelID = "model_id"
LabelManufacturerName = "manufacturer_name"
LabelSwVersion = "sw_version"
LabelSwConfigID = "sw_config_id"
LabelUniqueID = "unique_id"
labelName = "name"
labelType = "type"
labelID = "id"
labelModelID = "model_id"
labelManufacturerName = "manufacturer_name"
labelSwVersion = "sw_version"
labelSwConfigID = "sw_config_id"
labelUniqueID = "unique_id"
LabelStateOn = "state_on"
LabelStateAlert = "state_alert"
LabelStateBri = "state_bri"
LabelStateColorMode = "state_color_mode"
LabelStateCT = "state_ct"
LabelStateReachable = "state_reachable"
LabelStateSaturation = "state_saturation"
LabelStateButtonEvent = "state_buttonevent"
LabelStateDaylight = "state_daylight"
LabelStateLastUpdated = "state_lastupdated"
LabelStateTemperature = "state_temperature"
LabelStateLightLevel = "state_lightlevel"
labelStateOn = "state_on"
labelStateAlert = "state_alert"
labelStateBri = "state_bri"
labelStateColorMode = "state_color_mode"
labelStateCT = "state_ct"
labelStateReachable = "state_reachable"
labelStateSaturation = "state_saturation"
labelStateButtonEvent = "state_buttonevent"
labelStateDaylight = "state_daylight"
labelStateLastUpdated = "state_lastupdated"
labelStateTemperature = "state_temperature"
labelStateLightLevel = "state_lightlevel"
LabelConfigBattery = "config_battery"
LabelConfigOn = "config_on"
LabelConfigReachable = "config_reachable"
labelConfigBattery = "config_battery"
labelConfigOn = "config_on"
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
func CollectAll(url string, username string, fileName string) {
@ -150,17 +81,20 @@ func CollectAll(url string, username string, fileName string) {
return
}
bridgeData, err := collectBridgeInfo(bridge)
if err != nil {
fmt.Sprintln(err)
return
}
for _, sensor := range sensorData {
jsonContent = append(jsonContent, collectEntry{
Type: "sensor",
Result: sensor,
})
jsonContent = append(jsonContent, collectEntry{Type: "sensor", Result: sensor})
}
for _, light := range lightData {
jsonContent = append(jsonContent, collectEntry{
Type: "light",
Result: light,
})
jsonContent = append(jsonContent, collectEntry{Type: "light", Result: light})
}
for _, bridge := range bridgeData {
jsonContent = append(jsonContent, collectEntry{Type: "bridge", Result: bridge})
}
jsonString, err := json.MarshalIndent(jsonContent, "", "\t")
@ -195,11 +129,14 @@ func (exporter *Exporter) Collect(metrics []*metric.Metric) (err error) {
for _, metric := range metrics {
switch metric.HueType {
case TypeLight:
case typeLight:
metric.MetricResult = lightData
case TypeSensor:
case typeSensor:
metric.MetricResult = sensorData
default:
return fmt.Errorf("Type '%v' currently not supported", metric.HueType)
}
}
return nil
@ -209,17 +146,17 @@ func collectSensors(bridge *hueAPI.Bridge) (sensorData []map[string]interface{},
sensors, err := bridge.GetSensors()
if err != nil {
return nil, fmt.Errorf("[error GetAllSensors()] '%v'", err)
return nil, fmt.Errorf("[GetAllSensors()] '%v'", err)
}
for _, sensor := range sensors {
result := make(map[string]interface{})
result[LabelName] = sensor.Name
result[LabelID] = sensor.ID
result[LabelType] = sensor.Type
result[LabelModelID] = sensor.ModelID
result[LabelManufacturerName] = sensor.ManufacturerName
result[LabelSwVersion] = sensor.SwVersion
result[LabelUniqueID] = sensor.UniqueID
result[labelName] = sensor.Name
result[labelID] = sensor.ID
result[labelType] = sensor.Type
result[labelModelID] = sensor.ModelID
result[labelManufacturerName] = sensor.ManufacturerName
result[labelSwVersion] = sensor.SwVersion
result[labelUniqueID] = sensor.UniqueID
//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()
if err != nil {
return nil, fmt.Errorf("[error GetAllLights()] '%v'", err)
return nil, fmt.Errorf("[GetAllLights()] '%v'", err)
}
for _, light := range lights {
result := make(map[string]interface{})
result[LabelName] = light.Name
result[LabelID] = light.ID
result[LabelType] = light.Type
result[LabelModelID] = light.ModelID
result[LabelManufacturerName] = light.ManufacturerName
result[LabelSwVersion] = light.SwVersion
result[LabelSwConfigID] = light.SwConfigID
result[LabelUniqueID] = light.UniqueID
result[labelName] = light.Name
result[labelID] = light.ID
result[labelType] = light.Type
result[labelModelID] = light.ModelID
result[labelManufacturerName] = light.ManufacturerName
result[labelSwVersion] = light.SwVersion
result[labelSwConfigID] = light.SwConfigID
result[labelUniqueID] = light.UniqueID
// State
result[LabelStateOn] = light.State.On
result[LabelStateAlert] = light.State.Alert
result[LabelStateBri] = light.State.Bri
result[LabelStateColorMode] = light.State.ColorMode
result[LabelStateCT] = light.State.Ct
result[LabelStateReachable] = light.State.Reachable
result[LabelStateSaturation] = light.State.Sat
result[labelStateOn] = light.State.On
result[labelStateAlert] = light.State.Alert
result[labelStateBri] = light.State.Bri
result[labelStateColorMode] = light.State.ColorMode
result[labelStateCT] = light.State.Ct
result[labelStateReachable] = light.State.Reachable
result[labelStateSaturation] = light.State.Sat
lightData = append(lightData, result)
}
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
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
@ -11,12 +13,14 @@ import (
"github.com/aexel90/hue_exporter/collector"
"github.com/aexel90/hue_exporter/hue"
"github.com/aexel90/hue_exporter/metric"
)
var (
flagBridgeURL = flag.String("hue-url", "", "The URL of the bridge")
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.")
flagBridgeURL = flag.String("hue-url", "", "The URL of the bridge")
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.")
flagMetricsFile = flag.String("metrics-file", "metrics.json", "The JSON file with the metric definitions.")
flagTest = flag.Bool("test", false, "test configured metrics")
flagCollect = flag.Bool("collect", false, "test configured metrics")
@ -27,13 +31,21 @@ func main() {
flag.Parse()
var metricsFile *metric.MetricsFile
// collect mode
if *flagCollect {
hue.CollectAll(*flagBridgeURL, *flagUsername, *flagCollectFile)
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 {
fmt.Println(err)
return
@ -48,3 +60,16 @@ func main() {
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
type Metric struct {
HueType string
Labels []string
HueType string `json:"type"`
ResultKey string `json:"resultKey"`
FqName string `json:"fqName"`
Help string `json:"help"`
Labels []string `json:"labels"`
MetricResult []map[string]interface{}
ResultKey string
FqName string
Help string
PromType prometheus.ValueType
PromDesc *prometheus.Desc
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"
]
}
]
}