Table of contents
Part of nurago, a collection of independent Go packages for backend services.
import "github.com/tecnickcom/nurago/pkg/profiling"
Exposes Go’s net/http/pprof profiles through httprouter, as one handler on one wildcard route.
router.HandlerFunc(http.MethodGet, "/pprof/*option", profiling.PProfHandler)
The problem with importing net/http/pprof
The standard package registers its handlers on http.DefaultServeMux as an import side effect. That is convenient for a program serving from the default mux and a nuisance otherwise: it mutates global state on import, binds the paths to /debug/pprof/, and does not help at all with a router that is not the default mux.
The usual workaround is to register each handler individually against your router, which means naming Index, Cmdline, Profile, Symbol, Trace, and then a route for every named runtime profile.
PProfHandler reads httprouter’s *option wildcard parameter and dispatches internally. One route covers everything, http.DefaultServeMux is untouched, and the mount prefix is yours: /pprof/*option, /debug/pprof/*option, or anything else.
Named profiles are forwarded to pprof.Handler, so profiles the Go runtime adds later work with no change here.
What is served
/pprof/ index page listing available profiles
/pprof/cmdline the running program's command line
/pprof/profile CPU profile, 30 seconds or ?seconds=N
/pprof/symbol symbol lookup for program counters
/pprof/trace execution trace, ?seconds=N
/pprof/<name> any named runtime profile: heap, goroutine, allocs,
block, mutex, threadcreate
Three mounting requirements
These come from the package’s own caveats, and each has a visible failure mode.
The wildcard must be named option. The handler reads that parameter by name. Registering /pprof/*path compiles, serves, and returns the index page for every request, including /pprof/heap.
The route must be exempt from the request timeout. profile and trace block for their full duration by design; a 30-second CPU profile under a 30-second request timeout is truncated or killed. httpserver disables the request timeout on the pprof route for exactly this reason.
Keep httprouter’s trailing-slash redirect enabled. The index page links to the other profiles with relative URLs like heap?debug=1, which only resolve correctly from a path ending in a slash. httprouter’s RedirectTrailingSlash sends /pprof to /pprof/ and keeps those links working.
Keep it off the public internet
pprof exposes the internals of a running process: heap contents, full goroutine stacks with function names and arguments, CPU traces. That is enough to map your code and, in a heap dump, to recover data the process was holding.
There is also a denial-of-service edge. /pprof/profile?seconds=3600 ties up a profiling slot for an hour, and CPU profiling costs real overhead while it runs.
Mount this on an internal or administrative listener that is not publicly reachable, and put authentication in front of it. httpserver supports a separate listener for operational routes for this purpose, and the same applies to the metrics endpoint from prometheus.
Dependencies
Reaches github.com/julienschmidt/httprouter.
Links
- Reference documentation
- Source code
- Mounting and timeouts: httpserver
- The security guide: /docs/security/
- All nurago packages