Skip to content

Conversation

@Steffen911
Copy link
Member

@Steffen911 Steffen911 commented Sep 17, 2025

Important

Introduces context propagation using OpenTelemetry baggage in Langfuse, updating span processing and tests accordingly.

  • Behavior:
    • Introduces propagate_attributes() in attributes.py to propagate context attributes using OpenTelemetry baggage.
    • Updates LangfuseSpanProcessor in span_processor.py to use BaggageSpanProcessor for attaching baggage to spans.
    • Modifies update_trace() in span.py to use propagate_attributes() for context management.
  • Dependencies:
    • Adds opentelemetry-processor-baggage to pyproject.toml.
  • Tests:
    • Updates test_core_sdk.py to test context propagation and baggage handling in spans and traces.

This description was created by Ellipsis for 02d3dea. You can customize this summary. It will automatically update as commits are pushed.

Disclaimer: Experimental PR review

Greptile Summary

Updated On: 2025-09-17 13:59:45 UTC

This PR implements OpenTelemetry baggage-based context propagation to showcase how trace-level attributes can be automatically propagated to child spans. The implementation consists of several interconnected changes:

Core Architecture Changes:

  • The update_trace method in span.py is converted from a regular method to a context manager using @contextmanager. This method now creates an OpenTelemetry context with trace attributes stored in baggage, attaches the context during execution, and properly detaches it when the context manager exits.
  • A new propagate_attributes function is added to attributes.py that converts dictionary attributes into OpenTelemetry baggage entries, enabling cross-boundary context propagation.
  • The LangfuseSpanProcessor in span_processor.py is enhanced with a BaggageSpanProcessor integration that automatically attaches baggage keys to spans during their initialization via the on_start lifecycle method.

Integration with OpenTelemetry Stack:
The changes build upon the existing OpenTelemetry infrastructure already present in the codebase (api, sdk, exporter) by adding the opentelemetry-processor-baggage dependency. This creates a complete context propagation pipeline where trace-level attributes set via update_trace() are automatically available to child spans without manual propagation.

Usage Pattern Changes:
The update_trace method now requires usage as a context manager (with span.update_trace(...):) rather than a direct method call. Child spans created within this context automatically inherit the trace-level attributes through the baggage mechanism, eliminating the need for manual attribute management across span hierarchies.

The test modifications in test_core_sdk.py demonstrate this new pattern, showing how trace metadata is automatically propagated to child spans when operations are performed within the update_trace context manager scope.

Confidence score: 3/5

  • This PR introduces significant architectural changes to core tracing functionality that could impact existing integrations
  • Score reflects the beta version dependency and breaking API changes to update_trace method signature
  • Pay close attention to span_processor.py and span.py for potential compatibility issues with existing OpenTelemetry integrations

@Steffen911 Steffen911 mentioned this pull request Sep 17, 2025
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, no comments

Edit Code Review Bot Settings | Greptile

Comment on lines +72 to +74
for key, value in dict_to_propagate.items():
current_ctx = baggage.set_baggage(key, str(value), context=current_ctx)
return current_ctx
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The context is immutable, i.e. every set_baggage operation produces a new, updated context with the relevant properties. We update whatever context we get and return the new one.


return self

@contextmanager
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're turning this into a context manager as we need to detach the context at the end of the execution to avoid memory leaks and issues in async/multi-thread processing.

Every call like

    span.update_trace(name="foo")
    [...]
    # ongoing execution

must become

    with span.update_trace(name="foo"):
        [...]
        # ongoing execution

to ensure that all child spans will be started with the attached context.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this is a breaking change!

else None,
)

def on_start(self, span: Span, parent_context: Optional[Context] = None) -> None:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're injecting the baggage span processor in the on_start here to make use of it and call its own implementation: https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py.

The other overwrites are taken as-is from the SpanProcessor, i.e. there is no need to overwrite the on_end, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants