Fix pprof endpoints when -web.route-prefix or -web.external-url is used (#3054)

Whenever a route prefix is applied, the router prepends the prefix to
the URL path on the request. For most handlers, this is not an issue
because the request's path is only used for routing and is not actually
needed by the handler itself. However, Prometheus delegates the handling
of the /debug/* endpoints to the http.DefaultServeMux which has it's own
routing logic that depends on the url.Path. As a result, whenever a
prefix is applied, the prefixed URL is passed to the DefaultServeMux
which has no awareness of the prefix and returns a 404.

This change fixes the issue by creating a new serveDebug handler which
routes requests /debug/* requests to appropriate net/http/pprof handler
and removing the net/http/pprof import in cmd/prometheus since it is no
longer necessary.

Fixes #2183.
This commit is contained in:
Mark Adams 2017-08-22 18:00:56 -05:00 committed by Julius Volz
parent 32a951ec89
commit 77c816b309
2 changed files with 23 additions and 3 deletions

View file

@ -17,7 +17,6 @@ package main
import (
"flag"
"fmt"
_ "net/http/pprof" // Comment this line to disable pprof endpoint.
"os"
"os/signal"
"runtime/debug"

View file

@ -21,6 +21,7 @@ import (
"io/ioutil"
"net"
"net/http"
"net/http/pprof"
"net/url"
"os"
"path"
@ -226,8 +227,8 @@ func New(o *Options) *Handler {
fmt.Fprintf(w, "This endpoint requires a POST request.\n")
})
router.Get("/debug/*subpath", readyf(http.DefaultServeMux.ServeHTTP))
router.Post("/debug/*subpath", readyf(http.DefaultServeMux.ServeHTTP))
router.Get("/debug/*subpath", readyf(serveDebug))
router.Post("/debug/*subpath", readyf(serveDebug))
router.Get("/-/healthy", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
@ -241,6 +242,26 @@ func New(o *Options) *Handler {
return h
}
func serveDebug(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
subpath := route.Param(ctx, "subpath")
// Based off paths from init() in golang.org/src/net/http/pprof/pprof.go
if subpath == "/pprof/" {
pprof.Index(w, req)
} else if subpath == "/pprof/cmdline" {
pprof.Cmdline(w, req)
} else if subpath == "/pprof/profile" {
pprof.Profile(w, req)
} else if subpath == "/pprof/symbol" {
pprof.Symbol(w, req)
} else if subpath == "/pprof/trace" {
pprof.Trace(w, req)
} else {
http.NotFound(w, req)
}
}
func serveStaticAsset(w http.ResponseWriter, req *http.Request) {
fp := route.Param(req.Context(), "filepath")
fp = filepath.Join("web/ui/static", fp)