diff --git a/src/dstack/_internal/server/services/users.py b/src/dstack/_internal/server/services/users.py index 73ceebe0e..35c1fe5b3 100644 --- a/src/dstack/_internal/server/services/users.py +++ b/src/dstack/_internal/server/services/users.py @@ -32,6 +32,7 @@ from dstack._internal.server.services import events from dstack._internal.server.services.locking import get_locker from dstack._internal.server.services.permissions import get_default_permissions +from dstack._internal.server.utils import otel from dstack._internal.server.utils.routers import error_forbidden from dstack._internal.utils import crypto from dstack._internal.utils.common import get_current_datetime, get_or_error, run_async @@ -397,6 +398,7 @@ async def log_in_with_token(session: AsyncSession, token: str) -> Optional[UserM return None if user.token.get_plaintext_or_error() != token: return None + otel.set_current_span_attribute("dstack.user.name", user.name) return user diff --git a/src/dstack/_internal/server/utils/otel/__init__.py b/src/dstack/_internal/server/utils/otel/__init__.py index 1b63bfd41..ee7f831b7 100644 --- a/src/dstack/_internal/server/utils/otel/__init__.py +++ b/src/dstack/_internal/server/utils/otel/__init__.py @@ -3,6 +3,7 @@ if TYPE_CHECKING: from fastapi import FastAPI + from opentelemetry.util.types import AttributeValue from sqlalchemy.ext.asyncio import AsyncEngine try: @@ -54,3 +55,13 @@ def record_task_run(name: str, *, error: bool) -> None: if _task_runs_counter is None: return _task_runs_counter.add(1, {"task": name, "status": "error" if error else "success"}) + + +def set_current_span_attribute(key: str, value: "AttributeValue") -> None: + """ + Sets an attribute on the currently active span. + No-op if OpenTelemetry is not installed or tracing is not configured. + """ + if otel_trace is None: + return + otel_trace.get_current_span().set_attribute(key, value)