mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 21:27:31 +00:00
tsweb: move varz handler(s) into separate modules
This splits Prometheus metric handlers exposed by tsweb into two modules: - `varz.Handler` exposes Prometheus metrics generated by our expvar converter; - `promvarz.Handler` combines our expvar-converted metrics and native Prometheus metrics. By default, tsweb will use the promvarz handler, however users can keep using only the expvar converter. Specifically, `tailscaled` now uses `varz.Handler` explicitly, which avoids a dependency on the (heavyweight) Prometheus client. Updates https://github.com/tailscale/corp/issues/10205 Signed-off-by: Anton Tolchanov <anton@tailscale.com>
This commit is contained in:

committed by
Anton Tolchanov

parent
c153e6ae2f
commit
8546ff98fb
48
tsweb/promvarz/promvarz.go
Normal file
48
tsweb/promvarz/promvarz.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package promvarz combines Prometheus metrics exported by our expvar converter
|
||||
// (tsweb/varz) with metrics exported by the official Prometheus client.
|
||||
package promvarz
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/expfmt"
|
||||
"tailscale.com/tsweb/varz"
|
||||
)
|
||||
|
||||
// Handler returns Prometheus metrics exported by our expvar converter
|
||||
// and the official Prometheus client.
|
||||
func Handler(w http.ResponseWriter, r *http.Request) {
|
||||
if err := gatherNativePrometheusMetrics(w); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
varz.Handler(w, r)
|
||||
}
|
||||
|
||||
// gatherNativePrometheusMetrics writes metrics from the default
|
||||
// metric registry in text format.
|
||||
func gatherNativePrometheusMetrics(w http.ResponseWriter) error {
|
||||
enc := expfmt.NewEncoder(w, expfmt.FmtText)
|
||||
mfs, err := prometheus.DefaultGatherer.Gather()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not gather metrics from DefaultGatherer: %w", err)
|
||||
}
|
||||
|
||||
for _, mf := range mfs {
|
||||
if err := enc.Encode(mf); err != nil {
|
||||
return fmt.Errorf("could not encode metric %v: %w", mf, err)
|
||||
}
|
||||
}
|
||||
if closer, ok := enc.(expfmt.Closer); ok {
|
||||
if err := closer.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
35
tsweb/promvarz/promvarz_test.go
Normal file
35
tsweb/promvarz/promvarz_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
package promvarz
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prometheus/client_golang/prometheus/testutil"
|
||||
)
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
test1 := expvar.NewInt("gauge_promvarz_test_expvar")
|
||||
test1.Set(42)
|
||||
test2 := promauto.NewGauge(prometheus.GaugeOpts{Name: "promvarz_test_native"})
|
||||
test2.Set(4242)
|
||||
|
||||
svr := httptest.NewServer(http.HandlerFunc(Handler))
|
||||
defer svr.Close()
|
||||
|
||||
want := `
|
||||
# TYPE promvarz_test_expvar gauge
|
||||
promvarz_test_expvar 42
|
||||
# TYPE promvarz_test_native gauge
|
||||
promvarz_test_native 4242
|
||||
`
|
||||
if err := testutil.ScrapeAndCompare(svr.URL, strings.NewReader(want), "promvarz_test_expvar", "promvarz_test_native"); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user