summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAnton Tolchanov <anton@tailscale.com>2024-10-26 18:15:46 +0100
committerAnton Tolchanov <anton@tailscale.com>2024-10-26 18:15:46 +0100
commit160ba1f82c3d145aed12b9c0f6200980def0a0d1 (patch)
treea3f1544a11ffae8821c62d47b23b2a5ee616f61f
parentfd77965f23a317cb6f7bc53d585ace2c771d5b48 (diff)
downloadtailscale-knyar/metricshelp.tar.xz
tailscale-knyar/metricshelp.zip
metrics: do not export MultiLabelMap with no variablesknyar/metricshelp
Avoid exporting HELP and TYPE of metrics that don't yet have any variables. Updates tailscale/corp#22075 Signed-off-by: Anton Tolchanov <anton@tailscale.com>
-rw-r--r--metrics/multilabelmap.go11
-rw-r--r--metrics/multilabelmap_test.go28
2 files changed, 23 insertions, 16 deletions
diff --git a/metrics/multilabelmap.go b/metrics/multilabelmap.go
index 223a55a75..7f5abee44 100644
--- a/metrics/multilabelmap.go
+++ b/metrics/multilabelmap.go
@@ -104,6 +104,15 @@ func (v *MultiLabelMap[T]) String() string {
// WritePrometheus writes v to w in Prometheus exposition format.
// The name argument is the metric name.
func (v *MultiLabelMap[T]) WritePrometheus(w io.Writer, name string) {
+ v.mu.RLock()
+ defer v.mu.RUnlock()
+
+ if len(v.sorted) == 0 {
+ // Do not print TYPE and HELP if we don't actually have any variables
+ // in the map.
+ return
+ }
+
if v.Type != "" {
io.WriteString(w, "# TYPE ")
io.WriteString(w, name)
@@ -118,8 +127,6 @@ func (v *MultiLabelMap[T]) WritePrometheus(w io.Writer, name string) {
io.WriteString(w, v.Help)
io.WriteString(w, "\n")
}
- v.mu.RLock()
- defer v.mu.RUnlock()
for _, kv := range v.sorted {
io.WriteString(w, name)
diff --git a/metrics/multilabelmap_test.go b/metrics/multilabelmap_test.go
index 195696234..d42fce320 100644
--- a/metrics/multilabelmap_test.go
+++ b/metrics/multilabelmap_test.go
@@ -17,6 +17,15 @@ type L2 struct {
Bar string `prom:"bar"`
}
+func checkRendered[T comparable](t *testing.T, m *MultiLabelMap[T], name, wantRendered string) {
+ t.Helper()
+ var buf bytes.Buffer
+ m.WritePrometheus(&buf, name)
+ if got := buf.String(); got != wantRendered {
+ t.Errorf("prometheus output = %q; want %q", got, wantRendered)
+ }
+}
+
func TestMultilabelMap(t *testing.T) {
m := new(MultiLabelMap[L2])
m.Add(L2{"a", "b"}, 2)
@@ -45,19 +54,14 @@ func TestMultilabelMap(t *testing.T) {
t.Errorf("got %q; want %q", g, w)
}
- var buf bytes.Buffer
- m.WritePrometheus(&buf, "metricname")
- const want = `metricname{foo="a",bar="a"} 1
+ checkRendered(t, m, "metricname", `metricname{foo="a",bar="a"} 1
metricname{foo="a",bar="b"} 2
metricname{foo="b",bar="b"} 3
metricname{foo="b",bar="c"} 4
metricname{foo="sf",bar="sf"} 5.5
metricname{foo="sfunc",bar="sfunc"} 3
metricname{foo="si",bar="si"} 5
-`
- if got := buf.String(); got != want {
- t.Errorf("promtheus output = %q; want %q", got, want)
- }
+`)
m.Delete(L2{"b", "b"})
@@ -95,16 +99,12 @@ func TestMultiLabelMapTypes(t *testing.T) {
m := new(MultiLabelMap[LabelTypes])
m.Type = "counter"
m.Help = "some good stuff"
+ checkRendered(t, m, "metricname", "")
m.Add(LabelTypes{"a", true, -1, 2}, 3)
- var buf bytes.Buffer
- m.WritePrometheus(&buf, "metricname")
- const want = `# TYPE metricname counter
+ checkRendered(t, m, "metricname", `# TYPE metricname counter
# HELP metricname some good stuff
metricname{s="a",b="true",i="-1",u="2"} 3
-`
- if got := buf.String(); got != want {
- t.Errorf("got %q; want %q", got, want)
- }
+`)
writeAllocs := testing.AllocsPerRun(1000, func() {
m.WritePrometheus(io.Discard, "test")