mirror of
https://github.com/hikhvar/mqtt2prometheus.git
synced 2026-02-14 18:09:53 +00:00
Merge pull request #115 from wmoss/wmoss-fix-sensor_filter_name-errors
Remove incorrect errors when using SensorNameFilter
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/hikhvar/mqtt2prometheus/pkg/config"
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -25,6 +25,7 @@ func TestNewJSONObjectExtractor_parseMetric(t *testing.T) {
|
||||
args args
|
||||
want Metric
|
||||
wantErr bool
|
||||
noValue bool
|
||||
}{
|
||||
{
|
||||
name: "string value",
|
||||
@@ -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 {
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -9,12 +8,10 @@ import (
|
||||
"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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
|
||||
@@ -411,7 +411,7 @@ func TestParser_parseMetric(t *testing.T) {
|
||||
args: args{
|
||||
metricPath: "enabled",
|
||||
deviceID: "dht22",
|
||||
value: metricNotConfigured,
|
||||
value: []int{3},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user