tsweb/varz: flesh out munging of expvar keys into valid Prometheus metrics

From a problem we hit with how badger registers expvars; it broke
trunkd's exported metrics.

Updates tailscale/corp#1297

Change-Id: I42e1552e25f734c6f521b6e993d57a82849464b2
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2024-03-22 20:01:48 -07:00 committed by Brad Fitzpatrick
parent b104688e04
commit 4992aca6ec
2 changed files with 42 additions and 1 deletions

View File

@ -17,6 +17,8 @@
"strings"
"sync"
"time"
"unicode"
"unicode/utf8"
"tailscale.com/metrics"
"tailscale.com/version"
@ -85,8 +87,29 @@ func prometheusMetric(prefix string, key string) (string, string, string) {
label, key = a, b
}
}
// Convert the metric to a valid Prometheus metric name.
// "Metric names may contain ASCII letters, digits, underscores, and colons.
// It must match the regex [a-zA-Z_:][a-zA-Z0-9_:]*"
mapInvalidMetricRunes := func(r rune) rune {
if r >= 'a' && r <= 'z' ||
r >= 'A' && r <= 'Z' ||
r >= '0' && r <= '9' ||
r == '_' || r == ':' {
return r
}
if r < utf8.RuneSelf && unicode.IsPrint(r) {
return '_'
}
return -1
}
metricName := strings.Map(mapInvalidMetricRunes, prefix+key)
if metricName == "" || unicode.IsDigit(rune(metricName[0])) {
metricName = "_" + metricName
}
d := &prometheusMetricDetails{
Name: strings.ReplaceAll(prefix+key, "-", "_"),
Name: metricName,
Type: typ,
Label: label,
}

View File

@ -43,6 +43,24 @@ func TestVarzHandler(t *testing.T) {
new(expvar.Int),
"# TYPE foo_bar counter\nfoo_bar 0\n",
},
{
"slash_in_metric_name",
"counter_foo/bar",
new(expvar.Int),
"# TYPE foo_bar counter\nfoo_bar 0\n",
},
{
"metric_name_start_digit",
"0abc",
new(expvar.Int),
"# TYPE _0abc counter\n_0abc 0\n",
},
{
"metric_name_have_bogus_bytes",
"abc\x10defügh",
new(expvar.Int),
"# TYPE abcdefgh counter\nabcdefgh 0\n",
},
{
"int_with_type_counter",
"counter_foo",