Skip to main content

Overview

The pprof middleware exposes Go’s built-in profiling endpoints for performance analysis and debugging. It integrates the standard net/http/pprof package with Mizu.

Installation

import "github.com/go-mizu/mizu/middlewares/pprof"

Quick Start

app := mizu.New()

// Expose pprof endpoints at /debug/pprof
app.Use(pprof.New())

Configuration

OptionTypeDefaultDescription
Prefixstring"/debug/pprof"URL prefix for pprof endpoints

Endpoints

PathDescription
/debug/pprof/Index page with all profiles
/debug/pprof/cmdlineCommand line arguments
/debug/pprof/profileCPU profile (30s default)
/debug/pprof/symbolSymbol lookup
/debug/pprof/traceExecution trace
/debug/pprof/heapHeap memory profile
/debug/pprof/goroutineGoroutine stack traces
/debug/pprof/blockBlocking profile
/debug/pprof/mutexMutex contention profile
/debug/pprof/allocsMemory allocations
/debug/pprof/threadcreateThread creation profile

Examples

Basic Usage

app := mizu.New()

// Add pprof middleware
app.Use(pprof.New())

// Access at http://localhost:8080/debug/pprof/

Custom Prefix

app.Use(pprof.WithOptions(pprof.Options{
    Prefix: "/internal/profiling",
}))

// Access at http://localhost:8080/internal/profiling/

Protected Pprof

// Create a sub-app for admin routes
admin := app.Group("/admin")

// Add authentication
admin.Use(basicauth.New(basicauth.Options{
    Users: map[string]string{
        "admin": "secret",
    },
}))

// Add pprof to admin group
admin.Use(pprof.WithOptions(pprof.Options{
    Prefix: "/admin/pprof",
}))

Conditional Pprof

// Only enable in development
if os.Getenv("ENV") == "development" {
    app.Use(pprof.New())
}

IP Restricted

// Only allow from localhost
app.Use(ipfilter.WithOptions(ipfilter.Options{
    Whitelist: []string{"127.0.0.1", "::1"},
    PathPrefix: "/debug/pprof",
}))

app.Use(pprof.New())

Using the Profiles

CPU Profile

Capture a 30-second CPU profile:
go tool pprof http://localhost:8080/debug/pprof/profile
Or with a custom duration:
curl "http://localhost:8080/debug/pprof/profile?seconds=60" > cpu.prof
go tool pprof cpu.prof

Heap Profile

go tool pprof http://localhost:8080/debug/pprof/heap

Goroutine Dump

curl http://localhost:8080/debug/pprof/goroutine?debug=2

Execution Trace

curl "http://localhost:8080/debug/pprof/trace?seconds=5" > trace.out
go tool trace trace.out

Memory Allocations

go tool pprof http://localhost:8080/debug/pprof/allocs

Common Pprof Commands

Inside go tool pprof:
# Top functions by CPU/memory
top 10

# View call graph
web

# List function source
list <function_name>

# Show flamegraph (web view)
web

API Reference

func New() mizu.Middleware
func WithOptions(opts Options) mizu.Middleware

Technical Details

The pprof middleware integrates Go’s standard net/http/pprof package with Mizu’s middleware system. Here’s how it works:

Implementation Architecture

The middleware uses a path-based routing strategy to handle different profiling endpoints:
  1. Path Matching: The middleware checks if the incoming request path matches the configured prefix (default: /debug/pprof)
  2. Pass-through: If the path doesn’t match, the request is passed to the next middleware in the chain
  3. Subpath Routing: For matching paths, the middleware extracts the subpath and routes to the appropriate pprof handler

Handler Routing Logic

  • Index Page (/ or empty subpath): Displays the pprof index using pprof.Index()
  • Special Handlers: Four endpoints have dedicated handlers:
    • /cmdline: Command line invocation using pprof.Cmdline()
    • /profile: CPU profiling using pprof.Profile()
    • /symbol: Symbol lookup using pprof.Symbol()
    • /trace: Execution tracing using pprof.Trace()
  • Named Profiles: All other subpaths are treated as named profiles (heap, goroutine, block, mutex, allocs, threadcreate) and handled by pprof.Handler(name)

Prefix Normalization

The middleware automatically normalizes the prefix by removing trailing slashes to ensure consistent path matching regardless of how the prefix is configured.

Request Flow

Request -> Path Check -> Match Prefix? -> No -> Next Middleware
                              |
                             Yes
                              |
                       Extract Subpath -> Route to Handler -> Serve Profile

Security Warning

Pprof endpoints can expose sensitive information about your application. In production:
  1. Use authentication
  2. Restrict by IP address
  3. Use a separate admin port
  4. Or disable entirely
// Production-safe setup
if os.Getenv("ENABLE_PPROF") == "true" {
    app.Use(ipfilter.WithOptions(ipfilter.Options{
        Whitelist: []string{"10.0.0.0/8"},
        PathPrefix: "/debug/pprof",
    }))
    app.Use(pprof.New())
}

Best Practices

  • Never expose pprof publicly in production
  • Use authentication for protected access
  • Enable only when debugging is needed
  • Use execution traces sparingly (high overhead)
  • CPU profiles should be short (30-60 seconds)

Testing

The pprof middleware includes comprehensive test coverage to ensure all endpoints and configurations work correctly:
Test CaseDescriptionExpected Behavior
TestNew/index pageTests the pprof index page at /debug/pprof/Returns HTTP 200 and contains “pprof” in response body
TestNew/cmdlineTests the command line endpointReturns HTTP 200 with command line arguments
TestNew/symbolTests the symbol lookup endpointReturns HTTP 200 for symbol queries
TestNew/heap profileTests the heap memory profile endpointReturns HTTP 200 with heap profile data
TestNew/goroutine profileTests the goroutine stack traces endpointReturns HTTP 200 with goroutine information
TestNew/non-pprof pathTests that non-pprof paths pass through to next handlerReturns “home” text from the application route
TestWithOptions_CustomPrefixTests custom prefix configuration (/profiling)Returns HTTP 200 when accessing index at custom prefix
TestWithOptions_PrefixWithTrailingSlashTests prefix normalization with trailing slashReturns HTTP 200, correctly handles trailing slash in prefix

Test Coverage

The test suite validates:
  • All major pprof endpoints (index, cmdline, symbol, heap, goroutine)
  • Middleware pass-through for non-matching paths
  • Custom prefix configuration
  • Prefix normalization (trailing slash handling)