File size: 1,867 Bytes
ac5551d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
50
51
52
53
54
55
56
57
58
"""
middleware/logging_middleware.py — Structured request/response logging.
Attaches a trace_id to every request, logs timing, method, path, status.
"""
from __future__ import annotations

import time
import uuid
from typing import Callable

from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware

from observability.logger import audit, get_logger, log_system_event

log = get_logger("http")


class RequestLoggingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        trace_id = str(uuid.uuid4())[:8]
        request.state.trace_id = trace_id
        start = time.perf_counter()

        log_system_event(
            level="info",
            message=f"API Request: {request.method} {request.url.path}",
            source="gateway",
            payload={"trace_id": trace_id, "query": str(request.url.query)}
        )

        response = await call_next(request)
        duration_ms = (time.perf_counter() - start) * 1000

        log_system_event(
            level="info" if response.status_code < 400 else "error",
            message=f"API Response: {response.status_code} ({duration_ms:.1f}ms)",
            source="gateway",
            payload={"trace_id": trace_id, "status": response.status_code, "latency_ms": round(duration_ms, 2)}
        )

        response.headers["X-Trace-Id"] = trace_id
        response.headers["X-Response-Time"] = f"{duration_ms:.1f}ms"

        # Audit slow requests
        if duration_ms > 200:
            await audit(
                "slow_request",
                payload={
                    "path": request.url.path,
                    "duration_ms": round(duration_ms, 2),
                    "trace_id": trace_id,
                },
                level="warning",
            )

        return response