Skip to content

Commit

Permalink
Parse more value types
Browse files Browse the repository at this point in the history
* Parse bools as 0 for false and 1 for true
* Allow mapping between string and float values
  • Loading branch information
oxplot committed May 3, 2020
1 parent 39a6e39 commit 13c47b4
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 24 deletions.
23 changes: 21 additions & 2 deletions config.yaml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mqtt:
qos: 0
cache:
# Timeout. Each received metric will be presented for this time if no update is send via MQTT
timeout: 2min
timeout: 2m
# This is a list of valid metrics. Only metrics listed here will be exported
metrics:
# The name of the metric in prometheus
Expand Down Expand Up @@ -46,4 +46,23 @@ metrics:
type: gauge
# A map of string to string for constant labels. This labels will be attached to every prometheus metric
const_labels:
sensor_type: dht22
sensor_type: dht22
- prom_name: state
# The name of the metric in a MQTT JSON message
mqtt_name: state
# The prometheus help text for this metric
help: Light state
# The prometheus type for this metric. Valid values are: "gauge" and "counter"
type: gauge
# A map of string to string for constant labels. This labels will be attached to every prometheus metric
const_labels:
sensor_type: ikea
# When specified, enables mapping between string values to metric values.
string_value_mapping:
# A map of string to metric value.
map:
off: 0
low: 0
# Metric value to use if a match cannot be found in the map above.
# If not specified, parsing error will occur.
error_value: 1
21 changes: 15 additions & 6 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package config

import (
"time"
"io/ioutil"
"time"

"github.com/prometheus/client_golang/prometheus"
"gopkg.in/yaml.v2"
)
Expand Down Expand Up @@ -40,11 +41,19 @@ type MQTTConfig struct {

// Metrics Config is a mapping between a metric send on mqtt to a prometheus metric
type MetricConfig struct {
PrometheusName string `yaml:"prom_name"`
MQTTName string `yaml:"mqtt_name"`
Help string `yaml:"help"`
ValueType string `yaml:"type"`
ConstantLabels map[string]string `yaml:"const_labels"`
PrometheusName string `yaml:"prom_name"`
MQTTName string `yaml:"mqtt_name"`
Help string `yaml:"help"`
ValueType string `yaml:"type"`
ConstantLabels map[string]string `yaml:"const_labels"`
StringValueMapping *StringValueMappingConfig `yaml:"string_value_mapping"`
}

// StringValueMappingConfig defines the mapping between from string to float
type StringValueMappingConfig struct {
// ErrorValue is used when no mapping is found in Map
ErrorValue *float64 `yaml:"error_value"`
Map map[string]float64 `yaml:"map"`
}

func (mc *MetricConfig) PrometheusDescription() *prometheus.Desc {
Expand Down
57 changes: 41 additions & 16 deletions pkg/metrics/ingest.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,30 +45,55 @@ func (i *Ingest) store(deviceID string, rawMetrics MQTTPayload) error {
var mc MetricCollection

for metricName, value := range rawMetrics {
if cfg, found := i.validMetrics[metricName]; found {
var floatValue float64
var isFloat bool
var err error
floatValue, isFloat = value.(float64)
if !isFloat {
stringValue, isString := value.(string)

if !isString || ! validNumber.MatchString(stringValue) {
return fmt.Errorf("got data with unexpectd type: %T ('%s')", value, value)
cfg, cfgFound := i.validMetrics[metricName]
if !cfgFound {
continue
}

var metricValue float64

if boolValue, ok := value.(bool); ok {
if boolValue {
metricValue = 1
} else {
metricValue = 0
}
} else if strValue, ok := value.(string); ok {

// If string value mapping is defined, use that
if cfg.StringValueMapping != nil {

floatValue, ok := cfg.StringValueMapping.Map[strValue]
if ok {
metricValue = floatValue
} else if cfg.StringValueMapping.ErrorValue != nil {
metricValue = *cfg.StringValueMapping.ErrorValue
} else {
return fmt.Errorf("got unexpected string data '%s'", strValue)
}

floatValue, err = strconv.ParseFloat(stringValue, 64)
} else {

// otherwise try to parse float
floatValue, err := strconv.ParseFloat(strValue, 64)
if err != nil {
return fmt.Errorf("got data with unexpectd type: %T ('%s') and failed to parse to float", value, value)
}
metricValue = floatValue

}

mc = append(mc, Metric{
Description: cfg.PrometheusDescription(),
Value: floatValue,
ValueType: cfg.PrometheusValueType(),
})
} else if floatValue, ok := value.(float64); ok {
metricValue = floatValue
} else {
return fmt.Errorf("got data with unexpectd type: %T ('%s')", value, value)
}

mc = append(mc, Metric{
Description: cfg.PrometheusDescription(),
Value: metricValue,
ValueType: cfg.PrometheusValueType(),
})
}
i.collector.Observe(deviceID, mc)
return nil
Expand Down

0 comments on commit 13c47b4

Please sign in to comment.