mirror of
https://github.com/prometheus/statsd_exporter.git
synced 2024-11-22 23:41:00 +00:00
Merge pull request #192 from ivanizag/master
Fixes #191: crash on empty metric name
This commit is contained in:
commit
035a309552
3 changed files with 73 additions and 2 deletions
|
@ -280,7 +280,7 @@ type Exporter struct {
|
||||||
|
|
||||||
func escapeMetricName(metricName string) string {
|
func escapeMetricName(metricName string) string {
|
||||||
// If a metric starts with a digit, prepend an underscore.
|
// If a metric starts with a digit, prepend an underscore.
|
||||||
if metricName[0] >= '0' && metricName[0] <= '9' {
|
if len(metricName) > 0 && metricName[0] >= '0' && metricName[0] <= '9' {
|
||||||
metricName = "_" + metricName
|
metricName = "_" + metricName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,6 +333,11 @@ func (b *Exporter) handleEvent(event Event) {
|
||||||
metricName := ""
|
metricName := ""
|
||||||
prometheusLabels := event.Labels()
|
prometheusLabels := event.Labels()
|
||||||
if present {
|
if present {
|
||||||
|
if mapping.Name == "" {
|
||||||
|
log.Debugf("The mapping of '%s' for match '%s' generates an empty metric name", event.MetricName(), mapping.Match)
|
||||||
|
errorEventStats.WithLabelValues("empty_metric_name").Inc()
|
||||||
|
return
|
||||||
|
}
|
||||||
metricName = escapeMetricName(mapping.Name)
|
metricName = escapeMetricName(mapping.Name)
|
||||||
for label, value := range labels {
|
for label, value := range labels {
|
||||||
prometheusLabels[label] = value
|
prometheusLabels[label] = value
|
||||||
|
@ -348,7 +353,7 @@ func (b *Exporter) handleEvent(event Event) {
|
||||||
// will cause the exporter to panic. Instead we will warn and continue to the next event.
|
// will cause the exporter to panic. Instead we will warn and continue to the next event.
|
||||||
if event.Value() < 0.0 {
|
if event.Value() < 0.0 {
|
||||||
log.Debugf("Counter %q is: '%f' (counter must be non-negative value)", metricName, event.Value())
|
log.Debugf("Counter %q is: '%f' (counter must be non-negative value)", metricName, event.Value())
|
||||||
eventStats.WithLabelValues("illegal_negative_counter").Inc()
|
errorEventStats.WithLabelValues("illegal_negative_counter").Inc()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,56 @@ func TestNegativeCounter(t *testing.T) {
|
||||||
close(events)
|
close(events)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
errorCounter := errorEventStats.WithLabelValues("illegal_negative_counter")
|
||||||
|
prev := getTelemetryCounterValue(errorCounter)
|
||||||
|
|
||||||
ex := NewExporter(&mapper.MetricMapper{})
|
ex := NewExporter(&mapper.MetricMapper{})
|
||||||
ex.Listen(events)
|
ex.Listen(events)
|
||||||
|
|
||||||
|
updated := getTelemetryCounterValue(errorCounter)
|
||||||
|
if updated-prev != 1 {
|
||||||
|
t.Fatal("Illegal negative counter error not counted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestEmptyStringMetric validates when a metric name ends up
|
||||||
|
// being the empty string after applying the match replacements
|
||||||
|
// tha we don't panic the Exporter Listener.
|
||||||
|
func TestEmptyStringMetric(t *testing.T) {
|
||||||
|
events := make(chan Events)
|
||||||
|
go func() {
|
||||||
|
c := Events{
|
||||||
|
&CounterEvent{
|
||||||
|
metricName: "foo_bar",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
events <- c
|
||||||
|
close(events)
|
||||||
|
}()
|
||||||
|
|
||||||
|
config := `
|
||||||
|
mappings:
|
||||||
|
- match: .*_bar
|
||||||
|
match_type: regex
|
||||||
|
name: "${1}"
|
||||||
|
`
|
||||||
|
testMapper := &mapper.MetricMapper{}
|
||||||
|
err := testMapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
errorCounter := errorEventStats.WithLabelValues("empty_metric_name")
|
||||||
|
prev := getTelemetryCounterValue(errorCounter)
|
||||||
|
|
||||||
|
ex := NewExporter(testMapper)
|
||||||
|
ex.Listen(events)
|
||||||
|
|
||||||
|
updated := getTelemetryCounterValue(errorCounter)
|
||||||
|
if updated-prev != 1 {
|
||||||
|
t.Fatal("Empty metric name error event not counted")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInvalidUtf8InDatadogTagValue validates robustness of exporter listener
|
// TestInvalidUtf8InDatadogTagValue validates robustness of exporter listener
|
||||||
|
@ -167,6 +215,7 @@ func TestEscapeMetricName(t *testing.T) {
|
||||||
"with😱emoji": "with_emoji",
|
"with😱emoji": "with_emoji",
|
||||||
"with.*.multiple": "with___multiple",
|
"with.*.multiple": "with___multiple",
|
||||||
"test.web-server.foo.bar": "test_web_server_foo_bar",
|
"test.web-server.foo.bar": "test_web_server_foo_bar",
|
||||||
|
"": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
for in, want := range scenarios {
|
for in, want := range scenarios {
|
||||||
|
@ -355,3 +404,12 @@ func labelPairsAsLabels(pairs []*dto.LabelPair) (labels prometheus.Labels) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTelemetryCounterValue(counter prometheus.Counter) float64 {
|
||||||
|
var metric dto.Metric
|
||||||
|
err := counter.Write(&metric)
|
||||||
|
if err != nil {
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
return metric.Counter.GetValue()
|
||||||
|
}
|
||||||
|
|
|
@ -102,6 +102,13 @@ var (
|
||||||
},
|
},
|
||||||
[]string{"type"},
|
[]string{"type"},
|
||||||
)
|
)
|
||||||
|
errorEventStats = prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: "statsd_exporter_events_error_total",
|
||||||
|
Help: "The total number of StatsD events discarded due to errors.",
|
||||||
|
},
|
||||||
|
[]string{"reason"},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -119,4 +126,5 @@ func init() {
|
||||||
prometheus.MustRegister(configLoads)
|
prometheus.MustRegister(configLoads)
|
||||||
prometheus.MustRegister(mappingsCount)
|
prometheus.MustRegister(mappingsCount)
|
||||||
prometheus.MustRegister(conflictingEventStats)
|
prometheus.MustRegister(conflictingEventStats)
|
||||||
|
prometheus.MustRegister(errorEventStats)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue