summaryrefslogtreecommitdiffhomepage
path: root/tsweb/debug.go
diff options
context:
space:
mode:
Diffstat (limited to 'tsweb/debug.go')
-rw-r--r--tsweb/debug.go44
1 files changed, 37 insertions, 7 deletions
diff --git a/tsweb/debug.go b/tsweb/debug.go
index 9e6ce4df4..ac1981999 100644
--- a/tsweb/debug.go
+++ b/tsweb/debug.go
@@ -14,7 +14,7 @@ import (
"os"
"runtime"
- "tailscale.com/tsweb/promvarz"
+ "tailscale.com/feature"
"tailscale.com/tsweb/varz"
"tailscale.com/version"
)
@@ -34,8 +34,14 @@ type DebugHandler struct {
kvs []func(io.Writer) // output one <li>...</li> each, see KV()
urls []string // one <li>...</li> block with link each
sections []func(io.Writer, *http.Request) // invoked in registration order prior to outputting </body>
+ title string // title displayed on index page
}
+// PrometheusHandler is an optional hook to enable native Prometheus
+// support in the debug handler. It is disabled by default. Import the
+// tailscale.com/tsweb/promvarz package to enable this feature.
+var PrometheusHandler feature.Hook[func(*DebugHandler)]
+
// Debugger returns the DebugHandler registered on mux at /debug/,
// creating it if necessary.
func Debugger(mux *http.ServeMux) *DebugHandler {
@@ -44,14 +50,19 @@ func Debugger(mux *http.ServeMux) *DebugHandler {
return d
}
ret := &DebugHandler{
- mux: mux,
+ mux: mux,
+ title: fmt.Sprintf("%s debug", version.CmdName()),
}
mux.Handle("/debug/", ret)
ret.KVFunc("Uptime", func() any { return varz.Uptime() })
ret.KV("Version", version.Long())
ret.Handle("vars", "Metrics (Go)", expvar.Handler())
- ret.Handle("varz", "Metrics (Prometheus)", http.HandlerFunc(promvarz.Handler))
+ if PrometheusHandler.IsSet() {
+ PrometheusHandler.Get()(ret)
+ } else {
+ ret.Handle("varz", "Metrics (Prometheus)", http.HandlerFunc(varz.Handler))
+ }
// pprof.Index serves everything that runtime/pprof.Lookup finds:
// goroutine, threadcreate, heap, allocs, block, mutex
@@ -85,7 +96,7 @@ func (d *DebugHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
AddBrowserHeaders(w)
f := func(format string, args ...any) { fmt.Fprintf(w, format, args...) }
- f("<html><body><h1>%s debug</h1><ul>", version.CmdName())
+ f("<html><body><h1>%s</h1><ul>", html.EscapeString(d.title))
for _, kv := range d.kvs {
kv(w)
}
@@ -103,14 +114,20 @@ func (d *DebugHandler) handle(slug string, handler http.Handler) string {
return href
}
-// Handle registers handler at /debug/<slug> and creates a descriptive
-// entry in /debug/ for it.
+// Handle registers handler at /debug/<slug> and adds a link to it
+// on /debug/ with the provided description.
func (d *DebugHandler) Handle(slug, desc string, handler http.Handler) {
href := d.handle(slug, handler)
d.URL(href, desc)
}
-// HandleSilent registers handler at /debug/<slug>. It does not create
+// Handle registers handler at /debug/<slug> and adds a link to it
+// on /debug/ with the provided description.
+func (d *DebugHandler) HandleFunc(slug, desc string, handler http.HandlerFunc) {
+ d.Handle(slug, desc, handler)
+}
+
+// HandleSilent registers handler at /debug/<slug>. It does not add
// a descriptive entry in /debug/ for it. This should be used
// sparingly, for things that need to be registered but would pollute
// the list of debug links.
@@ -118,6 +135,14 @@ func (d *DebugHandler) HandleSilent(slug string, handler http.Handler) {
d.handle(slug, handler)
}
+// HandleSilent registers handler at /debug/<slug>. It does not add
+// a descriptive entry in /debug/ for it. This should be used
+// sparingly, for things that need to be registered but would pollute
+// the list of debug links.
+func (d *DebugHandler) HandleSilentFunc(slug string, handler http.HandlerFunc) {
+ d.HandleSilent(slug, handler)
+}
+
// KV adds a key/value list item to /debug/.
func (d *DebugHandler) KV(k string, v any) {
val := html.EscapeString(fmt.Sprintf("%v", v))
@@ -149,6 +174,11 @@ func (d *DebugHandler) Section(f func(w io.Writer, r *http.Request)) {
d.sections = append(d.sections, f)
}
+// Title sets the title at the top of the debug page.
+func (d *DebugHandler) Title(title string) {
+ d.title = title
+}
+
func gcHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("running GC...\n"))
if f, ok := w.(http.Flusher); ok {