feat: add profiling middleware and update README for performance profiling

This commit is contained in:
grillazz
2026-02-05 11:46:45 +01:00
parent 59b673ed0e
commit 9353c4b3f8
8 changed files with 107 additions and 3 deletions

View File

@@ -13,7 +13,12 @@ router = APIRouter()
@router.get("/redis", status_code=status.HTTP_200_OK)
async def redis_check(request: Request):
async def redis_check(
request: Request,
pyprofile: Annotated[
bool, Query(description="Enable profiler for this request")
] = False,
):
"""
Endpoint to check Redis health and retrieve server information.
@@ -23,6 +28,7 @@ async def redis_check(request: Request):
Args:
request (Request): The incoming HTTP request.
pyprofile (bool, optional): If `True`, enables the profiler for this request. Defaults to `False`.
Returns:
dict or None: Returns Redis server information as a dictionary if successful,

View File

@@ -6,6 +6,8 @@ from fastapi import Depends, FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from rotoger import get_logger
from starlette.middleware import Middleware
from starlette.middleware.gzip import GZipMiddleware
from app.api.health import router as health_router
from app.api.ml import router as ml_router
@@ -15,6 +17,7 @@ from app.api.stuff import router as stuff_router
from app.api.user import router as user_router
from app.config import settings as global_settings
from app.exception_handlers import register_exception_handlers
from app.middleware.profiler import ProfilingMiddleware
from app.redis import get_redis
from app.services.auth import AuthBearer
@@ -44,11 +47,18 @@ async def lifespan(app: FastAPI):
await app.postgres_pool.close()
middleware = [
Middleware(GZipMiddleware),
Middleware(ProfilingMiddleware),
]
def create_app() -> FastAPI:
app = FastAPI(
title="Stuff And Nonsense API",
version="1.22.0",
lifespan=lifespan,
middleware=middleware,
)
app.include_router(stuff_router)
app.include_router(nonsense_router)
@@ -68,6 +78,8 @@ def create_app() -> FastAPI:
# Register exception handlers
register_exception_handlers(app)
@app.get("/index", response_class=HTMLResponse)
def get_index(request: Request):
return templates.TemplateResponse("index.html", {"request": request})

View File

View File

@@ -0,0 +1,28 @@
from __future__ import annotations
from fastapi import Request
from pyinstrument import Profiler
from starlette.middleware.base import (
BaseHTTPMiddleware,
RequestResponseEndpoint,
)
from starlette.responses import HTMLResponse, Response
class ProfilingMiddleware(BaseHTTPMiddleware):
async def dispatch(
self, request: Request, call_next: RequestResponseEndpoint
) -> Response:
if request.query_params.get("pyprofile") == "true":
profiler = Profiler(interval=0.001, async_mode="enabled")
profiler.start()
await call_next(request)
profiler.stop()
return HTMLResponse(
profiler.output_html(),
headers={"Content-Disposition": "attachment; filename=profile.html"},
)
return await call_next(request)