Spaces:
Running
Running
File size: 1,952 Bytes
aa27d2d 817ad83 aa27d2d 817ad83 aa27d2d 817ad83 aa27d2d 817ad83 aa27d2d 817ad83 aa27d2d 817ad83 aa27d2d 817ad83 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import time
import os
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
from app.core.logger import logger
# Paths that are too noisy to log at INFO β only log if they error
_QUIET_PATHS = frozenset(["/health", "/favicon.ico", "/metrics", "/docs", "/openapi.json", "/redoc"])
class APILoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
start_time = time.perf_counter()
path = request.url.path
method = request.method
try:
response = await call_next(request)
except Exception as exc:
duration_ms = round((time.perf_counter() - start_time) * 1000, 1)
logger.bind(
method=method,
path=path,
status=500,
duration_ms=duration_ms,
).error(f"Unhandled exception on {method} {path} β {type(exc).__name__}: {exc}")
raise
duration_ms = round((time.perf_counter() - start_time) * 1000, 1)
status = response.status_code
# Suppress noisy health-check / static paths unless they error
if path in _QUIET_PATHS and status < 400:
return response
# Route logs by severity so production dashboards can filter cleanly
bound = logger.bind(method=method, path=path, status=status, duration_ms=duration_ms)
if status >= 500:
bound.error(f"{method} {path} β {status} ({duration_ms}ms)")
elif status >= 400:
# 401 on /auth/me is expected background noise β demote to DEBUG
if path == "/auth/me" and status == 401:
bound.debug(f"{method} {path} β {status} ({duration_ms}ms)")
else:
bound.warning(f"{method} {path} β {status} ({duration_ms}ms)")
else:
bound.info(f"{method} {path} β {status} ({duration_ms}ms)")
return response |