4747
4848from langfuse ._client .attributes import LangfuseOtelSpanAttributes
4949from langfuse ._client .constants import (
50- LANGFUSE_CTX_METADATA ,
51- LANGFUSE_CTX_SESSION_ID ,
52- LANGFUSE_CTX_USER_ID ,
50+ LANGFUSE_CORRELATION_CONTEXT_KEY ,
5351 ObservationTypeGenerationLike ,
5452 ObservationTypeLiteral ,
5553 ObservationTypeLiteralNoEvent ,
8078 LangfuseSpan ,
8179 LangfuseTool ,
8280)
83- from langfuse ._client .utils import run_async_safely
81+ from langfuse ._client .utils import (
82+ get_attribute_key_from_correlation_context ,
83+ run_async_safely ,
84+ )
8485from langfuse ._utils import _get_timestamp
8586from langfuse ._utils .parse_error import handle_fern_exception
8687from langfuse ._utils .prompt_cache import PromptCache
@@ -363,19 +364,18 @@ def start_span(
363364 )
364365
365366 @_agnosticcontextmanager
366- def with_attributes (
367+ def correlation_context (
367368 self ,
368- session_id : Optional [str ] = None ,
369- user_id : Optional [str ] = None ,
370- metadata : Optional [dict [str , str ]] = None ,
369+ correlation_context : Dict [str , str ],
370+ * ,
371371 as_baggage : bool = False ,
372372 ) -> Generator [None , None , None ]:
373- """Creates a context manager that propagates the given attributes to all spans created within the context.
373+ """Create a context manager that propagates the given correlation_context to all spans within the context manager's scope .
374374
375375 Args:
376- session_id ( str): Session identifier.
377- user_id (str): User identifier.
378- metadata (dict): Additional metadata to associate with all spans in the context. Values must be strings and are truncated to 200 characters.
376+ correlation_context (Dict[ str, str] ): Dictionary containing key-value pairs to be propagated
377+ to all spans within the context manager's scope. Common keys include user_id, session_id,
378+ and custom metadata. All values must be strings below 200 characters.
379379 as_baggage (bool, optional): If True, stores the values in OpenTelemetry baggage
380380 for cross-service propagation. If False, stores only in local context for
381381 current-service propagation. Defaults to False.
@@ -388,79 +388,55 @@ def with_attributes(
388388 outbound requests made within this context. Only use this for non-sensitive
389389 identifiers that are safe to transmit across service boundaries.
390390
391- Example :
391+ Examples :
392392 ```python
393- # Local context only (default)
394- with langfuse.with_attributes( session_id=" session_123"):
393+ # Local context only (default) - pass context as dictionary
394+ with langfuse.correlation_context({" session_id": " session_123"} ):
395395 with langfuse.start_as_current_span(name="process-request") as span:
396396 # This span and all its children will have session_id="session_123"
397397 child_span = langfuse.start_span(name="child-operation")
398398
399+ # Multiple values in context dictionary
400+ with langfuse.correlation_context({"user_id": "user_456", "experiment": "A"}):
401+ # All spans will have both user_id and experiment attributes
402+ span = langfuse.start_span(name="experiment-operation")
403+
399404 # Cross-service propagation (use with caution)
400- with langfuse.with_attributes( session_id=" session_123", as_baggage=True):
405+ with langfuse.correlation_context({" session_id": " session_123"} , as_baggage=True):
401406 # session_id will be propagated to external service calls
402407 response = requests.get("https://api.example.com/data")
403408 ```
404409 """
405410 current_context = otel_context_api .get_current ()
406411 current_span = otel_trace_api .get_current_span ()
407412
408- # Process session_id
409- if session_id is not None :
410- current_context = otel_context_api .set_value (
411- LANGFUSE_CTX_SESSION_ID , session_id , current_context
412- )
413- if current_span is not None and current_span .is_recording ():
414- current_span .set_attribute ("session.id" , session_id )
415- if as_baggage :
416- current_context = otel_baggage_api .set_baggage (
417- "session.id" , session_id , current_context
418- )
413+ current_context = otel_context_api .set_value (
414+ LANGFUSE_CORRELATION_CONTEXT_KEY , correlation_context , current_context
415+ )
419416
420- # Process user_id
421- if user_id is not None :
422- current_context = otel_context_api .set_value (
423- LANGFUSE_CTX_USER_ID , user_id , current_context
424- )
425- if current_span is not None and current_span .is_recording ():
426- current_span .set_attribute ("user.id" , user_id )
427- if as_baggage :
428- current_context = otel_baggage_api .set_baggage (
429- "user.id" , user_id , current_context
417+ for key , value in correlation_context .items ():
418+ if len (value ) > 200 :
419+ langfuse_logger .warning (
420+ f"Correlation context key '{ key } ' is over 200 characters ({ len (value )} chars). Dropping value."
430421 )
422+ continue
431423
432- # Process metadata
433- if metadata is not None :
434- # Truncate values with size > 200 to 200 characters and emit warning including the ky
435- for k , v in metadata .items ():
436- if not isinstance (v , str ):
437- # Ignore unreachable mypy warning as this runtime guard should make sense either way
438- warnings .warn ( # type: ignore[unreachable]
439- f"Metadata values must be strings, got { type (v )} for key '{ k } '"
440- )
441- del metadata [k ]
442- if len (v ) > 200 :
443- warnings .warn (
444- f"Metadata value for key '{ k } ' exceeds 200 characters and will be truncated."
445- )
446- metadata [k ] = v [:200 ]
424+ attribute_key = get_attribute_key_from_correlation_context (key )
447425
448- current_context = otel_context_api .set_value (
449- LANGFUSE_CTX_METADATA , metadata , current_context
450- )
451426 if current_span is not None and current_span .is_recording ():
452- for k , v in metadata . items ():
453- current_span . set_attribute ( f"langfuse.metadata. { k } " , v )
427+ current_span . set_attribute ( attribute_key , value )
428+
454429 if as_baggage :
455- for k , v in metadata .items ():
456- current_context = otel_baggage_api .set_baggage (
457- f"langfuse.metadata.{ k } " , str (v ), current_context
458- )
430+ current_context = otel_baggage_api .set_baggage (
431+ key , value , current_context
432+ )
459433
460434 # Activate context, execute, and detach context
461435 token = otel_context_api .attach (current_context )
436+
462437 try :
463438 yield
439+
464440 finally :
465441 otel_context_api .detach (token )
466442
@@ -1782,7 +1758,7 @@ def update_current_trace(
17821758 ```
17831759 """
17841760 warnings .warn (
1785- "update_current_trace is deprecated and will be removed in a future version. Use `with langfuse.with_attributes (...)` instead. " ,
1761+ "update_current_trace is deprecated and will be removed in a future version. Use `with langfuse.correlation_context (...)` instead. " ,
17861762 DeprecationWarning ,
17871763 stacklevel = 2 ,
17881764 )
0 commit comments