diff --git a/app/api/dependencies.py b/app/api/dependencies.py index d188e37..434401a 100644 --- a/app/api/dependencies.py +++ b/app/api/dependencies.py @@ -9,7 +9,6 @@ from app.core.db import get_db_session from app.core.enums import UserStatus from app.core.config import get_settings -from app.core.logging import set_request_user_email from app.core.security import decode_access_token from app.repositories.user import UserRepository from app.schemas.auth import TokenPayload, UserRead @@ -52,7 +51,6 @@ def get_current_user( span = trace.get_current_span() span.set_attribute("user.id", str(resolved.id)) span.set_attribute("user.email", resolved.email) - set_request_user_email(resolved.email) return resolved diff --git a/app/core/logging.py b/app/core/logging.py index 70d3b52..2109946 100644 --- a/app/core/logging.py +++ b/app/core/logging.py @@ -4,17 +4,9 @@ import json import logging -from contextvars import ContextVar from opentelemetry import trace -_user_email_var: ContextVar[str] = ContextVar('user_email', default='') - - -def set_request_user_email(email: str) -> None: - _user_email_var.set(email) - - _SKIP_ATTRS = frozenset(( "name", "msg", "args", "levelname", "levelno", "pathname", "filename", "module", "exc_info", @@ -41,7 +33,14 @@ def format(self, record: logging.LogRecord) -> str: "span_id": format(ctx.span_id, "016x") if ctx.is_valid else "", } - user_email = _user_email_var.get() + # Read off the span's attributes rather than a ContextVar: the + # dependency that resolves the user runs in FastAPI's threadpool + # (sync def), and contextvars.copy_context() there means any + # ContextVar.set() inside it never propagates back to the request's + # context. The span object itself is shared by reference across + # that boundary, so attribute mutations on it are visible everywhere. + attributes = getattr(span, "attributes", None) or {} + user_email = attributes.get("user.email") if user_email: entry["user_email"] = user_email