Skip to content

Add span backdating to core tracing traits#11

Closed
NaluTripician wants to merge 1 commit into
mainfrom
nalutripician/cosmos-diag-ws4c-backdating
Closed

Add span backdating to core tracing traits#11
NaluTripician wants to merge 1 commit into
mainfrom
nalutripician/cosmos-diag-ws4c-backdating

Conversation

@NaluTripician

Copy link
Copy Markdown
Owner

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):

  • Tracer::start_span_at(name, kind, attributes, start_time)
  • Tracer::start_span_with_parent_at(name, kind, attributes, parent, start_time)
  • Span::end_at(end_time)

azure_core_opentelemetry:

  • Implements the three methods against the raw OpenTelemetry
    SpanBuilder::with_start_time / SpanRef::end_with_timestamp APIs.
  • Refactors span construction into shared build_span / parent_context helpers so the
    four start_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, non-breaking)

The change is deliberately additive: all three 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. This matches the
    guidance that Heath is open to additive trait changes in minor releases.
  • 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.

std::time::SystemTime is used as the timestamp type: it's the natural cross-boundary type
(no new dependency in typespec_client_core) and maps directly onto the OpenTelemetry
with_start_time<T: Into<SystemTime>> and end_with_timestamp(SystemTime) signatures.

I considered a single SpanBuilder-style entry point instead of the paired *_at methods,
but the _at variants mirror the existing start_span / start_span_with_parent naming,
keep the diff minimal, and are the smallest additive surface that covers the tail-sampling
use case (backdated root + backdated attempt children). A builder can still be layered on
later without breaking these.

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 passed (incl. the 2 new backdating tests);
    typespec_client_core 139 passed

Note: workspace-wide --all-features / --all-targets runs fail in this environment for
reasons unrelated to this change (no local OpenSSL for openssl-sys; keyvault crates
whose git-symlink source files aren't materialized on Windows). Verification was scoped to
the affected core crates' lib + tests.

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

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>
@NaluTripician

Copy link
Copy Markdown
Owner Author

Re-targeted to upstream: superseded by Azure#4784 (same commit/branch). The effort reviews on upstream.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant