Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse more value types #9

Merged
merged 3 commits into from
May 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 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
60 changes: 41 additions & 19 deletions pkg/metrics/ingest.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"log"
"path/filepath"
"regexp"
"strconv"

"github.com/eclipse/paho.mqtt.golang"
Expand All @@ -19,8 +18,6 @@ type Ingest struct {
MessageMetric *prometheus.CounterVec
}

var validNumber = regexp.MustCompile(`^[0-9.]+$`)

func NewIngest(collector Collector, metrics []config.MetricConfig) *Ingest {
valid := make(map[string]config.MetricConfig)
for i := range metrics {
Expand All @@ -45,30 +42,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