Skip to content

feat: publish Linux OTel contexts - #4077

Merged
morrisonlevi merged 72 commits into
masterfrom
feat/otel-context
Aug 14, 2026
Merged

feat: publish Linux OTel contexts#4077
morrisonlevi merged 72 commits into
masterfrom
feat/otel-context

Conversation

@morrisonlevi

@morrisonlevi morrisonlevi commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

PROF-15487

Description

Publish standard OTel process and thread contexts from the tracer and make the profiler consume them for runtime identity and effective service metadata. Handle span, stack, Fiber, configuration, and fork lifecycle changes while retaining the legacy non-Linux path.

WIP for appsec.

Reviewer checklist

  • Test coverage seems ok.
  • Appropriate labels assigned.

@datadog-datadog-prod-us1

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

Copy link
Copy Markdown

Pipelines  Tests

Unblock PR with BitsAI

⚠️ Warnings

🚦 19 Pipeline jobs failed

DataDog/apm-reliability/dd-trace-php | ASAN test_c: [7.4, arm64]   View in Datadog   GitLab

🧪 1 Test failed

All test failures are known flaky.

❄️ Known flaky: tmp/build_extension/tests/ext/live-debugger/debugger_log_probe.phpt (Installing a live debugger log probe) from PHP.tmp.build_extension.tests.ext.live.debugger   View in Datadog
002+ 
003+ Fatal error: Uncaught Exception: wait for replay timeout in tmp/build_extension/tests/ext/live-debugger/live_debugger.inc:57
004+ Stack trace:
005+ #0 tmp/build_extension/tests/ext/live-debugger/debugger_log_probe.php(37): DebuggerLogReplayer->waitForDebuggerDataAndReplay()
006+ #1 {main}
007+   thrown in tmp/build_extension/tests/ext/live-debugger/live_debugger.inc on line 57
002- array(6) {
003-   ["service"]=>
004-   string(22) "debugger_log_probe.php"
005-   ["ddsource"]=>
...

Not introduced in this PR.

DataDog/apm-reliability/dd-trace-php | System Tests: [parametric]   View in Datadog   GitLab

🧪 2 Tests failed

tests.parametric.test_otel_api_interoperability.Test_Otel_API_Interoperability.test_concurrent_traces_in_order[library_env0, parametric-php] from system_tests_suite   View in Datadog
requests.exceptions.HTTPError: 500 Server Error: Internal Server Error for url: http://localhost:4504/trace/otel/start_span

self = <tests.parametric.test_otel_api_interoperability.Test_Otel_API_Interoperability object at 0x7f8a3e212270>
test_agent = <utils.docker_fixtures._test_agent.TestAgentAPI object at 0x7f8a3d27a870>
test_library = <utils.docker_fixtures._test_clients._test_client_parametric.ParametricTestClientApi object at 0x7f8a3d4306b0>

    def test_concurrent_traces_in_order(self, test_agent: TestAgentAPI, test_library: APMLibrary):
        """- Basic concurrent traces and spans"""
        with (
            test_library,
...
tests.parametric.test_otel_api_interoperability.Test_Otel_API_Interoperability.test_otel_start_after_datadog_span[library_env0, parametric-php] from system_tests_suite   View in Datadog
requests.exceptions.HTTPError: 500 Server Error: Internal Server Error for url: http://localhost:4501/trace/otel/start_span

self = <tests.parametric.test_otel_api_interoperability.Test_Otel_API_Interoperability object at 0x7fcc0c6e67e0>
test_agent = <utils.docker_fixtures._test_agent.TestAgentAPI object at 0x7fcc0b4e5fd0>
test_library = <utils.docker_fixtures._test_clients._test_client_parametric.ParametricTestClientApi object at 0x7fcc0b6b7e00>

    def test_otel_start_after_datadog_span(self, test_agent: TestAgentAPI, test_library: APMLibrary):
        """- Start a span using the OTel API while a span created using the Datadog API already exists"""
        with test_library:
            with (
...

DataDog/apm-reliability/dd-trace-php | ASAN test_c with multiple observers: [8.3]   View in Datadog   GitLab

View all 19 failed jobs.

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

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

🎯 Code Coverage (details)
Patch Coverage: 0.00%
Overall Coverage: 59.60% (-1.03%)

Useful? React with 👍 / 👎

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

@pr-commenter

pr-commenter Bot commented Jul 30, 2026

Copy link
Copy Markdown

Benchmarks [ tracer ]

Benchmark execution time: 2026-08-14 21:05:26

Comparing candidate commit cbd2d75 in PR branch feat/otel-context with baseline commit 22015fe in branch master.

Found 9 performance improvements and 4 performance regressions! Performance is the same for 181 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:ContextPropagationBench/benchInject64Bit-opcache

  • 🟩 execution_time [-11.649µs; -11.307µs] or [-84.600%; -82.122%]

scenario:MessagePackSerializationBench/benchMessagePackSerialization

  • 🟥 execution_time [+2.423µs; +4.197µs] or [+2.328%; +4.031%]

scenario:MessagePackSerializationBench/benchMessagePackSerialization-opcache

  • 🟥 execution_time [+2.306µs; +4.174µs] or [+2.159%; +3.906%]

scenario:SpanBench/benchOpenTelemetryAPI

  • 🟩 execution_time [-360.315µs; -350.235µs] or [-51.135%; -49.705%]
  • 🟩 mem_peak [-6.932MB; -6.932MB] or [-14.510%; -14.510%]

scenario:SpanBench/benchOpenTelemetryAPI-opcache

  • 🟩 execution_time [-336.435µs; -327.919µs] or [-51.563%; -50.258%]
  • 🟩 mem_peak [-6.829MB; -6.829MB] or [-15.270%; -15.270%]

scenario:SpanBench/benchOpenTelemetryInteroperability

  • 🟥 mem_peak [+643.606KB; +643.615KB] or [+2.232%; +2.232%]

scenario:SpanBench/benchOpenTelemetryInteroperability-opcache

  • 🟥 mem_peak [+641.572KB; +641.579KB] or [+2.478%; +2.478%]

scenario:TraceFlushBench/benchFlushTrace

  • 🟩 execution_time [-924.969µs; -911.531µs] or [-73.697%; -72.626%]

scenario:TraceFlushBench/benchFlushTrace-opcache

  • 🟩 execution_time [-981.376µs; -956.924µs] or [-40.596%; -39.584%]

scenario:TraceSerializationBench/benchSerializeTrace

  • 🟩 execution_time [-42.571µs; -28.229µs] or [-9.014%; -5.978%]

scenario:TraceSerializationBench/benchSerializeTrace-opcache

  • 🟩 execution_time [-45.877µs; -32.223µs] or [-11.305%; -7.941%]

@pr-commenter

pr-commenter Bot commented Jul 30, 2026

Copy link
Copy Markdown

Benchmarks [ appsec ]

Benchmark execution time: 2026-08-14 20:31:23

Comparing candidate commit cbd2d75 in PR branch feat/otel-context with baseline commit 22015fe in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 12 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 ----------------------------------'

Publish standard OTel process and thread contexts from the tracer and make the profiler consume them for runtime identity and effective service metadata. Handle span, stack, Fiber, configuration, and fork lifecycle changes while retaining the legacy non-Linux path.
@github-actions github-actions Bot added the profiling Relates to the Continuous Profiler label Jul 30, 2026
@pr-commenter

pr-commenter Bot commented Jul 30, 2026

Copy link
Copy Markdown

Benchmarks [ profiler ]

Benchmark execution time: 2026-08-14 20:03:57

Comparing candidate commit cbd2d75 in PR branch feat/otel-context with baseline commit 22015fe in branch master.

Found 0 performance improvements and 2 performance regressions! Performance is the same for 27 metrics, 7 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:php-profiler-timeline-memory-with-profiler

  • 🟥 execution_time [+36.645ms; +54.880ms] or [+3.348%; +5.013%]

scenario:walk_stack/1

  • 🟥 wall_time [+394.048ns; +400.293ns] or [+3.197%; +3.248%]

@morrisonlevi
morrisonlevi marked this pull request as ready for review July 30, 2026 18:59
@morrisonlevi
morrisonlevi requested review from a team as code owners July 30, 2026 18:59
@morrisonlevi
morrisonlevi requested review from pavlokhrebto and typotter and removed request for a team July 30, 2026 18:59

@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: 8d01de4429

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread profiling/src/process_context/linux.rs
Comment thread profiling/src/profiling/mod.rs Outdated
Comment thread profiling/src/profiling/mod.rs Outdated
Service, environment, version, and configured hostname can vary by request. Omit them from the process-wide context while retaining their thread-context key mapping and active values.
@morrisonlevi morrisonlevi changed the title feat(profiling): publish Linux OTel contexts feat: publish Linux OTel contexts Aug 3, 2026
@ivoanjo ivoanjo mentioned this pull request Aug 11, 2026
2 tasks

@ivoanjo ivoanjo 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 a big n00b on the codebase, yet I gave a pass on the OTel thread context bits, hopefully this helps!

Comment thread tracer/otel_context.c
Comment thread tracer/otel_context.c Outdated
Comment thread tracer/otel_context.c
Comment thread tracer/otel_context.c
Comment on lines +129 to +132
static void ddtrace_otel_record_end_update(datadog_otel_thr_ctx_rec *record) {
atomic_signal_fence(memory_order_release);
atomic_store_explicit(&record->valid, 1, memory_order_relaxed);
}

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.

Same note as for ddtrace_otel_detach -- the signal fence should come last for similar reasons

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I intentionally kept the release signal fence before the pointer store. This matches OTEP 4947 and libdatadog’s ThreadContext::attach(), which performs compiler_fence(Ordering::Release) followed by a relaxed TLS swap.

Comment thread tracer/otel_context.h
Comment on lines +21 to +23
_Atomic(uint64_t) span_id;
_Atomic(uint8_t) valid;
_Atomic(uint8_t) trace_flags;

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.

Minor: Maybe this is useful for the PHP profiler, so it's probably ok to keep; just wanted to point out that span_id and trace_flags don't actually need to be atomic, (e.g. similar to how trace_id and the others also don't need).

valid is the only one that needs to be treated specially, since in practice it's kind of a crappy lock -- 0 means lock is taken by writer, 1 means it's free for reading ;)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

These remain atomic because sometimes all we do is flip a single field. Since they are small enough, they will not tear in practice. Cheaper/faster when switching fibers which happens often for code that does this, or for trace propagation, etc.

gh-worker-dd-mergequeue-cf854d Bot pushed a commit to DataDog/libdatadog that referenced this pull request Aug 12, 2026
# What does this PR do?

If these items are not set, they should be missing, rather than sent with no value.

# Motivation

In PHP, these will not be set at all because they live in the OTel thread context instead of the process context.

# Additional Notes

Needed for DataDog/dd-trace-php#4077.

# How to test the change?

Tests the same, there just won't be "empty" items and they'll be missing instead.

Co-authored-by: bob.weinand <bob.weinand@datadoghq.com>
Comment thread tracer/span.c
Comment on lines +1002 to +1006
#ifdef __linux__
if (stack == DDTRACE_G(active_stack) && stack->active && SPANDATA(stack->active)->stack == stack) {
ddtrace_update_otel_thread_context_span_id(SPANDATA(stack->active));
}
#endif

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think the stack == DDTRACE_G(active_stack) is wrong, because all it does is updating the spans id. If there's a later swap to this closed spans stack, it'll be stale.
And let's mirror it like dd_drop_span, i.e.

    if (!stack->active || SPANDATA(stack->active)->stack != stack) {
        dd_close_entry_span_of_stack(stack);
#ifdef __linux__
    } else {
        ddtrace_update_otel_thread_context_span_id(SPANDATA(stack->active));
#endif
    }

@morrisonlevi morrisonlevi Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I believe I've fixed this, check the current code and refer to our conversation in Slack.

Comment thread tracer/span.c Outdated

@bwoebi bwoebi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Logic looks right to me now.

@morrisonlevi
morrisonlevi merged commit 018f212 into master Aug 14, 2026
2153 of 2167 checks passed
@morrisonlevi
morrisonlevi deleted the feat/otel-context branch August 14, 2026 22:16
@github-actions github-actions Bot added this to the 1.24.0 milestone Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

profiling Relates to the Continuous Profiler tracing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants