mirror of
https://github.com/prometheus/statsd_exporter.git
synced 2024-06-27 00:50:32 +00:00
Merge pull request #197 from bakins/escapeMetricName-performance
Increase escapeMetricName performance
This commit is contained in:
commit
ece9385f22
29
exporter.go
29
exporter.go
|
@ -21,7 +21,6 @@ import (
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -42,8 +41,6 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
illegalCharsRE = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
|
||||||
|
|
||||||
hash = fnv.New64a()
|
hash = fnv.New64a()
|
||||||
strBuf bytes.Buffer // Used for hashing.
|
strBuf bytes.Buffer // Used for hashing.
|
||||||
intBuf = make([]byte, 8)
|
intBuf = make([]byte, 8)
|
||||||
|
@ -311,15 +308,35 @@ type Exporter struct {
|
||||||
labelValues map[string]map[uint64]*LabelValues
|
labelValues map[string]map[uint64]*LabelValues
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace invalid characters in the metric name with "_"
|
||||||
|
// Valid characters are a-z, A-Z, 0-9, and _
|
||||||
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 len(metricName) > 0 && metricName[0] >= '0' && metricName[0] <= '9' {
|
if len(metricName) > 0 && metricName[0] >= '0' && metricName[0] <= '9' {
|
||||||
metricName = "_" + metricName
|
metricName = "_" + metricName
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace all illegal metric chars with underscores.
|
// this is an character replacement method optimized for this limited
|
||||||
metricName = illegalCharsRE.ReplaceAllString(metricName, "_")
|
// use case. It is much faster than using a regex.
|
||||||
return metricName
|
out := make([]byte, len(metricName))
|
||||||
|
j := 0
|
||||||
|
for _, c := range metricName {
|
||||||
|
// check if the rune is valid for a metric name
|
||||||
|
// and replace it if it is not.
|
||||||
|
// As only certain ASCII characters are valid in metric names,
|
||||||
|
// we can use a byte.
|
||||||
|
if (c >= 'a' && c <= 'z') ||
|
||||||
|
(c >= 'A' && c <= 'Z') ||
|
||||||
|
(c >= '0' && c <= '9') {
|
||||||
|
out[j] = byte(c)
|
||||||
|
} else {
|
||||||
|
out[j] = byte('_')
|
||||||
|
}
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(out[:j])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen handles all events sent to the given channel sequentially. It
|
// Listen handles all events sent to the given channel sequentially. It
|
||||||
|
|
|
@ -506,3 +506,24 @@ func getTelemetryCounterValue(counter prometheus.Counter) float64 {
|
||||||
}
|
}
|
||||||
return metric.Counter.GetValue()
|
return metric.Counter.GetValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkEscapeMetricName(b *testing.B) {
|
||||||
|
scenarios := []string{
|
||||||
|
"clean",
|
||||||
|
"0starts_with_digit",
|
||||||
|
"with_underscore",
|
||||||
|
"with.dot",
|
||||||
|
"with😱emoji",
|
||||||
|
"with.*.multiple",
|
||||||
|
"test.web-server.foo.bar",
|
||||||
|
"",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
b.Run(s, func(b *testing.B) {
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
escapeMetricName(s)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue