Skip to content

feat(tracing): add support for DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT#337

Open
MilanGarnier wants to merge 12 commits into
milan.garnier/span-links-supportfrom
milan.garnier/propagation-behavior-extract
Open

feat(tracing): add support for DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT#337
MilanGarnier wants to merge 12 commits into
milan.garnier/span-links-supportfrom
milan.garnier/propagation-behavior-extract

Conversation

@MilanGarnier

@MilanGarnier MilanGarnier commented Jul 6, 2026

Copy link
Copy Markdown

Description

Add support for DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT, which controls how the
tracer handles incoming distributed-trace context during extraction:

  • continue (default): preserve the existing behavior and continue the
    extracted trace context.
  • restart: create a new root trace with a fresh sampling decision and add a
    span link to the extracted context.
  • ignore: discard the incoming context; extract_span returns
    Error::NO_SPAN_TO_EXTRACT, and baggage extraction is disabled.

Changes:

  • Add the public PropagationBehaviorExtract enum and parser, with values
    continue, restart, and ignore.
  • Add DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT (default: continue) to tracer
    configuration, config inversion metadata, and telemetry reporting. Both
    programmatic and environment configuration are supported; environment values
    take precedence.
  • Apply the behavior in Tracer::extract_span:
    • continue retains the existing extraction path.
    • restart creates a new trace and attaches a span link to the selected
      extracted context. The link records reason=propagation_behavior_extract,
      the selected extraction style in context_headers, the merged sampling
      decision as W3C flags, and the raw W3C tracestate when it belongs to the
      linked context.
    • ignore short-circuits context extraction.
  • Store the raw W3C tracestate during extraction so it can be retained on a
    restart link when applicable.
  • Update the system-test request handler so restart contexts without a remote
    parent use collision-safe synthetic handles.
  • Add unit coverage for configuration precedence/defaults and restart-link
    metadata, sampling flags, and selected-context behavior.
  • Simplify Span::add_link(const Span&, ...) to construct the link in one
    step.

This PR is stacked on milan.garnier/span-links-support, which supplies the
underlying span-link support; this diff is scoped to propagation behavior on
extraction.

Motivation

This aligns C++ with the extraction-behavior control available in other
Datadog tracers. It lets services avoid continuing an untrusted or foreign
trace while retaining a correlation link to its context.

System tests: DataDog/system-tests#7279

Jira ticket: APMAPI-1941

@MilanGarnier MilanGarnier added the enhancement New feature or request label Jul 6, 2026
@datadog-prod-us1-6

datadog-prod-us1-6 Bot commented Jul 6, 2026

Copy link
Copy Markdown

Tests

🔄 Datadog auto-retried 7 jobs - 4 passed on retry View in Datadog

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 16eb8a7 | Docs | Datadog PR Page | Give us feedback!

@pr-commenter

pr-commenter Bot commented Jul 7, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-07-13 13:20:10

Comparing candidate commit 16eb8a7 in PR branch milan.garnier/propagation-behavior-extract with baseline commit f033eef in branch milan.garnier/span-links-support.

Found 2 performance improvements and 1 performance regressions! Performance is the same for 5 metrics, 0 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:BM_HexPadded_uint64/NoPadding

  • 🟩 execution_time [-1.985ns; -1.886ns] or [-3.603%; -3.423%]

scenario:BM_HexPadded_uint64/WorstCasePadding

  • 🟩 execution_time [-1.989ns; -1.907ns] or [-4.002%; -3.836%]

scenario:BM_TraceTinyCCSource

  • 🟥 execution_time [+1.520ms; +1.947ms] or [+2.026%; +2.596%]

@MilanGarnier

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b642bbdb6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/datadog/tracer.cpp Outdated
Comment on lines +475 to +476
auto tracestate =
extracted_contexts[PropagationStyle::W3C].tracestate_full;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not attach W3C tracestate to a different context

When a request carries both Datadog and W3C headers with different trace IDs (the default extraction order prefers Datadog), merged_context and span_data refer to the Datadog trace, but this unconditionally copies the W3C tracestate. The restarted span link then combines Datadog trace/span IDs with tracestate from an unrelated W3C context, corrupting the link metadata; only carry W3C tracestate when that W3C context is the one being linked.

Useful? React with 👍 / 👎.

Comment thread src/datadog/tracer.cpp Outdated
Comment on lines +479 to +481
restarted_span.add_link(
SpanLink{span_data->trace_id, span_data->parent_id, tracestate,
link_attributes, nullopt}); // TODO: flags

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not emit span links with a zero span_id

When extraction accepts a root context (trace ID present with no parent, such as Datadog origin/root-context extraction), the code above normalizes the missing parent to 0, so restart mode reaches this constructor and serializes a span link with span_id 0. A span link should identify another span, so these requests produce invalid link metadata; skip the link or add it only when the extracted parent ID is non-zero.

Useful? React with 👍 / 👎.

Comment thread src/datadog/tracer.cpp Outdated
Comment thread bin/check-format Outdated
Comment thread src/datadog/tracer.cpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant