// 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" ) // OmitPromethusMetrics, if set to true, makes Handler not include native // Prometheus metrics. // // This is useful in some specific cases where the built-in Prometheus // collectors have poor performance characteristics. var OmitPromethusMetrics bool // 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 { if OmitPromethusMetrics { return nil } 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 }