1616 Any ,
1717 Callable ,
1818 Dict ,
19+ Generator ,
1920 List ,
2021 Literal ,
2122 Optional ,
2223 Type ,
2324 Union ,
2425 cast ,
2526 overload ,
26- Generator ,
2727)
2828
2929import backoff
3030import httpx
3131from opentelemetry import (
3232 baggage as otel_baggage_api ,
33- trace as otel_trace_api ,
33+ )
34+ from opentelemetry import (
3435 context as otel_context_api ,
3536)
37+ from opentelemetry import (
38+ trace as otel_trace_api ,
39+ )
3640from opentelemetry .sdk .trace import TracerProvider
3741from opentelemetry .sdk .trace .id_generator import RandomIdGenerator
3842from opentelemetry .util ._decorator import (
4347
4448from langfuse ._client .attributes import LangfuseOtelSpanAttributes
4549from langfuse ._client .constants import (
50+ LANGFUSE_CORRELATION_CONTEXT_KEY ,
4651 ObservationTypeGenerationLike ,
4752 ObservationTypeLiteral ,
4853 ObservationTypeLiteralNoEvent ,
4954 ObservationTypeSpanLike ,
5055 get_observation_types_list ,
51- LANGFUSE_CTX_USER_ID ,
52- LANGFUSE_CTX_SESSION_ID ,
53- LANGFUSE_CTX_METADATA ,
5456)
5557from langfuse ._client .datasets import DatasetClient , DatasetItemClient
5658from langfuse ._client .environment_variables import (
7678 LangfuseSpan ,
7779 LangfuseTool ,
7880)
79- 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+ )
8085from langfuse ._utils import _get_timestamp
8186from langfuse ._utils .parse_error import handle_fern_exception
8287from langfuse ._utils .prompt_cache import PromptCache
@@ -219,10 +224,8 @@ def __init__(
219224 additional_headers : Optional [Dict [str , str ]] = None ,
220225 tracer_provider : Optional [TracerProvider ] = None ,
221226 ):
222- self ._host = (
223- host
224- if host is not None
225- else os .environ .get (LANGFUSE_HOST , "https://cloud.langfuse.com" )
227+ self ._host = host or cast (
228+ str , os .environ .get (LANGFUSE_HOST , "https://cloud.langfuse.com" )
226229 )
227230 self ._environment = environment or cast (
228231 str , os .environ .get (LANGFUSE_TRACING_ENVIRONMENT )
@@ -361,19 +364,18 @@ def start_span(
361364 )
362365
363366 @_agnosticcontextmanager
364- def with_attributes (
367+ def correlation_context (
365368 self ,
366- session_id : Optional [str ] = None ,
367- user_id : Optional [str ] = None ,
368- metadata : Optional [dict [str , str ]] = None ,
369+ correlation_context : Dict [str , str ],
370+ * ,
369371 as_baggage : bool = False ,
370372 ) -> Generator [None , None , None ]:
371- """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 .
372374
373375 Args:
374- session_id ( str): Session identifier.
375- user_id (str): User identifier.
376- 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.
377379 as_baggage (bool, optional): If True, stores the values in OpenTelemetry baggage
378380 for cross-service propagation. If False, stores only in local context for
379381 current-service propagation. Defaults to False.
@@ -386,79 +388,55 @@ def with_attributes(
386388 outbound requests made within this context. Only use this for non-sensitive
387389 identifiers that are safe to transmit across service boundaries.
388390
389- Example :
391+ Examples :
390392 ```python
391- # Local context only (default)
392- 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"} ):
393395 with langfuse.start_as_current_span(name="process-request") as span:
394396 # This span and all its children will have session_id="session_123"
395397 child_span = langfuse.start_span(name="child-operation")
396398
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+
397404 # Cross-service propagation (use with caution)
398- with langfuse.with_attributes( session_id=" session_123", as_baggage=True):
405+ with langfuse.correlation_context({" session_id": " session_123"} , as_baggage=True):
399406 # session_id will be propagated to external service calls
400407 response = requests.get("https://api.example.com/data")
401408 ```
402409 """
403410 current_context = otel_context_api .get_current ()
404411 current_span = otel_trace_api .get_current_span ()
405412
406- # Process session_id
407- if session_id is not None :
408- current_context = otel_context_api .set_value (
409- LANGFUSE_CTX_SESSION_ID , session_id , current_context
410- )
411- if current_span is not None and current_span .is_recording ():
412- current_span .set_attribute ("session.id" , session_id )
413- if as_baggage :
414- current_context = otel_baggage_api .set_baggage (
415- "session.id" , session_id , current_context
416- )
413+ current_context = otel_context_api .set_value (
414+ LANGFUSE_CORRELATION_CONTEXT_KEY , correlation_context , current_context
415+ )
417416
418- # Process user_id
419- if user_id is not None :
420- current_context = otel_context_api .set_value (
421- LANGFUSE_CTX_USER_ID , user_id , current_context
422- )
423- if current_span is not None and current_span .is_recording ():
424- current_span .set_attribute ("user.id" , user_id )
425- if as_baggage :
426- current_context = otel_baggage_api .set_baggage (
427- "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."
428421 )
422+ continue
429423
430- # Process metadata
431- if metadata is not None :
432- # Truncate values with size > 200 to 200 characters and emit warning including the ky
433- for k , v in metadata .items ():
434- if not isinstance (v , str ):
435- # Ignore unreachable mypy warning as this runtime guard should make sense either way
436- warnings .warn ( # type: ignore[unreachable]
437- f"Metadata values must be strings, got { type (v )} for key '{ k } '"
438- )
439- del metadata [k ]
440- if len (v ) > 200 :
441- warnings .warn (
442- f"Metadata value for key '{ k } ' exceeds 200 characters and will be truncated."
443- )
444- metadata [k ] = v [:200 ]
424+ attribute_key = get_attribute_key_from_correlation_context (key )
445425
446- current_context = otel_context_api .set_value (
447- LANGFUSE_CTX_METADATA , metadata , current_context
448- )
449426 if current_span is not None and current_span .is_recording ():
450- for k , v in metadata . items ():
451- current_span . set_attribute ( f"langfuse.metadata. { k } " , v )
427+ current_span . set_attribute ( attribute_key , value )
428+
452429 if as_baggage :
453- for k , v in metadata .items ():
454- current_context = otel_baggage_api .set_baggage (
455- f"langfuse.metadata.{ k } " , str (v ), current_context
456- )
430+ current_context = otel_baggage_api .set_baggage (
431+ key , value , current_context
432+ )
457433
458434 # Activate context, execute, and detach context
459435 token = otel_context_api .attach (current_context )
436+
460437 try :
461438 yield
439+
462440 finally :
463441 otel_context_api .detach (token )
464442
@@ -1780,7 +1758,7 @@ def update_current_trace(
17801758 ```
17811759 """
17821760 warnings .warn (
1783- "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. " ,
17841762 DeprecationWarning ,
17851763 stacklevel = 2 ,
17861764 )
0 commit comments