diff --git a/exporter.go b/exporter.go index 7a6adb4..7fe55c5 100644 --- a/exporter.go +++ b/exporter.go @@ -280,7 +280,7 @@ type Exporter struct { func escapeMetricName(metricName string) string { // 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 } @@ -333,6 +333,10 @@ func (b *Exporter) handleEvent(event Event) { metricName := "" prometheusLabels := event.Labels() if present { + if mapping.Name == "" { + log.Debugf("The mapping for match \"%v\" generates an empty metric name.", mapping.Match) + return + } metricName = escapeMetricName(mapping.Name) for label, value := range labels { prometheusLabels[label] = value diff --git a/exporter_test.go b/exporter_test.go index f353c96..cb31724 100644 --- a/exporter_test.go +++ b/exporter_test.go @@ -56,6 +56,38 @@ func TestNegativeCounter(t *testing.T) { ex.Listen(events) } +// 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) + } + + ex := NewExporter(testMapper) + ex.Listen(events) +} + // TestInvalidUtf8InDatadogTagValue validates robustness of exporter listener // against datadog tags with invalid tag values. // It sends the same tags first with a valid value, then with an invalid one. @@ -167,6 +199,7 @@ func TestEscapeMetricName(t *testing.T) { "with😱emoji": "with_emoji", "with.*.multiple": "with___multiple", "test.web-server.foo.bar": "test_web_server_foo_bar", + "": "", } for in, want := range scenarios {