diff --git a/metrics/multilabelmap.go b/metrics/multilabelmap.go index 325e9856f..223a55a75 100644 --- a/metrics/multilabelmap.go +++ b/metrics/multilabelmap.go @@ -97,12 +97,8 @@ type KeyValue[T comparable] struct { } func (v *MultiLabelMap[T]) String() string { - var sb strings.Builder - sb.WriteString("MultiLabelMap:\n") - v.Do(func(kv KeyValue[T]) { - fmt.Fprintf(&sb, "\t%v: %v\n", kv.Key, kv.Value) - }) - return sb.String() + // NOTE: This has to be valid JSON because it's used by expvar. + return `"MultiLabelMap"` } // WritePrometheus writes v to w in Prometheus exposition format. diff --git a/metrics/multilabelmap_test.go b/metrics/multilabelmap_test.go index b53e15ec8..195696234 100644 --- a/metrics/multilabelmap_test.go +++ b/metrics/multilabelmap_test.go @@ -5,6 +5,7 @@ package metrics import ( "bytes" + "encoding/json" "expvar" "fmt" "io" @@ -129,3 +130,21 @@ func BenchmarkMultiLabelWriteAllocs(b *testing.B) { m.WritePrometheus(w, "test") } } + +func TestMultiLabelMapExpvar(t *testing.T) { + m := new(MultiLabelMap[L2]) + m.Add(L2{"a", "b"}, 2) + m.Add(L2{"b", "c"}, 4) + + em := new(expvar.Map) + em.Set("multi", m) + + // Ensure that the String method is valid JSON to ensure that it can be + // used by expvar. + encoded := []byte(em.String()) + if !json.Valid(encoded) { + t.Fatalf("invalid JSON: %s", encoded) + } + + t.Logf("em = %+v", em) +}