Skip to content

Commit 3a9ad76

Browse files
authored
Merge pull request #157 from fatpat/error_value
make error_value global to metric and add error_expression
2 parents 4674e6a + d28d6cd commit 3a9ad76

File tree

9 files changed

+82
-24
lines changed

9 files changed

+82
-24
lines changed

Readme.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -241,15 +241,15 @@ metrics:
241241
# A map of string to string for constant labels. This labels will be attached to every prometheus metric
242242
const_labels:
243243
sensor_type: ikea
244+
# When specified, metric value to use if a value cannot be parsed (match cannot be found in the map above, invalid float parsing, expression fails, ...)
245+
# If not specified, parsing error will occur.
246+
error_value: 1
244247
# When specified, enables mapping between string values to metric values.
245248
string_value_mapping:
246249
# A map of string to metric value.
247250
map:
248251
off: 0
249252
low: 0
250-
# Metric value to use if a match cannot be found in the map above.
251-
# If not specified, parsing error will occur.
252-
error_value: 1
253253
# The name of the metric in prometheus
254254
- prom_name: total_light_usage_seconds
255255
# The name of the metric in a MQTT JSON message
@@ -265,15 +265,15 @@ metrics:
265265
# A map of string to string for constant labels. This labels will be attached to every prometheus metric
266266
const_labels:
267267
sensor_type: ikea
268+
# Metric value to use if a value cannot be parsed (match cannot be found in the map above, invalid float parsing, ...)
269+
# If not specified, parsing error will occur.
270+
error_value: 1
268271
# When specified, enables mapping between string values to metric values.
269272
string_value_mapping:
270273
# A map of string to metric value.
271274
map:
272275
off: 0
273276
low: 0
274-
# Metric value to use if a match cannot be found in the map above.
275-
# If not specified, parsing error will occur.
276-
error_value: 1
277277
# Sum up the time the light is on, see the section "Expressions" below.
278278
expression: "value > 0 ? last_result + elapsed.Seconds() : last_result"
279279
# The name of the metric in prometheus

cmd/mqtt2prometheus.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func main() {
8080
logger := mustSetupLogger()
8181
defer logger.Sync() //nolint:errcheck
8282
c := make(chan os.Signal, 1)
83-
cfg, err := config.LoadConfig(*configFlag)
83+
cfg, err := config.LoadConfig(*configFlag, logger)
8484
if err != nil {
8585
logger.Fatal("Could not load config", zap.Error(err))
8686
}

config.yaml.dist

+3-3
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,12 @@ metrics:
8181
# A map of string to string for constant labels. This labels will be attached to every prometheus metric
8282
const_labels:
8383
sensor_type: ikea
84+
# Metric value to use if a value cannot be parsed (match cannot be found in the map above, invalid float parsing, ...)
85+
# If not specified, parsing error will occur.
86+
error_value: 1
8487
# When specified, enables mapping between string values to metric values.
8588
string_value_mapping:
8689
# A map of string to metric value.
8790
map:
8891
off: 0
8992
low: 0
90-
# Metric value to use if a match cannot be found in the map above.
91-
# If not specified, parsing error will occur.
92-
error_value: 1

fuzzing/json_per_topic/fuzz.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ func Fuzz(data []byte) int {
1616
{
1717
PrometheusName: "enabled",
1818
ValueType: "gauge",
19+
ErrorValue: floatP(12333),
1920
StringValueMapping: &config.StringValueMappingConfig{
20-
ErrorValue: floatP(12333),
2121
Map: map[string]float64{
2222
"foo": 112,
2323
"bar": 2,

fuzzing/metric_per_topic/fuzz.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ func Fuzz(data []byte) int {
1717
{
1818
PrometheusName: "enabled",
1919
ValueType: "gauge",
20+
ErrorValue: floatP(12333),
2021
StringValueMapping: &config.StringValueMappingConfig{
21-
ErrorValue: floatP(12333),
2222
Map: map[string]float64{
2323
"foo": 112,
2424
"bar": 2,

hack/dht22.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ metrics:
5757
# A map of string to string for constant labels. This labels will be attached to every prometheus metric
5858
const_labels:
5959
sensor_type: ikea
60+
# Metric value to use if a value cannot be parsed (match cannot be found in the map above, invalid float parsing, ...)
61+
# If not specified, parsing error will occur.
62+
error_value: 1
6063
# When specified, enables mapping between string values to metric values.
6164
string_value_mapping:
6265
# A map of string to metric value.
6366
map:
6467
off: 0
6568
low: 0
66-
# Metric value to use if a match cannot be found in the map above.
67-
# If not specified, parsing error will occur.
68-
error_value: 1

pkg/config/config.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"time"
99

1010
"github.com/prometheus/client_golang/prometheus"
11+
"go.uber.org/zap"
1112
"gopkg.in/yaml.v2"
1213
)
1314

@@ -144,11 +145,14 @@ type MetricConfig struct {
144145
ConstantLabels map[string]string `yaml:"const_labels"`
145146
StringValueMapping *StringValueMappingConfig `yaml:"string_value_mapping"`
146147
MQTTValueScale float64 `yaml:"mqtt_value_scale"`
148+
// ErrorValue is used while error during value parsing
149+
ErrorValue *float64 `yaml:"error_value"`
147150
}
148151

149152
// StringValueMappingConfig defines the mapping from string to float
150153
type StringValueMappingConfig struct {
151-
// ErrorValue is used when no mapping is found in Map
154+
// ErrorValue was used when no mapping is found in Map
155+
// deprecated, a warning will be issued to migrate to metric level
152156
ErrorValue *float64 `yaml:"error_value"`
153157
Map map[string]float64 `yaml:"map"`
154158
}
@@ -170,7 +174,7 @@ func (mc *MetricConfig) PrometheusValueType() prometheus.ValueType {
170174
}
171175
}
172176

173-
func LoadConfig(configFile string) (Config, error) {
177+
func LoadConfig(configFile string, logger *zap.Logger) (Config, error) {
174178
configData, err := ioutil.ReadFile(configFile)
175179
if err != nil {
176180
return Config{}, err
@@ -232,6 +236,13 @@ func LoadConfig(configFile string) (Config, error) {
232236
if m.ForceMonotonicy {
233237
forcesMonotonicy = true
234238
}
239+
240+
if m.StringValueMapping != nil && m.StringValueMapping.ErrorValue != nil {
241+
if m.ErrorValue != nil {
242+
return Config{}, fmt.Errorf("metric %s/%s: cannot set both string_value_mapping.error_value and error_value (string_value_mapping.error_value is deprecated).", m.MQTTName, m.PrometheusName)
243+
}
244+
logger.Warn("string_value_mapping.error_value is deprecated: please use error_value at the metric level.", zap.String("prometheusName", m.PrometheusName), zap.String("MQTTName", m.MQTTName))
245+
}
235246
}
236247
if forcesMonotonicy {
237248
if err := os.MkdirAll(cfg.Cache.StateDir, 0755); err != nil {

pkg/metrics/parser.go

+23-4
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,12 @@ func (p *Parser) parseMetric(cfg *config.MetricConfig, metricID string, value in
179179
floatValue, ok := cfg.StringValueMapping.Map[strValue]
180180
if ok {
181181
metricValue = floatValue
182+
183+
// deprecated, replaced by ErrorValue from the upper level
182184
} else if cfg.StringValueMapping.ErrorValue != nil {
183185
metricValue = *cfg.StringValueMapping.ErrorValue
186+
} else if cfg.ErrorValue != nil {
187+
metricValue = *cfg.ErrorValue
184188
} else {
185189
return Metric{}, fmt.Errorf("got unexpected string data '%s'", strValue)
186190
}
@@ -190,27 +194,42 @@ func (p *Parser) parseMetric(cfg *config.MetricConfig, metricID string, value in
190194
// otherwise try to parse float
191195
floatValue, err := strconv.ParseFloat(strValue, 64)
192196
if err != nil {
193-
return Metric{}, fmt.Errorf("got data with unexpectd type: %T ('%v') and failed to parse to float", value, value)
197+
if cfg.ErrorValue != nil {
198+
metricValue = *cfg.ErrorValue
199+
} else {
200+
return Metric{}, fmt.Errorf("got data with unexpectd type: %T ('%v') and failed to parse to float", value, value)
201+
}
202+
} else {
203+
metricValue = floatValue
194204
}
195-
metricValue = floatValue
196205

197206
}
198207

199208
} else if floatValue, ok := value.(float64); ok {
200209
metricValue = floatValue
210+
} else if cfg.ErrorValue != nil {
211+
metricValue = *cfg.ErrorValue
201212
} else {
202213
return Metric{}, fmt.Errorf("got data with unexpectd type: %T ('%v')", value, value)
203214
}
204215

205216
if cfg.Expression != "" {
206217
if metricValue, err = p.evalExpression(metricID, cfg.Expression, metricValue); err != nil {
207-
return Metric{}, err
218+
if cfg.ErrorValue != nil {
219+
metricValue = *cfg.ErrorValue
220+
} else {
221+
return Metric{}, err
222+
}
208223
}
209224
}
210225

211226
if cfg.ForceMonotonicy {
212227
if metricValue, err = p.enforceMonotonicy(metricID, metricValue); err != nil {
213-
return Metric{}, err
228+
if cfg.ErrorValue != nil {
229+
metricValue = *cfg.ErrorValue
230+
} else {
231+
return Metric{}, err
232+
}
214233
}
215234
}
216235

pkg/metrics/parser_test.go

+31-3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ func TestParser_parseMetric(t *testing.T) {
3939
deviceID string
4040
value interface{}
4141
}
42+
43+
var errorValue float64 = 42.44
44+
4245
tests := []struct {
4346
name string
4447
fields fields
@@ -143,6 +146,32 @@ func TestParser_parseMetric(t *testing.T) {
143146
},
144147
wantErr: true,
145148
},
149+
{
150+
name: "string value failure with errorValue",
151+
fields: fields{
152+
map[string][]*config.MetricConfig{
153+
"temperature": {
154+
{
155+
PrometheusName: "temperature",
156+
ValueType: "gauge",
157+
ErrorValue: &errorValue,
158+
},
159+
},
160+
},
161+
},
162+
args: args{
163+
metricPath: "temperature",
164+
deviceID: "dht22",
165+
value: "12.6.5",
166+
},
167+
want: Metric{
168+
Description: prometheus.NewDesc("temperature", "", []string{"sensor", "topic"}, nil),
169+
ValueType: prometheus.GaugeValue,
170+
Value: errorValue,
171+
IngestTime: testNow(),
172+
Topic: "",
173+
},
174+
},
146175
{
147176
name: "float value",
148177
fields: fields{
@@ -335,8 +364,8 @@ func TestParser_parseMetric(t *testing.T) {
335364
{
336365
PrometheusName: "enabled",
337366
ValueType: "gauge",
367+
ErrorValue: floatP(12333),
338368
StringValueMapping: &config.StringValueMappingConfig{
339-
ErrorValue: floatP(12333),
340369
Map: map[string]float64{
341370
"foo": 112,
342371
"bar": 2,
@@ -392,8 +421,8 @@ func TestParser_parseMetric(t *testing.T) {
392421
{
393422
PrometheusName: "enabled",
394423
ValueType: "gauge",
424+
ErrorValue: floatP(12333),
395425
StringValueMapping: &config.StringValueMappingConfig{
396-
ErrorValue: floatP(12333),
397426
Map: map[string]float64{
398427
"foo": 112,
399428
"bar": 2,
@@ -419,7 +448,6 @@ func TestParser_parseMetric(t *testing.T) {
419448
PrometheusName: "enabled",
420449
ValueType: "gauge",
421450
StringValueMapping: &config.StringValueMappingConfig{
422-
ErrorValue: floatP(12333),
423451
Map: map[string]float64{
424452
"foo": 112,
425453
"bar": 2,

0 commit comments

Comments
 (0)