Skip to content

Commit

Permalink
Merge pull request #138 from jrasell/jrasell/f-improve-prom-flatten-k…
Browse files Browse the repository at this point in the history
…ey-perf

prometheus: improve flatten key performance.
  • Loading branch information
banks authored Sep 8, 2022
2 parents 129ee86 + 2a21e9d commit b6d5c86
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 4 deletions.
7 changes: 3 additions & 4 deletions prometheus/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package prometheus
import (
"fmt"
"log"
"regexp"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -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
Expand Down
83 changes: 83 additions & 0 deletions prometheus/prometheus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
})
}
}

0 comments on commit b6d5c86

Please sign in to comment.