Skip to content

Add span backdating to core tracing traits#4784

Merged
heaths merged 2 commits into
Azure:mainfrom
NaluTripician:nalutripician/cosmos-diag-ws4c-backdating
Jul 20, 2026
Merged

Add span backdating to core tracing traits#4784
heaths merged 2 commits into
Azure:mainfrom
NaluTripician:nalutripician/cosmos-diag-ws4c-backdating

Conversation

@NaluTripician

@NaluTripician NaluTripician commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Why

Tail-based (late-bound) sampling decides after an operation completes whether it's
worth emitting a span — e.g. only for slow or failed requests. To do that we must be able
to reconstruct a span for an operation that already happened, stamped with the
timestamps it actually had, not "now".

Today the tracing traits in typespec_client_core have no hook for this: Tracer::start_span
builds the span at "now" and Span::end() closes it at "now". This PR adds an explicit
start/end timestamp path so backdated spans aren't a Cosmos-only concern.

This is the upstream sub-task (WS4c) of the Cosmos diagnostics effort. It is independent
of the Cosmos work and touches only core crates — no Cosmos crate is modified.

What

typespec_client_core (src/tracing/mod.rs):

  • A new SpanOptions struct (currently carrying start_time: Option<OffsetDateTime>).
  • Tracer::start_span_with_options(name, kind, attributes, options)
  • Tracer::start_span_with_parent_and_options(name, kind, attributes, parent, options)
  • Span::end_at(end_time)

azure_core:

  • Re-exports SpanOptions alongside the existing tracing types.

azure_core_opentelemetry:

  • Implements the new methods against the raw OpenTelemetry
    SpanBuilder::with_start_time / SpanRef::end_with_timestamp APIs, converting the
    OffsetDateTime to SystemTime at the OpenTelemetry boundary.
  • Refactors span construction into shared build_span / parent_context helpers so the
    span variants don't duplicate builder logic.
  • Adds in-memory-exporter unit tests (test_open_telemetry_span_backdated,
    test_open_telemetry_span_backdated_with_parent) that assert the exported span carries
    the injected past timestamps (and that a backdated child is correctly parented).

Trait-design rationale (additive, future-proof)

The change is deliberately additive: all new methods have default implementations
that delegate to the existing non-backdating methods (dropping the timestamp). Consequences:

  • Existing Tracer/Span implementations keep compiling unchanged — adding a defaulted
    method to a trait is a SemVer-minor-compatible change in Rust.
  • A backend that genuinely can't backdate degrades gracefully to "start/end at now" rather
    than failing to compile or panicking. The OpenTelemetry bridge overrides the defaults to
    honor the timestamps.

Timestamps are carried by a SpanOptions struct rather than as bare method arguments, so
future options can be added without changing the Tracer method signatures (per review
feedback from @analogrelay / @heaths). time::OffsetDateTime is used as the timestamp type
to match the rest of the Rust SDK, which standardizes on the time crate (per review
feedback from @LarryOsterman); the OpenTelemetry bridge converts it to SystemTime where
the OTel APIs require it.

Verification

Run for the touched core crates (typespec_client_core, azure_core,
azure_core_opentelemetry):

  • cargo fmt — clean
  • cargo clippy (lib/tests) — no warnings
  • cargo testazure_core_opentelemetry 18 lib tests (incl. the 2 new backdating tests)
    plus its doctests and integration tests; typespec_client_core 143 lib tests and
    doctests (incl. the new SpanOptions doctest)

Scope guardrails

  • No Cosmos crate touched (azure_data_cosmos / driver untouched).
  • CHANGELOG entries added for the three core crates whose public API changed.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds explicit span timestamps to core tracing and OpenTelemetry, but also includes Cosmos retry changes that contradict the stated core-only scope.

Changes:

  • Adds start_span_at, start_span_with_parent_at, and end_at.
  • Implements and tests OpenTelemetry span backdating.
  • Adds bounded Cosmos 410 retry and 503 conversion behavior.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
sdk/core/typespec_client_core/src/tracing/mod.rs Adds timestamp-aware tracing APIs.
sdk/core/typespec_client_core/CHANGELOG.md Documents tracing APIs.
sdk/core/azure_core/CHANGELOG.md Documents re-exported APIs.
sdk/core/azure_core_opentelemetry/src/tracer.rs Implements backdated span creation.
sdk/core/azure_core_opentelemetry/src/span.rs Implements backdated ending and tests.
sdk/core/azure_core_opentelemetry/CHANGELOG.md Documents OpenTelemetry support.
sdk/cosmos/azure_data_cosmos/src/retry_policies/mod.rs Adds terminal 410-to-503 conversion.
sdk/cosmos/azure_data_cosmos/src/retry_policies/client_retry_policy.rs Adds bounded Gone retries.
sdk/cosmos/azure_data_cosmos/src/handler/retry_handler.rs Applies terminal conversion.
sdk/cosmos/azure_data_cosmos/tests/emulator_tests/cosmos_fault_injection.rs Tests surfaced 503 status.
sdk/cosmos/azure_data_cosmos/CHANGELOG.md Documents Cosmos retry behavior.

Comment thread sdk/cosmos/azure_data_cosmos/CHANGELOG.md Outdated
Comment thread sdk/cosmos/azure_data_cosmos/src/retry_policies/client_retry_policy.rs Outdated
Comment thread sdk/cosmos/azure_data_cosmos/src/retry_policies/mod.rs Outdated
@NaluTripician
NaluTripician force-pushed the nalutripician/cosmos-diag-ws4c-backdating branch 2 times, most recently from 161b0b3 to 7f9abef Compare July 15, 2026 21:43

@heaths heaths 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.

@LarryOsterman what do you think? Seems acceptable, and .NET's StartActivity already has an overload that lets you do this.

Comment thread sdk/core/azure_core/CHANGELOG.md Outdated
Comment thread sdk/core/azure_core_opentelemetry/src/span.rs Outdated
Comment thread sdk/core/typespec_client_core/src/tracing/mod.rs Outdated
@LarryOsterman

Copy link
Copy Markdown
Member

@LarryOsterman what do you think? Seems acceptable, and .NET's StartActivity already has an overload that lets you do this.

Fundamentally I don't have a problem with this idea - we didn't have a need for it earlier, but if we do now, then so be it.

My biggest concern is architectural: For better or for worse, we have standardized on the time crate for time related constructs and this uses std::time for time constructs. Note that SystemTime appears to be an inherently local time, which may be a problem.

@NaluTripician

Copy link
Copy Markdown
Contributor Author

⚠ Blocked on an upstream workspace-dependency linkage (not a defect in this PR)

This PR is clean and green on a consistent workspace (1 commit, 6 core-crate files, rebased directly onto upstream/main). However, the azure_core_opentelemetry impl will not compile on Azure/main as-is, due to a pre-existing version-pin drift on main:

  • Core members are bumped to betas: azure_core = 1.2.0-beta.1, typespec_client_core = 1.2.0-beta.1, azure_core_opentelemetry = 1.1.0-beta.1.
  • But root [workspace.dependencies] still pin the published versions (azure_core = "1.1.0", typespec_client_core = "1.1.0") with no path and no [patch].
  • Since a pre-release (1.2.0-beta.1) does not satisfy ^1.1.0, azure_core_opentelemetry (which uses azure_core.workspace = true) links against registry azure_core 1.1.0 — which predates the new trait methods. Cargo.lock confirms the workspace otel crate resolving to registry azure_core 1.1.0.
  • Net: the new Tracer::start_span_at / start_span_with_parent_at / Span::end_at (additive, default-impl'd in typespec_client_core, re-exported by azure_core) aren't visible to the otel impl until the workspace linkage is updated.

The typespec_client_core + azure_core trait additions compile standalone on main; only the otel impl is affected, purely by the linkage drift.

Needs a maintainer call (cc the tracing-trait / workspace-versioning owner, e.g. Heath): the fix is an upstream workspace-versioning change (path entries for the local betas, or publishing the 1.2.0-beta.1 crates), which is out of scope for this additive, core-only PR. Options considered: (a) land as-is and let the linkage catch up; (b) split trait-additions vs otel-impl (yields dead code until the impl lands — not recommended); (c) bundle a root Cargo.toml fix in this PR (touches every crate — not recommended). Guidance welcome.

@heaths

heaths commented Jul 16, 2026

Copy link
Copy Markdown
Member

You need to pull the latest upstream main and rebase, and then have azure_core_opentelemetry depend on the changes in azure_core via path + version as described in both our guidelines and CONTRIBUTING.md.

Comment thread sdk/core/typespec_client_core/src/tracing/mod.rs Outdated
@heaths

heaths commented Jul 16, 2026

Copy link
Copy Markdown
Member

@NaluTripician I'm working on fixing your PR. Turns out there's a few issues with just rebasing and updating the versions because of an unrelated crate. I'm prototyping a few ideas. You could make changes still and commit them, but don't push them yet. After my changes are pushed, you could pull this remote and update with git rebase --onto e.g.,

git fetch origin nalutripician/cosmos-diag-ws4c-backdating
git rebase --onto FETCH_HEAD HEAD~ # assuming you made only one subsequent commit with suggested changes

See https://heaths.dev/tips/2019/11/11/rebasing-commits-on-one-topic-branch-onto-another-branch.html for more information.

@heaths

heaths commented Jul 16, 2026

Copy link
Copy Markdown
Member

Opened #4791 to track long-term changes to workspace dependency resolution.

@heaths

heaths commented Jul 17, 2026

Copy link
Copy Markdown
Member

We'll need to wait for #4801 to merge and rebase. Hopefully that'll unblock this until we investigate #4791 more thoroughly; though, I did tried quite a few of those suggestions in #4801 already.

Add explicit start/end timestamp support to the tracing traits so
late-bound (tail-sampled) spans can be reconstructed from an
already-completed operation with their original timestamps, rather than
being stamped at "now".

typespec_client_core (`tracing/mod.rs`):
- `Tracer::start_span_at` and `Tracer::start_span_with_parent_at`
- `Span::end_at`

All three are additive with default implementations that delegate to the
existing non-backdating methods, so existing `Tracer`/`Span`
implementations keep compiling unchanged (non-breaking, minor-release
friendly). `azure_core` re-exports these traits, so its public API gains
the methods transitively.

azure_core_opentelemetry:
- Implement the new methods by mapping to raw OpenTelemetry
  `SpanBuilder::with_start_time` and `SpanRef::end_with_timestamp`.
- Refactor span construction into shared `build_span` / `parent_context`
  helpers to avoid duplication across the four start_span variants.
- Add in-memory-exporter unit tests proving a backdated span (and a
  backdated parent/child pair) carries the injected PAST timestamps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 17, 2026 21:26
@heaths
heaths force-pushed the nalutripician/cosmos-diag-ws4c-backdating branch from 7f9abef to 6fd91d7 Compare July 17, 2026 21:26
@heaths

heaths commented Jul 17, 2026

Copy link
Copy Markdown
Member

@NaluTripician this is ready. Please make additional requested changes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 6/6 changed files
  • Comments generated: 3
  • Review effort level: Medium

Comment thread sdk/core/azure_core_opentelemetry/src/tracer.rs Outdated
Comment thread sdk/core/azure_core_opentelemetry/src/span.rs
Comment thread sdk/core/azure_core_opentelemetry/src/span.rs
Address review feedback on the span-backdating traits:

- Replace `Tracer::start_span_at` / `start_span_with_parent_at` with a future-proof `SpanOptions` struct passed to `start_span_with_options` / `start_span_with_parent_and_options` (analogrelay/heaths).

- Use `time::OffsetDateTime` instead of `std::time::SystemTime` for the public timestamp type (LarryOsterman); the OpenTelemetry bridge converts to `SystemTime` at the OTel boundary.

- `azure_core` CHANGELOG now copies the `typespec_client_core` entry verbatim with no re-export note (heaths).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 20, 2026 17:24
@NaluTripician

Copy link
Copy Markdown
Contributor Author

@heaths @LarryOsterman @analogrelay — pushed the requested changes in 5288a57:

  • time crate, not std::time (@LarryOsterman): the public API now uses time::OffsetDateTime. The OpenTelemetry bridge converts to SystemTime only where the raw OTel APIs (with_start_time / end_with_timestamp) require it.
  • Future-proof SpanOptions (@analogrelay / @heaths): replaced start_span_at / start_span_with_parent_at with a SpanOptions struct passed to start_span_with_options / start_span_with_parent_and_options. New options can be added later without changing the trait method signatures. Span::end_at stays (a single timestamp is all it needs).
  • azure_core CHANGELOG (@heaths): removed the re-export parenthetical and copied the typespec_client_core entry verbatim.

The stale "blocked on workspace-dependency linkage" warning has been removed from the description — the local path deps already wire azure_core_opentelemetryazure_coretypespec_client_core, and CI is green.

Verification (core crates only): cargo fmt clean; cargo clippy no warnings; cargo testazure_core_opentelemetry 18 lib tests (incl. the 2 backdating tests) + doctests/integration, typespec_client_core 143 lib tests + doctests (incl. the new SpanOptions doctest).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

sdk/core/azure_core_opentelemetry/src/span.rs:319

  • Repository test guidance says test function names should not begin with test unless needed for disambiguation. The #[test] attribute already provides that context, so please rename this to open_telemetry_span_backdated.
    fn test_open_telemetry_span_backdated() {

sdk/core/azure_core_opentelemetry/src/span.rs:352

  • Repository test guidance says test function names should not begin with test unless needed for disambiguation. Please drop the redundant prefix here as well.
    fn test_open_telemetry_span_backdated_with_parent() {

@NaluTripician NaluTripician self-assigned this Jul 20, 2026
@analogrelay analogrelay moved this from Needs Attention to Ready To Merge in CosmosDB Rust SDK and Driver Jul 20, 2026

@heaths heaths 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.

I'm good with this. Thanks! But I want @LarryOsterman to have one last look before merging.

@heaths
heaths merged commit 12c2744 into Azure:main Jul 20, 2026
13 checks passed
@github-project-automation github-project-automation Bot moved this from Ready To Merge to Done in CosmosDB Rust SDK and Driver Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Azure.Core The azure_core crate Cosmos The azure_cosmos crate

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants