tsweb: also support LabelMaps from expvar.Map, without metrics
We want to use tsweb to format Prometheus-style metrics from our temporary golang.org/x/net/http2 fork, but we don't want http2 to depend on the tailscale.com module to use the concrete type tailscale.com/metrics.LabelMap. Instead, let a expvar.Map be used instead of it's annotated sufficiently in its name. Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
5f45d8f8e6
commit
3700cf9ea4
|
@ -364,18 +364,25 @@ func VarzHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
var dump func(prefix string, kv expvar.KeyValue)
|
var dump func(prefix string, kv expvar.KeyValue)
|
||||||
dump = func(prefix string, kv expvar.KeyValue) {
|
dump = func(prefix string, kv expvar.KeyValue) {
|
||||||
name := prefix + kv.Key
|
key := kv.Key
|
||||||
|
|
||||||
var typ string
|
var typ string
|
||||||
|
var label string
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(kv.Key, "gauge_"):
|
case strings.HasPrefix(kv.Key, "gauge_"):
|
||||||
typ = "gauge"
|
typ = "gauge"
|
||||||
name = prefix + strings.TrimPrefix(kv.Key, "gauge_")
|
key = strings.TrimPrefix(kv.Key, "gauge_")
|
||||||
|
|
||||||
case strings.HasPrefix(kv.Key, "counter_"):
|
case strings.HasPrefix(kv.Key, "counter_"):
|
||||||
typ = "counter"
|
typ = "counter"
|
||||||
name = prefix + strings.TrimPrefix(kv.Key, "counter_")
|
key = strings.TrimPrefix(kv.Key, "counter_")
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(key, "labelmap_") {
|
||||||
|
key = strings.TrimPrefix(key, "labelmap_")
|
||||||
|
if i := strings.Index(key, "_"); i != -1 {
|
||||||
|
label, key = key[:i], key[i+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name := prefix + key
|
||||||
|
|
||||||
switch v := kv.Value.(type) {
|
switch v := kv.Value.(type) {
|
||||||
case *expvar.Int:
|
case *expvar.Int:
|
||||||
|
@ -422,6 +429,15 @@ func VarzHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
v.Do(func(kv expvar.KeyValue) {
|
v.Do(func(kv expvar.KeyValue) {
|
||||||
fmt.Fprintf(w, "%s{%s=%q} %v\n", name, v.Label, kv.Key, kv.Value)
|
fmt.Fprintf(w, "%s{%s=%q} %v\n", name, v.Label, kv.Key, kv.Value)
|
||||||
})
|
})
|
||||||
|
case *expvar.Map:
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(w, "# skipping expvar.Map %q with incomplete metadata: label %q, Prometheus type %q\n", name, label, typ)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expvarDo(func(kv expvar.KeyValue) {
|
expvarDo(func(kv expvar.KeyValue) {
|
||||||
|
|
|
@ -343,7 +343,7 @@ func TestVarzHandler(t *testing.T) {
|
||||||
"# TYPE s_bar counter\ns_bar 2\n# TYPE s_foo counter\ns_foo 1\n",
|
"# TYPE s_bar counter\ns_bar 2\n# TYPE s_foo counter\ns_foo 1\n",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"metrics_set_TODO_guage_type",
|
"metrics_set_TODO_gauge_type",
|
||||||
"gauge_s", // TODO(bradfitz): arguably a bug; should pass down type
|
"gauge_s", // TODO(bradfitz): arguably a bug; should pass down type
|
||||||
&metrics.Set{
|
&metrics.Set{
|
||||||
Map: *(func() *expvar.Map {
|
Map: *(func() *expvar.Map {
|
||||||
|
@ -375,7 +375,7 @@ func TestVarzHandler(t *testing.T) {
|
||||||
"# skipping expvar \"x\" (Go type expvar.Func returning float64) with undeclared Prometheus type\n",
|
"# skipping expvar \"x\" (Go type expvar.Func returning float64) with undeclared Prometheus type\n",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label_map",
|
"metrics_label_map",
|
||||||
"counter_m",
|
"counter_m",
|
||||||
&metrics.LabelMap{
|
&metrics.LabelMap{
|
||||||
Label: "label",
|
Label: "label",
|
||||||
|
@ -389,6 +389,28 @@ func TestVarzHandler(t *testing.T) {
|
||||||
},
|
},
|
||||||
"# TYPE m counter\nm{label=\"bar\"} 2\nm{label=\"foo\"} 1\n",
|
"# TYPE m counter\nm{label=\"bar\"} 2\nm{label=\"foo\"} 1\n",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"expvar_label_map",
|
||||||
|
"counter_labelmap_keyname_m",
|
||||||
|
func() *expvar.Map {
|
||||||
|
m := new(expvar.Map)
|
||||||
|
m.Init()
|
||||||
|
m.Add("foo", 1)
|
||||||
|
m.Add("bar", 2)
|
||||||
|
return m
|
||||||
|
}(),
|
||||||
|
"# TYPE m counter\nm{keyname=\"bar\"} 2\nm{keyname=\"foo\"} 1\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expvar_label_map_malformed",
|
||||||
|
"counter_labelmap_lackslabel",
|
||||||
|
func() *expvar.Map {
|
||||||
|
m := new(expvar.Map)
|
||||||
|
m.Init()
|
||||||
|
return m
|
||||||
|
}(),
|
||||||
|
"# skipping expvar.Map \"lackslabel\" with incomplete metadata: label \"\", Prometheus type \"counter\"\n",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue