| """ |
| Request timing middleware. |
| Emits one structured log line per request with method, path, status, and duration. |
| """ |
| import logging |
| import time |
|
|
| from starlette.middleware.base import BaseHTTPMiddleware |
| from starlette.requests import Request |
|
|
| logger = logging.getLogger(__name__) |
|
|
|
|
| class TimingMiddleware(BaseHTTPMiddleware): |
| async def dispatch(self, request: Request, call_next): |
| start = time.perf_counter() |
| response = await call_next(request) |
| duration_ms = round((time.perf_counter() - start) * 1000, 2) |
| logger.info( |
| "request completed", |
| extra={ |
| "method": request.method, |
| "path": request.url.path, |
| "status_code": response.status_code, |
| "duration_ms": duration_ms, |
| "client_ip": request.client.host if request.client else None, |
| }, |
| ) |
| return response |
|
|