feat(api): add request logging middleware
Why: - Need visibility into API usage and performance - Need to track request method, path, status, and duration - Helps debugging production issues Changes: - Added RequestLoggingMiddleware class - Logs at appropriate level (INFO/WARNING/ERROR) - Non-invasive, no logic changes
This commit is contained in:
35
src/main.py
35
src/main.py
@@ -1,6 +1,10 @@
|
|||||||
"""FastAPI app factory. Composes all domain routers and middleware."""
|
"""FastAPI app factory. Composes all domain routers and middleware."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
|
from starlette.requests import Request
|
||||||
|
from starlette.responses import Response
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
@@ -23,6 +27,34 @@ logging.basicConfig(
|
|||||||
datefmt="%Y-%m-%d %H:%M:%S",
|
datefmt="%Y-%m-%d %H:%M:%S",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# ── Request Logging Middleware ─────────────────────────────────────
|
||||||
|
|
||||||
|
class RequestLoggingMiddleware(BaseHTTPMiddleware):
|
||||||
|
"""Log request method, path, status code, and duration."""
|
||||||
|
|
||||||
|
async def dispatch(self, request: Request, call_next) -> Response:
|
||||||
|
start = time.time()
|
||||||
|
method = request.method
|
||||||
|
path = request.url.path
|
||||||
|
|
||||||
|
response = await call_next(request)
|
||||||
|
|
||||||
|
duration = (time.time() - start) * 1000 # ms
|
||||||
|
status = response.status_code
|
||||||
|
|
||||||
|
# Log at appropriate level
|
||||||
|
if status >= 500:
|
||||||
|
logger.error("%s %s -> %d (%.1fms)", method, path, status, duration)
|
||||||
|
elif status >= 400:
|
||||||
|
logger.warning("%s %s -> %d (%.1fms)", method, path, status, duration)
|
||||||
|
else:
|
||||||
|
logger.info("%s %s -> %d (%.1fms)", method, path, status, duration)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
def create_app() -> FastAPI:
|
def create_app() -> FastAPI:
|
||||||
"""Create and configure the FastAPI application.
|
"""Create and configure the FastAPI application.
|
||||||
@@ -48,6 +80,9 @@ def create_app() -> FastAPI:
|
|||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Request logging
|
||||||
|
app.add_middleware(RequestLoggingMiddleware)
|
||||||
|
|
||||||
# Register exception handlers
|
# Register exception handlers
|
||||||
app.add_exception_handler(ChunkingError, chunking_exception_handler)
|
app.add_exception_handler(ChunkingError, chunking_exception_handler)
|
||||||
app.add_exception_handler(BenchmarkError, benchmark_exception_handler)
|
app.add_exception_handler(BenchmarkError, benchmark_exception_handler)
|
||||||
|
|||||||
Reference in New Issue
Block a user