import json import logging import time from datetime import datetime, timezone from starlette.middleware.base import BaseHTTPMiddleware from starlette.requests import Request logger = logging.getLogger("aivideo") class JsonFormatter(logging.Formatter): def format(self, record: logging.LogRecord) -> str: payload = { "timestamp": datetime.now(timezone.utc).isoformat(), "level": record.levelname.lower(), "message": record.getMessage(), } extra = getattr(record, "extra_payload", None) if isinstance(extra, dict): payload.update(extra) return json.dumps(payload, ensure_ascii=False) def configure_logging() -> None: handler = logging.StreamHandler() handler.setFormatter(JsonFormatter()) logger.setLevel(logging.INFO) logger.handlers.clear() logger.addHandler(handler) logger.propagate = False class LoggingMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): started = time.perf_counter() response = await call_next(request) duration_ms = round((time.perf_counter() - started) * 1000, 2) logger.info( "http_request", extra={ "extra_payload": { "request_id": getattr(request.state, "request_id", ""), "method": request.method, "path": request.url.path, "status_code": response.status_code, "duration_ms": duration_ms, } }, ) return response