Skip to content

Commit 85b7092

Browse files
committed
Add user tracking to OTLP span attributes + restore guide
- Extract user_id/user_name at top level (available for both Langfuse & OTLP) - Add enduser.id, user.id, user.name to OTLP span attributes - Enables user filtering/querying in OTLP traces (via span attributes) - Keep nice Langfuse SDK traces (generations UI, cost dashboards) User column won't populate in Langfuse UI (Langfuse doesn't extract from span attributes), but user info is available in OTLP trace metadata for custom queries/dashboards/parsing. Signed-off-by: sallyom <somalley@redhat.com>
1 parent b6459b4 commit 85b7092

File tree

1 file changed

+22
-10
lines changed

1 file changed

+22
-10
lines changed

components/runners/claude-code-runner/wrapper.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ async def run(self):
191191
async def _run_claude_agent_sdk(self, prompt: str):
192192
"""Execute the Claude Code SDK with the given prompt."""
193193
try:
194+
# Extract user context for observability (used by both Langfuse and OTLP)
195+
user_id = os.getenv('USER_ID', '').strip()
196+
user_name = os.getenv('USER_NAME', '').strip()
197+
194198
# Initialize Langfuse for observability if configured
195199
langfuse_client = None
196200
langfuse_session_span = None
@@ -204,10 +208,6 @@ async def _run_claude_agent_sdk(self, prompt: str):
204208
host=os.getenv('LANGFUSE_HOST')
205209
)
206210

207-
# Extract user context for observability
208-
user_id = os.getenv('USER_ID', '').strip()
209-
user_name = os.getenv('USER_NAME', '').strip()
210-
211211
# Start a span for this session (Langfuse SDK 3.x)
212212
langfuse_session_span = langfuse_client.start_as_current_span(
213213
name="claude_agent_session",
@@ -302,16 +302,28 @@ async def _run_claude_agent_sdk(self, prompt: str):
302302
# Get tracer (works whether we just set it or it was already set)
303303
otel_tracer = trace.get_tracer(__name__)
304304

305-
# Start session span
305+
# Start session span with user tracking
306+
span_attributes = {
307+
"session.id": self.context.session_id,
308+
"namespace": self.context.get_env('AGENTIC_SESSION_NAMESPACE', 'unknown'),
309+
"prompt.length": len(prompt),
310+
}
311+
312+
# Add user attributes for custom queries/dashboards
313+
if user_id:
314+
span_attributes["enduser.id"] = user_id # OpenTelemetry semantic convention
315+
span_attributes["user.id"] = user_id # Alternative attribute name
316+
if user_name:
317+
span_attributes["user.name"] = user_name
318+
306319
otel_span = otel_tracer.start_span(
307320
"claude_agent_session",
308-
attributes={
309-
"session.id": self.context.session_id,
310-
"namespace": self.context.get_env('AGENTIC_SESSION_NAMESPACE', 'unknown'),
311-
"prompt.length": len(prompt),
312-
}
321+
attributes=span_attributes
313322
)
314323

324+
if user_id:
325+
logging.info(f"OTLP: User attributes added for {user_name} ({user_id})")
326+
315327
logging.info(f"OpenTelemetry tracing enabled (endpoint: {otel_endpoint})")
316328
except Exception as e:
317329
logging.warning(f"Failed to initialize OpenTelemetry: {e}")

0 commit comments

Comments
 (0)