import time import logging from fastapi import Request, Response from starlette.middleware.base import BaseHTTPMiddleware from starlette.types import ASGIApp # Configure logger logger = logging.getLogger("api_access") logger.setLevel(logging.INFO) handler = logging.StreamHandler() formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) handler.setFormatter(formatter) logger.addHandler(handler) class AccessLoggingMiddleware(BaseHTTPMiddleware): def __init__(self, app: ASGIApp): super().__init__(app) async def dispatch(self, request: Request, call_next): start_time = time.time() client_host = request.client.host if request.client else "unknown" method = request.method url = request.url.path # Process the request try: response = await call_next(request) process_time = (time.time() - start_time) * 1000 status_code = response.status_code log_msg = f"Client: {client_host} | Method: {method} | Path: {url} | Status: {status_code} | Time: {process_time:.2f}ms" if status_code >= 500: logger.error(log_msg) elif status_code >= 400: logger.warning(log_msg) else: logger.info(log_msg) return response except Exception as e: process_time = (time.time() - start_time) * 1000 logger.error(f"Client: {client_host} | Method: {method} | Path: {url} | Error: {str(e)} | Time: {process_time:.2f}ms") raise e