mirror of
https://github.com/hikhvar/mqtt2prometheus.git
synced 2026-02-14 18:09:53 +00:00
Remove incorrect errors from SensorNameFilter
This commit reorganizes the logic in parseMetric to have it take in a MetricConfig so that the extractor can find the config and properly handle the case when there's no config found.
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hikhvar/mqtt2prometheus/pkg/config"
|
"github.com/hikhvar/mqtt2prometheus/pkg/config"
|
||||||
@@ -21,7 +20,14 @@ func NewJSONObjectExtractor(p Parser) Extractor {
|
|||||||
if rawValue == nil {
|
if rawValue == nil {
|
||||||
continue
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse valid metric value: %w", err)
|
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) {
|
return func(topic string, payload []byte, deviceID string) (MetricCollection, error) {
|
||||||
mName := metricName.GroupValue(topic, config.MetricNameRegexGroup)
|
metricName := metricNameRegex.GroupValue(topic, config.MetricNameRegexGroup)
|
||||||
if mName == "" {
|
if metricName == "" {
|
||||||
return nil, fmt.Errorf("failed to find valid metric in topic path")
|
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 err != nil {
|
||||||
if errors.Is(err, metricNotConfigured) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("failed to parse metric: %w", err)
|
return nil, fmt.Errorf("failed to parse metric: %w", err)
|
||||||
}
|
}
|
||||||
m.Topic = topic
|
m.Topic = topic
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ func TestNewJSONObjectExtractor_parseMetric(t *testing.T) {
|
|||||||
args args
|
args args
|
||||||
want Metric
|
want Metric
|
||||||
wantErr bool
|
wantErr bool
|
||||||
|
noValue bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "string value",
|
name: "string value",
|
||||||
@@ -78,6 +79,55 @@ func TestNewJSONObjectExtractor_parseMetric(t *testing.T) {
|
|||||||
IngestTime: testNow(),
|
IngestTime: testNow(),
|
||||||
Topic: "topic",
|
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 {
|
for _, tt := range tests {
|
||||||
@@ -93,10 +143,15 @@ func TestNewJSONObjectExtractor_parseMetric(t *testing.T) {
|
|||||||
t.Errorf("parseMetric() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("parseMetric() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
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) {
|
} else if !reflect.DeepEqual(got[0], tt.want) {
|
||||||
t.Errorf("parseMetric() got = %v, want %v", 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
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@@ -9,12 +8,10 @@ import (
|
|||||||
"github.com/hikhvar/mqtt2prometheus/pkg/config"
|
"github.com/hikhvar/mqtt2prometheus/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type metricNotConfiguredError error
|
|
||||||
|
|
||||||
var metricNotConfigured metricNotConfiguredError = errors.New("metric not configured failed to parse")
|
|
||||||
|
|
||||||
type Parser struct {
|
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
|
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
|
// validMetric returns config matching the metric and deviceID
|
||||||
// Second return value indicates if config was found.
|
// 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] {
|
for _, c := range p.metricConfigs[metric] {
|
||||||
if c.SensorNameFilter.Match(deviceID) {
|
if c.SensorNameFilter.Match(deviceID) {
|
||||||
return c, true
|
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
|
// 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.
|
// parse a metric value according to the device ID.
|
||||||
func (p *Parser) parseMetric(metricPath string, deviceID string, value interface{}) (Metric, error) {
|
func (p *Parser) parseMetric(cfg config.MetricConfig, value interface{}) (Metric, error) {
|
||||||
cfg, cfgFound := p.validMetric(metricPath, deviceID)
|
|
||||||
if !cfgFound {
|
|
||||||
return Metric{}, metricNotConfigured
|
|
||||||
}
|
|
||||||
|
|
||||||
var metricValue float64
|
var metricValue float64
|
||||||
|
|
||||||
if boolValue, ok := value.(bool); ok {
|
if boolValue, ok := value.(bool); ok {
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ func TestParser_parseMetric(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
metricPath: "enabled",
|
metricPath: "enabled",
|
||||||
deviceID: "dht22",
|
deviceID: "dht22",
|
||||||
value: metricNotConfigured,
|
value: []int{3},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
@@ -421,7 +421,17 @@ func TestParser_parseMetric(t *testing.T) {
|
|||||||
p := &Parser{
|
p := &Parser{
|
||||||
metricConfigs: tt.fields.metricConfigs,
|
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 {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("parseMetric() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("parseMetric() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user