Ver Fonte

tsweb/varz: only export numeric expvar.Map values

Currently the expvar exporter attempts to write expvar.String, which
breaks the Prometheus metric page.

Updates tailscale/corp#36552

Signed-off-by: Anton Tolchanov <[email protected]>
Anton Tolchanov há 3 semanas atrás
pai
commit
826fd544cc
2 ficheiros alterados com 55 adições e 2 exclusões
  1. 12 2
      tsweb/varz/varz.go
  2. 43 0
      tsweb/varz/varz_test.go

+ 12 - 2
tsweb/varz/varz.go

@@ -245,11 +245,21 @@ func writePromExpVar(w io.Writer, prefix string, kv expvar.KeyValue) {
 		if label != "" && typ != "" {
 			fmt.Fprintf(w, "# TYPE %s %s\n", name, typ)
 			v.Do(func(kv expvar.KeyValue) {
-				fmt.Fprintf(w, "%s{%s=%q} %v\n", name, label, kv.Key, kv.Value)
+				switch kv.Value.(type) {
+				case *expvar.Int, *expvar.Float:
+					fmt.Fprintf(w, "%s{%s=%q} %v\n", name, label, kv.Key, kv.Value)
+				default:
+					fmt.Fprintf(w, "# skipping %q expvar map key %q with unknown value type %T\n", name, kv.Key, kv.Value)
+				}
 			})
 		} else {
 			v.Do(func(kv expvar.KeyValue) {
-				fmt.Fprintf(w, "%s_%s %v\n", name, kv.Key, kv.Value)
+				switch kv.Value.(type) {
+				case *expvar.Int, *expvar.Float:
+					fmt.Fprintf(w, "%s_%s %v\n", name, kv.Key, kv.Value)
+				default:
+					fmt.Fprintf(w, "# skipping %q expvar map key %q with unknown value type %T\n", name, kv.Key, kv.Value)
+				}
 			})
 		}
 	}

+ 43 - 0
tsweb/varz/varz_test.go

@@ -180,6 +180,43 @@ func TestVarzHandler(t *testing.T) {
 			},
 			"# TYPE m counter\nm{label=\"bar\"} 2\nm{label=\"foo\"} 1\n",
 		},
+		{
+			"metrics_label_map_float",
+			"float_map",
+			func() *expvar.Map {
+				m := new(expvar.Map)
+				m.Init()
+				f := new(expvar.Float)
+				f.Set(1.5)
+				m.Set("a", f)
+				return m
+			}(),
+			"float_map_a 1.5\n",
+		},
+		{
+			"metrics_label_map_int",
+			"int_map",
+			func() *expvar.Map {
+				m := new(expvar.Map)
+				m.Init()
+				f := new(expvar.Int)
+				f.Set(55)
+				m.Set("a", f)
+				return m
+			}(),
+			"int_map_a 55\n",
+		},
+		{
+			"metrics_label_map_string",
+			"string_map",
+			func() *expvar.Map {
+				m := new(expvar.Map)
+				m.Init()
+				m.Set("a", expvar.NewString("foo"))
+				return m
+			}(),
+			"# skipping \"string_map\" expvar map key \"a\" with unknown value type *expvar.String\n",
+		},
 		{
 			"metrics_label_map_untyped",
 			"control_save_config",
@@ -298,6 +335,12 @@ foo_foo_b 1
 api_status_code 42
 			`) + "\n",
 		},
+		{
+			"string_expvar_is_not_exported",
+			"foo_string",
+			new(expvar.String),
+			"# skipping expvar \"foo_string\" (Go type *expvar.String) with undeclared Prometheus type\n",
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {