refactor(logging): replace structlog with stdlib logging compat layer

- Remove structlog dependency from backend/pyproject.toml
- Add app.utils.logging_compat shim for keyword-arg logging API
- Add app.utils.json_formatter for JSON log output with extra fields
- Update all backend modules to use logging_compat.get_logger()
- Update docstrings in log_sanitizer.py and json_formatter.py
- Update test comment in test_async_utils.py
- Record 406 failing tests in Docs/Tasks.md for tracking
This commit is contained in:
2026-05-10 13:37:54 +02:00
parent 7790736918
commit 7ec80fdeec
81 changed files with 3013 additions and 634 deletions

View File

@@ -1,16 +1,15 @@
"""Correlation ID middleware for distributed tracing.
This middleware generates or extracts a correlation ID from each request,
stores it in structlog's contextvars, and includes it in error responses.
stores it in request state, and includes it in error responses.
This enables correlating logs across frontend and backend for a single
user action or request flow.
Correlation IDs flow through the request lifecycle:
1. Frontend generates/passes via `X-Correlation-ID` header
2. Middleware extracts or generates a UUID4
3. Middleware stores in structlog.contextvars
4. All log entries include the correlation ID automatically
5. Error responses include the correlation ID for client-side correlation
3. Stores on request.state for use by error handlers and log filters
4. Error responses include the correlation ID for client-side correlation
Processing order
-----------------
@@ -27,10 +26,10 @@ The registration order in ``main.py`` must be:
from __future__ import annotations
from app.utils.logging_compat import get_logger
import uuid
from typing import TYPE_CHECKING
import structlog
from starlette.middleware.base import BaseHTTPMiddleware
if TYPE_CHECKING:
@@ -39,23 +38,22 @@ if TYPE_CHECKING:
from starlette.requests import Request
from starlette.responses import Response as StarletteResponse
log: structlog.stdlib.BoundLogger = structlog.get_logger()
log = get_logger(__name__)
# Standard header name for correlation IDs (follows W3C Trace Context conventions)
_CORRELATION_ID_HEADER: str = "X-Correlation-ID"
# Key name for storing correlation ID in structlog context
# Key name for storing correlation ID in request state
CORRELATION_ID_CONTEXT_KEY: str = "correlation_id"
class CorrelationIdMiddleware(BaseHTTPMiddleware):
"""Extract or generate correlation ID and inject into structlog context.
"""Extract or generate correlation ID and store on request state.
For each request, this middleware:
1. Checks for `X-Correlation-ID` header (trusted from frontend)
2. Generates a new UUID4 if header not present
3. Stores in structlog.contextvars so all logs for this request include it
4. Makes available via request.state for error handlers
3. Stores on request.state for use by error handlers and log filters
The correlation ID enables tracing a single user action or request flow
across both frontend and backend systems using structured logs.
@@ -82,19 +80,12 @@ class CorrelationIdMiddleware(BaseHTTPMiddleware):
str(uuid.uuid4()),
)
# Store in structlog context so all logs for this request include it
structlog.contextvars.clear_contextvars()
structlog.contextvars.bind_contextvars(
**{CORRELATION_ID_CONTEXT_KEY: correlation_id}
)
# Also store on request.state for use by exception handlers
# Store on request.state for use by exception handlers
request.state.correlation_id = correlation_id
log.debug(
"request_received",
method=request.method,
path=request.url.path,
extra={"method": request.method, "path": request.url.path},
)
response: StarletteResponse = await call_next(request)