Skip to content

Commit

Permalink
Merge pull request #115 from wmoss/wmoss-fix-sensor_filter_name-errors
Browse files Browse the repository at this point in the history
Remove incorrect errors when using SensorNameFilter
  • Loading branch information
hikhvar committed Jan 4, 2023
2 parents 682d2c1 + f03d084 commit db6213e
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 26 deletions.
28 changes: 19 additions & 9 deletions pkg/metrics/extractor.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package metrics

import (
"errors"
"fmt"

"github.com/hikhvar/mqtt2prometheus/pkg/config"
Expand All @@ -21,7 +20,14 @@ func NewJSONObjectExtractor(p Parser) Extractor {
if rawValue == nil {
continue
}
m, err := p.parseMetric(path, deviceID, rawValue)

// Find a valid metrics config
config, found := p.findMetricConfig(path, deviceID)
if !found {
continue
}

m, err := p.parseMetric(config, rawValue)
if err != nil {
return nil, fmt.Errorf("failed to parse valid metric value: %w", err)
}
Expand All @@ -32,17 +38,21 @@ func NewJSONObjectExtractor(p Parser) Extractor {
}
}

func NewMetricPerTopicExtractor(p Parser, metricName *config.Regexp) Extractor {
func NewMetricPerTopicExtractor(p Parser, metricNameRegex *config.Regexp) Extractor {
return func(topic string, payload []byte, deviceID string) (MetricCollection, error) {
mName := metricName.GroupValue(topic, config.MetricNameRegexGroup)
if mName == "" {
metricName := metricNameRegex.GroupValue(topic, config.MetricNameRegexGroup)
if metricName == "" {
return nil, fmt.Errorf("failed to find valid metric in topic path")
}
m, err := p.parseMetric(mName, deviceID, string(payload))

// Find a valid metrics config
config, found := p.findMetricConfig(metricName, deviceID)
if !found {
return nil, nil
}

m, err := p.parseMetric(config, string(payload))
if err != nil {
if errors.Is(err, metricNotConfigured) {
return nil, nil
}
return nil, fmt.Errorf("failed to parse metric: %w", err)
}
m.Topic = topic
Expand Down
59 changes: 57 additions & 2 deletions pkg/metrics/extractor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func TestNewJSONObjectExtractor_parseMetric(t *testing.T) {
args args
want Metric
wantErr bool
noValue bool
}{
{
name: "string value",
Expand Down Expand Up @@ -78,6 +79,55 @@ func TestNewJSONObjectExtractor_parseMetric(t *testing.T) {
IngestTime: testNow(),
Topic: "topic",
},
}, {
name: "metric matching SensorNameFilter",
separator: ".",
fields: fields{
map[string][]config.MetricConfig{
"temperature": []config.MetricConfig{
{
PrometheusName: "temperature",
MQTTName: "temperature",
ValueType: "gauge",
SensorNameFilter: *config.MustNewRegexp(".*22$"),
},
},
},
},
args: args{
metricPath: "topic",
deviceID: "dht22",
value: "{\"temperature\": 8.5}",
},
want: Metric{
Description: prometheus.NewDesc("temperature", "", []string{"sensor", "topic"}, nil),
ValueType: prometheus.GaugeValue,
Value: 8.5,
IngestTime: testNow(),
Topic: "topic",
},
}, {
name: "metric not matching SensorNameFilter",
separator: ".",
fields: fields{
map[string][]config.MetricConfig{
"temperature": []config.MetricConfig{
{
PrometheusName: "temperature",
MQTTName: "temperature",
ValueType: "gauge",
SensorNameFilter: *config.MustNewRegexp(".*fail$"),
},
},
},
},
args: args{
metricPath: "topic",
deviceID: "dht22",
value: "{\"temperature\": 8.5}",
},
want: Metric{},
noValue: true,
},
}
for _, tt := range tests {
Expand All @@ -93,10 +143,15 @@ func TestNewJSONObjectExtractor_parseMetric(t *testing.T) {
t.Errorf("parseMetric() error = %v, wantErr %v", err, tt.wantErr)
return
}
if len(got) != 1 {
t.Errorf("parseMetric() got = %v, want %v", nil, tt.want)

if len(got) == 0 {
if !tt.noValue {
t.Errorf("parseMetric() got = %v, want %v", nil, tt.want)
}
} else if !reflect.DeepEqual(got[0], tt.want) {
t.Errorf("parseMetric() got = %v, want %v", got[0], tt.want)
} else if len(got) > 1 {
t.Errorf("unexpected result got = %v, want %v", got, tt.want)
}
})
}
Expand Down
18 changes: 5 additions & 13 deletions pkg/metrics/parser.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
package metrics

import (
"errors"
"fmt"
"strconv"
"time"

"github.com/hikhvar/mqtt2prometheus/pkg/config"
)

type metricNotConfiguredError error

var metricNotConfigured metricNotConfiguredError = errors.New("metric not configured failed to parse")

type Parser struct {
separator string
separator string
// Maps the mqtt metric name to a list of configs
// The first that matches SensorNameFilter will be used
metricConfigs map[string][]config.MetricConfig
}

Expand All @@ -39,7 +36,7 @@ func (p *Parser) config() map[string][]config.MetricConfig {

// validMetric returns config matching the metric and deviceID
// Second return value indicates if config was found.
func (p *Parser) validMetric(metric string, deviceID string) (config.MetricConfig, bool) {
func (p *Parser) findMetricConfig(metric string, deviceID string) (config.MetricConfig, bool) {
for _, c := range p.metricConfigs[metric] {
if c.SensorNameFilter.Match(deviceID) {
return c, true
Expand All @@ -50,12 +47,7 @@ func (p *Parser) validMetric(metric string, deviceID string) (config.MetricConfi

// parseMetric parses the given value according to the given deviceID and metricPath. The config allows to
// parse a metric value according to the device ID.
func (p *Parser) parseMetric(metricPath string, deviceID string, value interface{}) (Metric, error) {
cfg, cfgFound := p.validMetric(metricPath, deviceID)
if !cfgFound {
return Metric{}, metricNotConfigured
}

func (p *Parser) parseMetric(cfg config.MetricConfig, value interface{}) (Metric, error) {
var metricValue float64

if boolValue, ok := value.(bool); ok {
Expand Down
14 changes: 12 additions & 2 deletions pkg/metrics/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ func TestParser_parseMetric(t *testing.T) {
args: args{
metricPath: "enabled",
deviceID: "dht22",
value: metricNotConfigured,
value: []int{3},
},
wantErr: true,
},
Expand All @@ -421,7 +421,17 @@ func TestParser_parseMetric(t *testing.T) {
p := &Parser{
metricConfigs: tt.fields.metricConfigs,
}
got, err := p.parseMetric(tt.args.metricPath, tt.args.deviceID, tt.args.value)

// Find a valid metrics config
config, found := p.findMetricConfig(tt.args.metricPath, tt.args.deviceID)
if !found {
if !tt.wantErr {
t.Errorf("MetricConfig not found")
}
return
}

got, err := p.parseMetric(config, tt.args.value)
if (err != nil) != tt.wantErr {
t.Errorf("parseMetric() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down

0 comments on commit db6213e

Please sign in to comment.