README.md

March 24, 2026 Β· View on GitHub

fastapi_profiler

A FastAPI Middleware of joerick/pyinstrument to check your service performance.

Codecov Package version PyPI - Python Version

PyPI - Format Contributions welcome License

πŸ“£ Info

A FastAPI Middleware of pyinstrument to check your service code performance.
Supports per-request profiling, sampling rate control, structured JSON logging, a built-in Web UI Dashboard, per-route profile history, runtime enable/disable, and request statistics aggregation (p95/p99).

πŸ”° Installation

Use uv (recommended)

$ uv add fastapi_profiler

Use pip

$ pip install fastapi_profiler -U

πŸ“ Quick Start

import uvicorn
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi_profiler import PyInstrumentProfilerMiddleware

app = FastAPI()
app.add_middleware(PyInstrumentProfilerMiddleware)

@app.get("/test")
async def normal_request():
    return JSONResponse({"retMsg": "Hello World!"})

if __name__ == "__main__":
    uvicorn.run(app=app, host="0.0.0.0", port=8080, workers=1)

βš™οΈ Configuration Reference

All parameters are passed as keyword arguments to add_middleware().

Core Parameters

ParameterTypeDefaultDescription
server_appFastAPI | NoneNonePass the FastAPI app instance to register a shutdown handler that writes file-based output automatically. Required for html, prof, json, speedscope output types.
profiler_output_typestr"text"Output format. One of "text", "html", "prof", "json", "speedscope".
is_print_each_requestboolTruePrint/log the profile summary after every request.
profiler_intervalfloat0.0001pyinstrument sampling interval in seconds.
async_modestr"enabled"pyinstrument async mode.
html_file_namestr | None"./fastapi-profiler.html"Output file name for html type.
prof_file_namestr | None"./fastapi-profiler.prof"Output file name for prof, json, and speedscope types.
open_in_browserboolFalseAutomatically open the HTML report in a browser on shutdown.
filter_pathslist[str] | NoneNoneList of URL path prefixes to skip profiling entirely (e.g. ["/health", "/metrics"]).

1.5.0 New Parameters

ParameterTypeDefaultDescription
slow_request_threshold_msfloat0Only emit profile output when request duration exceeds this value in milliseconds. 0 means always emit.
profiler_sample_ratefloat1.0Fraction of requests to profile (0.0 – 1.0). Useful for reducing overhead in production.
always_profile_errorsboolTrueAlways profile 5xx responses regardless of profiler_sample_rate or slow_request_threshold_ms.
log_formatstr"text"Log format for request lines. "text" emits a human-readable string; "json" emits a structured JSON object.
max_profiles_per_routeint10Maximum number of ProfileRecord objects to keep in memory per route (rolling window).
enable_dashboardboolFalseMount a built-in Web UI Dashboard with stats and runtime control APIs.
dashboard_pathstr"/__profiler__"URL prefix for the dashboard. Only used when enable_dashboard=True.
enabledboolTrueMaster switch. When False, the middleware passes all requests through without profiling. Controllable at runtime via the /config API.

πŸš€ Usage Examples

Basic β€” print profile to stdout

app.add_middleware(PyInstrumentProfilerMiddleware)

Output to HTML file

Each sampled request that exceeds the slow-request threshold writes (or overwrites) the configured HTML file with the latest call-tree profile:

app.add_middleware(
    PyInstrumentProfilerMiddleware,
    server_app=app,
    profiler_output_type="html",
    is_print_each_request=False,
    html_file_name="./fastapi-profiler.html",
)

Note: The file is updated on every qualifying request; it always contains the most recent profile. Use profiler_output_type="text" with is_print_each_request=True if you want a log entry per request.

Sampling rate β€” profile only 10% of requests

app.add_middleware(
    PyInstrumentProfilerMiddleware,
    server_app=app,
    profiler_sample_rate=0.1,   # Profile ~10% of requests
)

Always profile errors β€” even with sampling disabled

app.add_middleware(
    PyInstrumentProfilerMiddleware,
    server_app=app,
    profiler_sample_rate=0.0,   # Normally profile nothing...
    always_profile_errors=True, # ...but always profile 5xx responses
)

Slow-request threshold β€” only profile requests slower than 200 ms

app.add_middleware(
    PyInstrumentProfilerMiddleware,
    server_app=app,
    slow_request_threshold_ms=200,
)

Structured JSON logging

import logging
logging.basicConfig(level=logging.INFO, format="%(message)s")

app.add_middleware(
    PyInstrumentProfilerMiddleware,
    server_app=app,
    log_format="json",  # {"logger": "fastapi_profiler", "method": "GET", ...}
)

Built-in Web UI Dashboard

app.add_middleware(
    PyInstrumentProfilerMiddleware,
    server_app=app,
    enable_dashboard=True,
    dashboard_path="/__profiler__",
    filter_paths=["/__profiler__"],  # Exclude dashboard from stats
)

After starting the server, open http://localhost:8080/__profiler__ in your browser.

Dashboard API endpoints

MethodPathDescription
GET/__profiler__/HTML dashboard UI
GET/__profiler__/statsJSON stats for all routes
POST/__profiler__/resetClear all collected stats
POST/__profiler__/configUpdate runtime configuration

/stats response shape:

{
  "enabled": true,
  "sample_rate": 1.0,
  "slow_request_threshold_ms": 0,
  "routes": [
    {
      "path": "/test",
      "method": "GET",
      "count": 42,
      "error_count": 1,
      "avg_duration_ms": 3.14,
      "p95_duration_ms": 8.20,
      "p99_duration_ms": 12.50,
      "max_duration_ms": 15.00
    }
  ]
}

/config request body (all fields optional):

{
  "enabled": false,
  "sample_rate": 0.5,
  "slow_request_threshold_ms": 200
}

Runtime enable/disable

app.add_middleware(
    PyInstrumentProfilerMiddleware,
    server_app=app,
    enabled=True,
    enable_dashboard=True,
)

Toggle profiling without restarting the server:

# Disable profiling
curl -X POST http://localhost:8080/__profiler__/config \
     -H "Content-Type: application/json" \
     -d '{"enabled": false}'

# Re-enable with 50% sampling
curl -X POST http://localhost:8080/__profiler__/config \
     -H "Content-Type: application/json" \
     -d '{"enabled": true, "sample_rate": 0.5}'

Per-route profile history

app.add_middleware(
    PyInstrumentProfilerMiddleware,
    server_app=app,
    enable_dashboard=True,
    max_profiles_per_route=20,  # Keep last 20 profiles per route
)

All features combined

app.add_middleware(
    PyInstrumentProfilerMiddleware,
    server_app=app,
    # Sampling & thresholds
    profiler_sample_rate=0.5,
    always_profile_errors=True,
    slow_request_threshold_ms=100,
    # Logging
    is_print_each_request=True,
    log_format="json",
    # Dashboard & stats
    enable_dashboard=True,
    dashboard_path="/__profiler__",
    max_profiles_per_route=10,
    filter_paths=["/__profiler__"],
    # Runtime toggle
    enabled=True,
)

πŸ“‚ Example Files

FileDescription
fastapi_example.pyMinimal setup β€” print to stdout
fastapi_to_html_example.pyOutput to HTML file
fastapi_to_json_example.pyOutput to JSON file
fastapi_to_prof_example.pyOutput to .prof file
fastapi_to_speedscope_example.pyOutput to Speedscope JSON
fastapi_sampling_rate_example.pySampling rate control
fastapi_always_profile_errors_example.pyAlways profile 5xx errors
fastapi_json_logging_example.pyStructured JSON logging
fastapi_stats_dashboard_example.pyWeb UI Dashboard + stats API
fastapi_per_route_history_example.pyPer-route profile history
fastapi_runtime_toggle_example.pyRuntime enable/disable
fastapi_full_features_example.pyAll features combined

⛏ Development

Setup

This project is managed with uv. Install all dependencies (including dev tools) with:

$ uv sync --group dev

Common Tasks

Use make (Linux/macOS) or make.bat (Windows) for common development tasks:

CommandDescription
make installInstall all dependencies
make lintRun ruff + flake8 linters
make typecheckRun ty type checker
make testRun pytest with coverage
make checkRun lint + typecheck + test
make buildBuild distribution packages
make publishBuild and publish to PyPI
make cleanRemove build artifacts

Code Style

This project uses the following tools to ensure code quality:

  • ruff β€” fast linter and formatter
  • flake8 β€” style guide enforcement
  • ty β€” fast Python type checker
  • Codecov β€” test coverage reporting

CI

GitHub Actions runs the full matrix across Python 3.8 – 3.14 on Ubuntu, macOS, and Windows.

πŸ’‘ Author

πŸ“ƒ License

MIT Β©sunhailin-Leo