import time import uuid from collections.abc import Awaitable, Callable from fastapi import Request, Response from starlette.middleware.base import BaseHTTPMiddleware from starlette.types import ASGIApp from app.core.logging import get_logger class LoggingMiddleware(BaseHTTPMiddleware): """Middleware for logging HTTP requests and responses.""" def __init__(self, app: ASGIApp) -> None: """Initialize the logging middleware.""" super().__init__(app) self.logger = get_logger(__name__) async def dispatch( self, request: Request, call_next: Callable[[Request], Awaitable[Response]], ) -> Response: """Process the request and log details.""" request_id = str(uuid.uuid4()) start_time = time.time() self.logger.info( "Request started [%s]: %s %s - Client: %s", request_id, request.method, request.url.path, request.client.host if request.client else "unknown", ) try: response = await call_next(request) process_time = time.time() - start_time self.logger.info( "Request completed [%s]: %s %s - Status: %d - Duration: %.3fs", request_id, request.method, request.url.path, response.status_code, process_time, ) response.headers["X-Process-Time"] = str(process_time) except Exception: process_time = time.time() - start_time self.logger.exception( "Request failed [%s]: %s %s - Duration: %.3fs", request_id, request.method, request.url.path, process_time, ) raise else: return response