cool-lizard-26153
12/29/2025, 12:50 PMtall-airline-16756
12/29/2025, 12:50 PMtall-airline-16756
12/29/2025, 12:50 PMfrom opentelemetry.sdk.trace import SpanProcessor
class CustomSpanProcessor(SpanProcessor):
def __init__(self, room_id=None, call_id=None):
self.room_id = room_id
self.call_id = call_id
def on_start(self, span, parent_context):
if self.room_id:
span.set_attribute("room_id", self.room_id)
if self.call_id:
span.set_attribute("call_id", self.call_id)
def on_end(self, span):
pass
tracer_provider.add_span_processor(CustomSpanProcessor(room_id="room_123", call_id="call_456"))
This will attach `room_id`/`call_id` to spans and make them visible in the Langfuse dashboard. If you prefer, you can set these attributes when creating specific spans instead of globally.
If you want, tell me which language/sdk you’re using and whether you need the IDs applied globally or only to certain spans, and I’ll provide a tailored snippet.
Sources: Setting custom user_id and session_id in Langfuse tracescool-lizard-26153
12/29/2025, 12:54 PMtall-airline-16756
12/29/2025, 12:54 PMspan.set_attribute("room_id", room_id) (and call_id) so those attributes travel with that span and any child spans.
• Propagate the session ID via context and use a span processor or middleware to add the attribute on span start.
◦ Store the session ID in the request/session context (HTTP request context, thread-local, or framework request object).
◦ Use a custom SpanProcessor or framework middleware that reads the context on span start and sets `room_id`/`call_id` automatically.
Which language/SDK and web framework (if any) are you using? Tell me that and whether you want attributes applied only to root/session spans or to all child spans—I’ll provide a concise code example for your environment.cool-lizard-26153
12/29/2025, 12:55 PMtall-airline-16756
12/29/2025, 12:55 PMwith tracer.start_as_current_span("handle_call") as span:
span.set_attribute("room_id", room_id)
span.set_attribute("call_id", call_id)
# child spans inherit attributes in UI queries
Use this when you control where spans are started and only need IDs on specific spans.
2) Propagate IDs via context + custom SpanProcessor (automatic)
• Store the session ID in context (contextvars) and use a SpanProcessor to read it on span start so every span gets the session attributes automatically.
Example:
import contextvars
from opentelemetry.sdk.trace import SpanProcessor
# context var to hold current session ids
current_room_id = contextvars.ContextVar("room_id", default=None)
current_call_id = contextvars.ContextVar("call_id", default=None)
def set_session_ids(room, call):
current_room_id.set(room)
current_call_id.set(call)
class SessionSpanProcessor(SpanProcessor):
def on_start(self, span, parent_context):
room = current_room_id.get()
call = current_call_id.get()
if room:
span.set_attribute("room_id", room)
if call:
span.set_attribute("call_id", call)
def on_end(self, span):
pass
# add processor to your tracer provider once
tracer_provider.add_span_processor(SessionSpanProcessor())
• When handling a session, call set_session_ids(room_id, call_id) before starting spans (e.g., at request entry). This works across async tasks and threads if you manage context appropriately.
Which framework are you using (Flask, FastAPI, Django, plain asyncio)? I can give a concise example wiring this into request middleware for your framework.cool-lizard-26153
12/29/2025, 1:12 PMtall-airline-16756
12/29/2025, 1:12 PMcontextvars isn't suitable, here are practical alternatives to propagate per-session room/call IDs into spans in Python, with pros/cons and a concise example request so I can tailor one to your stack.
Options
• Explicit per-span attributes (most straightforward)
◦ Call span.set_attribute("room_id", room_id) when you create the span for that session. Works everywhere, no global state, easiest to reason about.
◦ Best when you control span creation points.
• OpenTelemetry Baggage (propagates across process boundaries)
◦ Use OTEL baggage to store IDs so they travel with context across threads/processes and remote calls.
◦ Use from opentelemetry import baggage, trace and set baggage at request entry; read it in a SpanProcessor or when creating spans.
◦ Good for cross-service tracing; slightly higher overhead.
• Thread-local storage (for sync code)
◦ Use threading.local() to store session IDs per thread and read them in a SpanProcessor or when starting spans.
◦ Works well in synchronous servers that use one thread per request; not suitable for async/asyncio frameworks.
• Request/framework-specific middleware (recommended for web apps)
◦ Attach IDs to the request object (e.g., request.state.room_id in FastAPI, g.room_id in Flask, request.room_id in Django) and set span attributes in middleware or when starting spans.
◦ This avoids global context and fits idiomatically into web frameworks.
Short examples
• Explicit per-span:
with tracer.start_as_current_span("handle_call") as span:
span.set_attribute("room_id", room_id)
• Baggage (set/read):
from opentelemetry import baggage
# at request entry
baggage.set_baggage("room_id", room_id)
# when starting a span
from opentelemetry import baggage as _baggage
room = _baggage.get_baggage("room_id")
span.set_attribute("room_id", room)
• Thread-local:
import threading
_ctx = threading.local()
_ctx.room_id = room_id
# in SpanProcessor.on_start or when creating spans
room = getattr(_ctx, "room_id", None)
span.set_attribute("room_id", room)
Which do you prefer or which environment are you using (FastAPI, Flask, Django, plain asyncio, or a worker process)? Tell me that and whether you want IDs on only root/session spans or on every child span — I’ll give a concise, tailored snippet and wiring advice.cool-lizard-26153
12/29/2025, 2:15 PMtall-airline-16756
12/29/2025, 2:15 PMcool-lizard-26153
12/29/2025, 2:28 PMtall-airline-16756
12/29/2025, 2:29 PMfrom opentelemetry import baggage
from opentelemetry.sdk.trace import SpanProcessor
class BaggageSpanProcessor(SpanProcessor):
def on_start(self, span, parent_context):
room = baggage.get_baggage("room_id", context=parent_context)
call = baggage.get_baggage("call_id", context=parent_context)
if room:
span.set_attribute("room_id", room)
if call:
span.set_attribute("call_id", call)
def on_end(self, span):
pass
# once at startup
tracer_provider.add_span_processor(BaggageSpanProcessor())
When handling a session in your worker (at the point you have room/call IDs), set baggage into the current context so subsequent auto-created spans inherit it:
from opentelemetry import baggage, context
# when processing a job/session
ctx = context.set_value(baggage.set_baggage("room_id", room_id))
ctx = context.set_value(baggage.set_baggage("call_id", call_id), context=ctx)
# run the work within that context so auto-instrumentation sees it
token = context.attach(ctx)
try:
process_job() # work that triggers auto-created spans
finally:
context.detach(token)
Notes and tips
• This works with async or sync worker code as long as you attach the context before work that produces spans.
• Baggage propagates across threads/process boundaries when using supported propagators — useful if your job dispatch forks work.
• If you only want IDs on root/session spans (not every child), the SpanProcessor can check span.kind or span.parent to conditionally set attributes.
Want a variant that avoids context attach/attach-detach (e.g., wrapping a job handler function) or an example integrating with your job queue? Tell me which queue/worker library you use and I’ll produce a tiny snippet.