Skip to content

Default to native transport on CRuby 4.0+ - #6419

Open
lloeki wants to merge 19 commits into
masterfrom
lloeki/native-transport-rollout
Open

lloeki wants to merge 19 commits into
masterfrom
lloeki/native-transport-rollout

Conversation

@lloeki

@lloeki lloeki commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

What does this PR do?

Enable native trace transport by default on CRuby 4.0.0+, preserving explicit overrides and unsupported-platform fallback.

Motivation:

Start a version-gated rollout.

Change log entry

Begin the progressive rollout of the native trace exporter, enabling it by default on CRuby 4.0.0 and later.

Additional Notes:

master
  └─ #6433 shared fixes — default false
       ├─ #6419 progressive — CRuby ≥4.0.0
       └─ #6426 unconditional — default true

Shared fixes · Progressive · Unconditional

All target master; either rollout includes the shared fixes. Registry metadata still needs confirmation.

How to test the change?

Ruby 2.5.9 and 4.0.1: 301 configuration/component and 189 native examples, 0 failures. Cohort boundaries use runtime stubs. RuboCop, Steep, and changelog schema checks passed locally.

Ruby 4.0.1 full main suite: 6,547 examples, 0 failures.

@lloeki lloeki added the AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos label Oct 5, 2026
lloeki added a commit that referenced this pull request Oct 5, 2026
Add the customer-facing changelog entry for CRuby 4.0.5 default
enablement and the explicit opt-out.

Refs: #6419
@dd-octo-sts dd-octo-sts Bot added the tracing label Oct 5, 2026
@datadog-prod-us1-3

datadog-prod-us1-3 Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Pipelines  Tests

❌ Errors

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 2 Pipeline jobs failed

Static Analysis | bundler-audit — 🔧 Needs a code fix, caused by this PR

View more details · View in GitHub Actions

Check Pull Request CI Status | all-jobs-are-green

View more details · View in GitHub Actions

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
• Patch Coverage: 96.55%
• Overall Coverage: 90.86% (+0.20%)

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 112099f | Docs | View more details | Give us feedback!

lloeki added a commit that referenced this pull request Oct 5, 2026
Begin the native trace exporter rollout with one exact Ruby version so
later releases do not expand the cohort automatically.

Keep explicit environment and programmatic overrides effective by
changing only the default of `tracing.native_transport`. Cover the
engine/version boundaries and native availability fallback.

Refs: #6419
@lloeki
lloeki force-pushed the lloeki/native-transport-rollout branch from b2215e6 to a4324d0 Compare October 5, 2026 15:18
@lloeki
lloeki marked this pull request as ready for review October 5, 2026 15:19
@lloeki
lloeki requested review from a team as code owners October 5, 2026 15:19
@lloeki
lloeki requested review from marcotc and vpellan and removed request for a team October 5, 2026 15:19
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-05T15:28:30.318169Z a4324d0 Draft marked ready
🔒 Security Review ✅ Completed 2026-10-05T15:31:30.947965Z a4324d0 Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Comment thread lib/datadog/tracing/configuration/settings.rb Outdated

@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: a4324d0ea3

ℹ️ 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 lib/datadog/tracing/configuration/settings.rb Outdated
Comment thread lib/datadog/tracing/configuration/settings.rb Outdated
lloeki added a commit that referenced this pull request Oct 5, 2026
Use `RubyVersion.is?` to select CRuby 4.0.6 and newer, including later
patch, minor, and major releases. Preserve explicit configuration
overrides and update the rollout tests and changelog.

Refs: #6419
@lloeki lloeki changed the title Default to native transport on CRuby 4.0.5 Default to native transport on CRuby 4.0.6+ Oct 5, 2026
@pr-commenter

pr-commenter Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-10-07 08:52:28

Comparing candidate commit 112099f in PR branch lloeki/native-transport-rollout with baseline commit 8a3b01c in branch master.

📊 Benchmarking dashboard

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

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

Hi! I tested the native transport setting with datadog-ci gem and discovered that it breaks datadog-ci's own transport.

The reason is that this code in build_writer method doesn't respect existing transport option:

        if settings.tracing.native_transport && (transport = build_native_transport(agent_settings))
          options = options.merge(transport: transport)
        end

It always replaces the transport with native without checking if another transport was configured.

lloeki added a commit that referenced this pull request Oct 6, 2026
Treat native transport as the default only when `:transport` is absent.
Replacing a supplied transport breaks `datadog-ci` and other custom
transports when the native transport setting is enabled.

Cover configuration, direct writer options, and asynchronous test mode
without constructing an unused native exporter.

Refs: #6419
lloeki added 5 commits October 6, 2026 17:57
Native transport is now the default, so any spec can initialise it.
Compile `libdatadog_api` before CRuby spec tasks rather than relying on
selected suites to build it incidentally.

Include Matrixfile tasks defined by later Rake imports as well as
already registered specs. This covers CI batches and direct Rake runs
without forcing compilation on unsupported Ruby engines.

Refs: #6426
Startup diagnostics only inspected Ruby HTTP adapters, leaving the
Agent URL empty when native transport was selected. Expose the actual
native destination and retain the existing HTTP and IO behaviour.

Cover TCP, IPv6 and Unix-socket destinations without requiring a live
Agent, restoring the configuration-reporting contract.

Refs: #6426
Forward the APM-disabled state to the existing libdatadog
client-computed-stats option. Standalone AppSec needs that header to
prevent the Agent from computing APM stats, just as Ruby HTTP does.

Verify the wire header with APM enabled and disabled, and reject
non-boolean values before allocating native configuration resources.

Refs: #6426
Closing a transport removed its fork hooks but left its Rust runtime
alive until GC. If the application forked before collecting that
exporter, child GC could hang destroying the unprepared runtime.

Release native resources deterministically under the transport locks,
outside the GVL, with ensure cleanup for interrupts. Captured fork
hooks safely become no-ops after close.

Cover child collection without a parent GC, idempotent native disposal,
and captured lifecycle callbacks. This does not resolve the separate
blocking-DNS limitation of native runtime destruction.

Refs: #6426
Determine the test Agent host from the native URL or the Ruby HTTP
adapter instead of assuming every selected transport has a `client`.

Preserve the existing HTTP replay of captured spans to the test Agent,
including its per-test configuration header. Pass that header through
transport options rather than reaching into a second client object.

Cover native TCP/IPv6/UDS, HTTP adapters and custom transports.

Refs: #6426
lloeki added 9 commits October 6, 2026 17:57
Expect the native transport keyword when assembling a default writer,
including asynchronous test mode. Stub native construction in these
assembly tests rather than creating unmanaged runtimes behind a mocked
writer factory. Native construction itself has dedicated coverage.

Refs: #6426
Serve sampling rates from a local HTTP server so both native and Ruby
transports receive the Agent response. WebMock only intercepts Ruby HTTP
and left the default native sampler without feedback.

Scope the existing WebMock header assertion to Ruby HTTP transport.
Native top-level header parity needs a separate implementation fix.

Refs: #6426
Sneakers pins Rake 12, whose FileUtils wrappers append a positional
options hash. Ruby 3 and later reject that hash when rake-compiler
copies a native extension into its staging directory.

Mark the merged options as keywords on Rubies that support it. Retain
Rake verbosity, dry-run behaviour, and explicit caller options without
changing the Sneakers appraisal or dependencies.

Refs: #6426
Declare profiling cleanup and compilation as ordered prerequisites.
The native-default prerequisite otherwise compiles libdatadog before
the helper action runs `clean`, deleting directories that Rake considers
already created. Profiling extension staging then fails with `ENOENT`.

Keep the clean build while letting Rake execute directory and native
compilation tasks in the correct order.

Refs: #6426
Reset ungrouped component callbacks without splitting native fork
callback triplets. Dropping only their child stage leaves transport
mutexes locked in the child and breaks nested forks.

Exercise a real grandchild send after the component reset helper runs.

Refs: #6426
Give synthetic fork callbacks a temporary registry and restore the
original registrations after each example. Fake child callbacks must
not reset real exporters, and clearing tests must not leave live native
runtimes unprepared for later genuine forks.

Close tracers owned by telemetry fixtures as well as their workers.
These fixtures otherwise retain exporters beyond the example lifetime.

Refs: #6426
Treat native transport as the default only when `:transport` is absent.
Replacing a supplied transport breaks `datadog-ci` and other custom
transports when the native transport setting is enabled.

Cover configuration, direct writer options, and asynchronous test mode
without constructing an unused native exporter.

Refs: #6419
Keep shared fixes independent of rollout policy. Build writer expectations
from the selected setting and verify ordinary HTTP selection when no
native setting is supplied.
Forward the resolved Agent timeout through the C bridge to the existing
libdatadog timeout setter, converting seconds to milliseconds. Native
requests previously ignored both programmatic and environment settings.

Validate timeout values before allocating native resources, and cover
HTTP/UDS configuration, environment resolution, and a nonresponding
Agent. The timeout applies per attempt; retries retain their policy.

Synchronise the close/fork race test on the callback snapshot rather
than waiting for a hook blocked by close. Its old ordering depended on
the implicit three-second timeout to unblock the send.

Refs: #6419, #6426
lloeki added 4 commits October 6, 2026 18:01
Attach customer-facing fixes to their shared PR so both rollout branches
inherit the same release notes without duplicating rollout announcements.

Refs: #6433
Begin the native trace exporter rollout with one exact Ruby version so
later releases do not expand the cohort automatically.

Keep explicit environment and programmatic overrides effective by
changing only the default of `tracing.native_transport`. Cover the
engine/version boundaries and native availability fallback.

Refs: #6419
Use `RubyVersion.is?` to select CRuby 4.0.6 and newer, including later
patch, minor, and major releases. Preserve explicit configuration
overrides and update the rollout tests and changelog.

Refs: #6419
Pin the inherited HTTP-default example to CRuby 4.0.5 so it remains
valid when the suite runs on a version inside the rollout cohort.

Refs: #6419
lloeki added a commit that referenced this pull request Oct 6, 2026
Use the native trace exporter for standard tracer writes when it is
available, retaining explicit configuration overrides and the existing
fallback on unsupported runtimes.

Exercise the eventual default through system tests and SSI/onboarding
CI before merging, independently of the progressive rollout in #6419.
@lloeki
lloeki force-pushed the lloeki/native-transport-rollout branch from 58ee2e4 to e63d7ec Compare October 6, 2026 16:06

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

tested again - compatibility issue with datadog-ci gem is fixed, thank you!

lloeki added a commit that referenced this pull request Oct 7, 2026
Use the full CRuby 4.0+ cohort for gradual enablement. Pierre\x27s BI
analysis estimates effective exposure below 10% of customers once
recent tracer adoption is accounted for.

Update version-boundary coverage and conditional-default metadata.

Refs: #6419
@lloeki lloeki changed the title Default to native transport on CRuby 4.0.6+ Default to native transport on CRuby 4.0+ Oct 7, 2026
Use the full CRuby 4.0+ cohort for gradual enablement.

Update version-boundary coverage and conditional-default metadata.

Refs: #6419
@lloeki
lloeki force-pushed the lloeki/native-transport-rollout branch from 117744c to 112099f Compare October 7, 2026 08:25

This branch has not been deployed

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

Labels

AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos tracing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants