Skip to content

Conversation

@jssmith
Copy link
Contributor

@jssmith jssmith commented Jan 11, 2026

What was changed

Aim: Improve compatibility between OpenAI Agents SDK (OpenAIAgentsPlugin) and OTel logging.

  • Adds OtelTracingPlugin - a high plugin for OpenTelemetry integration that simplifies OTEL setup for Temporal workflows .
    • Automatic sandbox passthrough configuration for opentelemetry modules
    • Automatic replay filtering to prevent duplicate spans during workflow replay

Why?

We experienced problems using Otel with OpenTelemetry. User issues included missing spans, disconnected spans, and unwanted addition of Temporal execution spans (e.g., startActivity, executeActivity)

Checklist

  1. Closes

  2. How was this tested:

Tests are included.

  1. Any docs updates needed?
    Will add a sample.

jssmith and others added 6 commits January 9, 2026 21:36
This adds two features for better OpenTelemetry integration:

1. TemporalAwareContext: A custom OTEL context implementation that stores
   context on both contextvars and workflow.instance(), allowing OTEL's
   get_current_span() to work inside Temporal's sandboxed workflows.
   Registered as "temporal_aware_context" entry point.

2. create_spans parameter: Added to TracingInterceptor, OpenAIAgentsTracingInterceptor,
   and OpenAIAgentsPlugin. When set to False, context is propagated via headers
   but no spans are created, giving users clean traces with only their
   application spans.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move OtelTracingPlugin from samples to SDK for reusability. This plugin
provides clean OTEL tracing through Temporal workflows with OpenAI Agents:

- Sets OTEL_PYTHON_CONTEXT to use TemporalAwareContext (sandbox-safe)
- Uses TracingInterceptor(create_spans=False) for context propagation
- Optionally instruments OpenAI Agents SDK with OpenInference

Also exports setup_tracing() helper function.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Workflow code re-executes during replay, which causes OTEL spans to be
duplicated. This helper checks workflow.unsafe.is_replaying() and only
creates spans on first execution.

Usage:
    with workflow_span("my_operation", key="value"):
        result = await workflow.execute_activity(...)

Activity spans don't need this wrapper since activities never replay.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This refactors the OpenTelemetry integration to use a simpler and more
robust approach for context propagation inside workflow sandboxes.

Key changes:
- Convert temporalio/contrib/opentelemetry.py to a package directory
- Add OtelTracingPlugin with sandbox_restrictions property that
  configures opentelemetry as a passthrough module
- Add ReplayFilteringSpanProcessor to filter spans during replay
- Remove TemporalAwareContext (passthrough approach is simpler)
- Remove temporal_aware_context entry point from pyproject.toml

The passthrough approach works because:
- When opentelemetry is passthrough, the same module instance is used
  inside and outside the sandbox
- Same module = same ContextVar = context propagation "just works"
- No custom context implementation needed

New tests verify:
- Context does NOT propagate without passthrough (demonstrates problem)
- Context DOES propagate with passthrough (demonstrates fix)
- No state leakage between workflow runs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add tests/contrib/conftest.py with shared tracing fixtures
- Add test_workflow_span_replay.py (moved from samples)
- Simplify test_sandbox_passthrough.py to use shared fixtures

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add workflow_runner callable to automatically add opentelemetry to
  sandbox passthrough modules (like OpenAIAgentsPlugin does)
- Remove ReplayFilteringSpanProcessor from public __all__ (keep internal)
- Update docstrings to reflect automatic configuration

Users no longer need to manually configure sandbox_restrictions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
# Capture create_spans in closure for use by the workflow interceptor class
create_spans = self._create_spans

class _BoundWorkflowInboundInterceptor(_ContextPropagationWorkflowInboundInterceptor):
Copy link
Contributor

Choose a reason for hiding this comment

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

This is silly

)
from temporalio.contrib.openai_agents.workflow import AgentsWorkflowError

# Re-export OtelTracingPlugin from its new location for backward compatibility
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this comment makes any sense.

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.

2 participants