4.7 KiB
pprof Reference
Enable pprof HTTP Server
Pprof endpoints MUST be protected with basic auth — NEVER expose them publicly. They leak sensitive runtime information (goroutine stacks, memory contents) and can be abused to DoS your service (CPU profiling is expensive). Pprof SHOULD be toggled via a PPROF_ENABLED environment variable.
Quick Setup (Development)
import _ "net/http/pprof"
func main() {
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
// ... rest of app
}
Secure Setup (Production)
For production, protect endpoints with basic auth:
import "net/http/pprof"
func setupPprof(mux *http.ServeMux) {
if os.Getenv("PPROF_ENABLED") != "true" {
return
}
// Protect pprof endpoints with basic auth — never expose unauthenticated
username := os.Getenv("PPROF_USERNAME")
password := os.Getenv("PPROF_PASSWORD")
if username == "" || password == "" {
panic("PPROF_USERNAME and PPROF_PASSWORD must be set when pprof is enabled")
}
auth := basicAuth(username, password)
mux.Handle("/debug/pprof/", auth(http.HandlerFunc(pprof.Index)))
mux.Handle("/debug/pprof/cmdline", auth(http.HandlerFunc(pprof.Cmdline)))
mux.Handle("/debug/pprof/profile", auth(http.HandlerFunc(pprof.Profile)))
mux.Handle("/debug/pprof/symbol", auth(http.HandlerFunc(pprof.Symbol)))
mux.Handle("/debug/pprof/trace", auth(http.HandlerFunc(pprof.Trace)))
slog.Info("pprof endpoints enabled (basic auth required)")
}
// basicAuth wraps an http.Handler with HTTP Basic Authentication.
func basicAuth(username, password string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
u, p, ok := r.BasicAuth()
if !ok || u != username || subtle.ConstantTimeCompare([]byte(p), []byte(password)) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="pprof"`)
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
}
Profile Types
| Profile | Command | What It Shows |
|---|---|---|
| CPU | go tool pprof profile |
Where CPU time is spent |
| Heap | go tool pprof heap |
Memory allocations, live objects |
| Goroutine | go tool pprof goroutine |
Stack traces of all goroutines |
| Block | go tool pprof block |
Blocking operations (needs SetBlockProfileRate) |
| Mutex | go tool pprof mutex |
Lock contention (needs SetMutexProfileFraction) |
| Alloc | go tool pprof -alloc_space heap |
Cumulative allocations (not current heap) |
Capturing Profiles
# CPU profiles SHOULD capture at least 30 seconds for meaningful data (30s default).
# Ensure your HTTP server's request timeout exceeds the capture duration.
curl http://localhost:6060/debug/pprof/profile?seconds=30 > cpu.prof
# Heap snapshot
curl http://localhost:6060/debug/pprof/heap > heap.prof
# Goroutine dump (human-readable)
curl http://localhost:6060/debug/pprof/goroutine?debug=2 > goroutines.txt
# Goroutine profile (for pprof analysis)
curl http://localhost:6060/debug/pprof/goroutine > goroutine.prof
# Go 1.26 experimental goroutine leak profile, only with GOEXPERIMENT=goroutineleakprofile
curl http://localhost:6060/debug/pprof/goroutineleak?debug=2
go tool pprof http://localhost:6060/debug/pprof/goroutineleak
# Mutex contention
curl http://localhost:6060/debug/pprof/mutex > mutex.prof
# Block profile
curl http://localhost:6060/debug/pprof/block > block.prof
Analyzing and Interpreting Profiles
→ See samber/cc-skills-golang@golang-benchmark skill (pprof.md) for interpreting profiles: top, list, peek, common profile patterns (flat vs cum, GC churn, memory leaks), and compiler diagnostics. See also compiler-analysis.md for escape analysis and inlining decisions.
Quick start:
go tool pprof cpu.prof # interactive analysis
go tool pprof -http=:8080 cpu.prof # graphical flamegraph
go tool pprof -base heap1.prof heap2.prof # compare heap snapshots
Remote Profiling (Production)
For production servers, replace localhost:6060 with your server address and use basic auth credentials.
Safety: idle pprof endpoints have low overhead, but profile captures are not free. CPU profiling samples for the requested duration, heap profiles may trigger extra work, and block/mutex profiles add runtime overhead when enabled.
→ See samber/cc-skills-golang@golang-observability skill for continuous profiling with Pyroscope. → See samber/cc-skills-golang@golang-benchmark skill for investigation session setup and Prometheus-based performance tracking.