Go

How do you expose pprof in a production service, and what are the security and design gotchas?

Question 369MediumGo 1.22 to 1.25

Importing net/http/pprof for its side effect registers handlers under /debug/pprof/ on http.DefaultServeMux. The gotcha: if your public API server also uses DefaultServeMux, you've just exposed profiling (and goroutine stacks, command line, heap contents) to the internet. The fix is to serve pprof on a separate, internal-only listener.

import (
    "log"
    "net/http"
    "net/http/pprof"
)

func startDebugServer() {
    mux := http.NewServeMux()
    mux.HandleFunc("/debug/pprof/", pprof.Index)
    mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
    mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
    mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
    mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
    go func() {
        // bind to localhost / internal interface only
        log.Println(http.ListenAndServe("127.0.0.1:6060", mux))
    }()
}

Then: go tool pprof -http=:8080 http://127.0.0.1:6060/debug/pprof/profile?seconds=30. Named profiles (heap, goroutine, block, mutex, allocs, threadcreate) are served by pprof.Index. Interviewer is looking for: awareness of the DefaultServeMux leak, that CPU profiling has low overhead (~a few %) and is safe to run in prod on demand, and that block/mutex profiles are off by default.

More on Performance, Profiling & Testing

All 38 Performance, Profiling & Testing questions