- api/helpers: audit, is_authority, get_org_name, paginate_query, require_roles - services/ws_manager: connect(ws, user_id, org_id), send_to_user, send_to_org, broadcast, make_notification(event, entity_type, entity_id, **extra) - services/risk_scheduler: setup_scheduler (заглушка/APScheduler) - services/email_service: email_service.send (заглушка) - middleware/request_logger: RequestLoggerMiddleware - core/rate_limit: RateLimitMiddleware (in-memory, RATE_LIMIT_PER_MINUTE, /health в обход) - api/routes/ws_notifications: WebSocket /ws/notifications?user_id=&org_id= Co-authored-by: Cursor <cursoragent@cursor.com>
22 lines
958 B
Python
22 lines
958 B
Python
"""Request logging middleware."""
|
|
import logging, time
|
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
from starlette.requests import Request
|
|
|
|
logger = logging.getLogger("klg.requests")
|
|
|
|
class RequestLoggerMiddleware(BaseHTTPMiddleware):
|
|
async def dispatch(self, request: Request, call_next):
|
|
start = time.time()
|
|
if request.url.path in ("/api/v1/health", "/api/v1/metrics"):
|
|
return await call_next(request)
|
|
response = await call_next(request)
|
|
ms = (time.time() - start) * 1000
|
|
logger.info("%s %s %d %.1fms", request.method, request.url.path, response.status_code, ms)
|
|
# Audit log regulator access
|
|
if "/regulator" in str(request.url.path):
|
|
logger.info("REGULATOR_ACCESS: %s %s from user=%s",
|
|
request.method, request.url.path, getattr(request.state, "user_id", "-"))
|
|
response.headers["X-Response-Time"] = f"{ms:.1f}ms"
|
|
return response
|