diff --git a/prometheus/prometheus.go b/prometheus/prometheus.go
index d8221fb..5b2eeb4 100644
--- a/prometheus/prometheus.go
+++ b/prometheus/prometheus.go
@@ -6,7 +6,6 @@ package prometheus
 import (
 	"fmt"
 	"log"
-	"regexp"
 	"strings"
 	"sync"
 	"time"
@@ -248,15 +247,15 @@ func initCounters(m *sync.Map, counters []CounterDefinition, help map[string]str
 	return
 }
 
-var forbiddenChars = regexp.MustCompile("[ .=\\-/]")
+var forbiddenCharsReplacer = strings.NewReplacer(" ", "_", ".", "_", "=", "_", "-", "_", "/", "_")
 
 func flattenKey(parts []string, labels []metrics.Label) (string, string) {
 	key := strings.Join(parts, "_")
-	key = forbiddenChars.ReplaceAllString(key, "_")
+	key = forbiddenCharsReplacer.Replace(key)
 
 	hash := key
 	for _, label := range labels {
-		hash += fmt.Sprintf(";%s=%s", label.Name, label.Value)
+		hash += ";" + label.Name + "=" + label.Value
 	}
 
 	return key, hash
diff --git a/prometheus/prometheus_test.go b/prometheus/prometheus_test.go
index 321a7b9..f857367 100644
--- a/prometheus/prometheus_test.go
+++ b/prometheus/prometheus_test.go
@@ -367,3 +367,86 @@ func TestMetricSinkInterface(t *testing.T) {
 	var pps *PrometheusPushSink
 	_ = metrics.MetricSink(pps)
 }
+
+func Test_flattenKey(t *testing.T) {
+	testCases := []struct {
+		name               string
+		inputParts         []string
+		inputLabels        []metrics.Label
+		expectedOutputKey  string
+		expectedOutputHash string
+	}{
+		{
+			name:       "no replacement needed",
+			inputParts: []string{"my", "example", "metric"},
+			inputLabels: []metrics.Label{
+				{Name: "foo", Value: "bar"},
+				{Name: "baz", Value: "buz"},
+			},
+			expectedOutputKey:  "my_example_metric",
+			expectedOutputHash: "my_example_metric;foo=bar;baz=buz",
+		},
+		{
+			name:       "key with whitespace",
+			inputParts: []string{" my ", " example ", " metric "},
+			inputLabels: []metrics.Label{
+				{Name: "foo", Value: "bar"},
+				{Name: "baz", Value: "buz"},
+			},
+			expectedOutputKey:  "_my___example___metric_",
+			expectedOutputHash: "_my___example___metric_;foo=bar;baz=buz",
+		},
+		{
+			name:       "key with dot",
+			inputParts: []string{".my.", ".example.", ".metric."},
+			inputLabels: []metrics.Label{
+				{Name: "foo", Value: "bar"},
+				{Name: "baz", Value: "buz"},
+			},
+			expectedOutputKey:  "_my___example___metric_",
+			expectedOutputHash: "_my___example___metric_;foo=bar;baz=buz",
+		},
+		{
+			name:       "key with dash",
+			inputParts: []string{"-my-", "-example-", "-metric-"},
+			inputLabels: []metrics.Label{
+				{Name: "foo", Value: "bar"},
+				{Name: "baz", Value: "buz"},
+			},
+			expectedOutputKey:  "_my___example___metric_",
+			expectedOutputHash: "_my___example___metric_;foo=bar;baz=buz",
+		},
+		{
+			name:       "key with forward slash",
+			inputParts: []string{"/my/", "/example/", "/metric/"},
+			inputLabels: []metrics.Label{
+				{Name: "foo", Value: "bar"},
+				{Name: "baz", Value: "buz"},
+			},
+			expectedOutputKey:  "_my___example___metric_",
+			expectedOutputHash: "_my___example___metric_;foo=bar;baz=buz",
+		},
+		{
+			name:       "key with all restricted",
+			inputParts: []string{"/my-", ".example ", "metric"},
+			inputLabels: []metrics.Label{
+				{Name: "foo", Value: "bar"},
+				{Name: "baz", Value: "buz"},
+			},
+			expectedOutputKey:  "_my___example__metric",
+			expectedOutputHash: "_my___example__metric;foo=bar;baz=buz",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(b *testing.T) {
+			actualKey, actualHash := flattenKey(tc.inputParts, tc.inputLabels)
+			if actualKey != tc.expectedOutputKey {
+				t.Fatalf("expected key %s, got %s", tc.expectedOutputKey, actualKey)
+			}
+			if actualHash != tc.expectedOutputHash {
+				t.Fatalf("expected hash %s, got %s", tc.expectedOutputHash, actualHash)
+			}
+		})
+	}
+}