Skip to content

feat(sdk): add OpenTelemetry tracing integration - #1591

Open
eamsden wants to merge 1 commit into
mainfrom
eamsden/opentelemetry-integration
Open

eamsden wants to merge 1 commit into
mainfrom
eamsden/opentelemetry-integration

Conversation

@eamsden

@eamsden eamsden commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

What was changed

  • Add an optional opentelemetry feature to the main Rust SDK crate.
  • Add a plugin that creates spans for client, Workflow, and Activity operations.
  • Propagate W3C Trace Context and W3C Baggage in the cross-SDK _tracer-data header.
  • Add replay-safe Workflow span IDs and suppress span export during replay.
  • Preserve application span context across Workflow polls and calls.
  • Add unit tests and a live-and-replay integration test.

This integration does not trace inbound Nexus handlers because the Rust SDK does not provide an interceptor for those handlers.

Why?

The Rust SDK needs the same general OpenTelemetry behavior as other Temporal SDKs. Applications must be able to trace Temporal operations and propagate trace context across SDK boundaries.

Checklist

  1. Closes: N/A

  2. How was this tested:

  • cargo lint
  • cargo test-lint
  • cargo test -p temporalio-sdk --features opentelemetry --lib
  • cargo integ-test opentelemetry_plugin_parents_activity_to_application_workflow_span
  • cargo doc -p temporalio-sdk --features opentelemetry --no-deps
  1. Any docs updates needed?
    tbd

@eamsden
eamsden marked this pull request as ready for review September 4, 2026 22:49
@eamsden
eamsden requested a review from a team as a code owner September 4, 2026 22:49

@Sushisource Sushisource left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall this makes sense to me. I think we probably want to expand the integration test a bit to include more kinds of spans. I think there are some good examples in the TS SDK.

Comment on lines +198 to +199
static WORKFLOW_OTEL_TRACER: OnceLock<SdkTracer> = OnceLock::new();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will end up shared across the two tests which seems wrong

Comment on lines +149 to +152
/// Use this generator in the tracer provider for [`OpenTelemetryPlugin`]. This generator gives
/// the same IDs to spans during execution and replay. Outside a Workflow context that requires
/// replay safety, it uses the standard OpenTelemetry random ID generator.
#[derive(Clone, Debug, Default)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is it possible to, when they call with_tracer, force the generator to be this?

Comment on lines +165 to +170
loop {
let id = TraceId::from(random.random::<u128>());
if id != TraceId::INVALID {
return id;
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a bit odd. Why would it be invalid? Can we just clamp the random output or something if the issue is extreme values?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IIRC the spec only classifies 0 as an invalid trace id

Comment thread crates/sdk/README.md
the Temporal client. Workers that use the client automatically get the worker interceptors.

```toml
temporalio-sdk = { version = "1.0", features = ["opentelemetry"] }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Codex loves adding these to our README, but I don't think they're really helpful. Version string will be annoying to to keep up to date and I don't think it is necessary to show how to enable a feature.

Comment on lines +165 to +170
loop {
let id = TraceId::from(random.random::<u128>());
if id != TraceId::INVALID {
return id;
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IIRC the spec only classifies 0 as an invalid trace id

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