2026-07-09 18:31:29 +00:00
|
|
|
import logging
|
2026-07-09 20:10:10 +00:00
|
|
|
import time
|
|
|
|
|
from collections.abc import Awaitable, Callable
|
|
|
|
|
|
|
|
|
|
from starlette.requests import Request
|
|
|
|
|
from starlette.responses import Response
|
|
|
|
|
|
|
|
|
|
request_logger = logging.getLogger("guidecity.http")
|
2026-07-09 18:31:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def configure_logging(level: int = logging.INFO) -> None:
|
|
|
|
|
logging.basicConfig(
|
|
|
|
|
level=level,
|
|
|
|
|
format="%(asctime)s %(levelname)s %(name)s %(message)s",
|
|
|
|
|
)
|
2026-07-09 20:10:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
async def log_requests(
|
|
|
|
|
request: Request,
|
|
|
|
|
call_next: Callable[[Request], Awaitable[Response]],
|
|
|
|
|
) -> Response:
|
|
|
|
|
"""Logs method/path/status/duration for every request handled by the app."""
|
|
|
|
|
start = time.perf_counter()
|
|
|
|
|
try:
|
|
|
|
|
response = await call_next(request)
|
|
|
|
|
except Exception:
|
|
|
|
|
duration_ms = (time.perf_counter() - start) * 1000
|
|
|
|
|
request_logger.exception(
|
|
|
|
|
"%s %s -> unhandled exception (%.1fms)", request.method, request.url.path, duration_ms
|
|
|
|
|
)
|
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
duration_ms = (time.perf_counter() - start) * 1000
|
|
|
|
|
request_logger.info(
|
|
|
|
|
"%s %s -> %d (%.1fms)", request.method, request.url.path, response.status_code, duration_ms
|
|
|
|
|
)
|
|
|
|
|
return response
|