diff --git a/pkg/promutil/prometheus.go b/pkg/promutil/prometheus.go index 3f62a1588..66acfde6f 100644 --- a/pkg/promutil/prometheus.go +++ b/pkg/promutil/prometheus.go @@ -13,6 +13,7 @@ package promutil import ( + "regexp" "strings" "time" @@ -105,6 +106,8 @@ var replacer = strings.NewReplacer( "%", "_percent", ) +var metricNumberPrefixRE = regexp.MustCompile(`^\d`) + type PrometheusMetric struct { Name string Labels map[string]string @@ -194,6 +197,11 @@ func PromStringTag(text string, labelsSnakeCase bool) (bool, string) { // sanitize replaces some invalid chars with an underscore func sanitize(text string) string { + // metrics starting with a digit violate the prometheus metric naming convention, so we add an underscore + if metricNumberPrefixRE.MatchString(text) { + text = "_" + text + } + if strings.ContainsAny(text, "“%") { // fallback to the replacer for complex cases: // - '“' is non-ascii rune diff --git a/pkg/promutil/prometheus_test.go b/pkg/promutil/prometheus_test.go index 9e461b4a2..006b65e03 100644 --- a/pkg/promutil/prometheus_test.go +++ b/pkg/promutil/prometheus_test.go @@ -63,6 +63,10 @@ func TestSanitize(t *testing.T) { input: "IHaveA%Sign", output: "IHaveA_percentSign", }, + { + input: "5XXError", + output: "_5XXError", + }, } for _, tc := range testCases {