Skip to content

fix(ddtrace/tracer): decouple trace protocol v1.0 from client-side stats - #5122

Closed
darccio wants to merge 6 commits into
mainfrom
dario.castane/nostalgic-fermat-150b6e
Closed

fix(ddtrace/tracer): decouple trace protocol v1.0 from client-side stats#5122
darccio wants to merge 6 commits into
mainfrom
dario.castane/nostalgic-fermat-150b6e

Conversation

@darccio

@darccio darccio commented Aug 4, 2026

Copy link
Copy Markdown
Member

What does this PR do?

Fourth in a split of this PR into a reviewable stack, following feedback that the original was too large to review as one unit. See the sequence below. Stacked on #5148 — this PR's diff is scoped to just the decoupling itself; merge #5148 first.

The v1.0 protocol was gated on !canComputeStats(), commented "v1 requires CSS", but that's not actually true:

  • The Datadog Agent has accepted v1.0 payloads without CSS since the format's first release — its handler computes stats server-side when ClientComputedStats is false, exactly like it does for v0.4.
  • CSS is negotiated entirely out-of-band via the Datadog-Client-Computed-Stats header and the separate /v0.6/stats endpoint. The trace-send path is otherwise protocol-blind.
  • The v1 payload encoder reads no config and no agent capability state.
  • The original ETP RFC never mentions stats/CSS at all; its only gating rule is agent endpoint availability.

No commit, PR, or doc anywhere states a rationale for the coupling — it was introduced as an unexplained one-line addition to a test-enablement PR. The practical, silent consequence: DD_TRACE_STATS_COMPUTATION_ENABLED=false (or disabling the Agent's client_drop_p0s, e.g. via its probabilistic sampler) would downgrade the wire protocol with no log, even though 1.0 is the tracer's default.

Replaces the startup gate with (*config).effectiveTraceProtocol, a pure function of (requested protocol, agent v1 availability) evaluated at point of use. Nothing is downgraded in config and nothing is baked into a component, so the requested value stays inspectable and the effective one can't drift from it. Config telemetry now reports the effective protocol via ReportEffectiveTraceProtocol, which dedupes so repeated evaluation cannot inflate seqIDs.

TestNewConfigKeepsV1WhenCSSDisabled pins this end-to-end at the wire level: with CSS off and the agent advertising /v1.0/traces, the request must land on /v1.0/traces with a msgpack map body. Before this change it went to /v0.4/traces with an array body (0x91).

The stack

This PR was originally one 1215-line diff across 23 files (kakkoyun's feedback). It's now split as follows — ✅ merged into main, 🔵 open:

  1. #5146 test(ddtrace/x/agenttest): configurable mock-agent /info response — base main
  2. #5147 refactor(ddtrace/tracer): transport derives URL from payload protocol — stacked on test(ddtrace/x/agenttest): make the mock agent's /info response configurable #5146
  3. #5148 refactor(internal/config): rename TraceProtocolRequestedTraceProtocol — stacked on refactor(ddtrace/tracer): derive the trace-intake URL from the payload's protocol #5147
  4. This PR — the CSS decoupling itself — stacked on refactor(internal/config): rename TraceProtocol to RequestedTraceProtocol #5148
  5. (to follow) fix(ddtrace/tracer): runtime re-evaluation of agent v1 support — stacked on this PR
  6. (to follow) feat(ddtrace/tracer): trace protocol observability (startup log + downgrade diagnostic) — stacked on Matt2 #5, above

Independent siblings, not part of this chain:

Notes for reviewers

Reviewer's Checklist

  • Changed code has unit tests for its functionality at or near 100% coverage.
  • System-Tests covering this feature have been added and enabled with the va.b.c-dev version tag.
  • There is a benchmark for any new code, or changes to existing code.
  • If this interacts with the agent in a new way, a system test has been added. (protocol/capability negotiation covered by unit tests against a mock agent)
  • New code is free of linting errors. You can check this by running make lint locally.
  • New code doesn't break existing tests. You can check this by running make test locally.
  • Add an appropriate team label so this PR gets put in the right place for the release notes.
  • All generated files are up to date. You can check this by running make generate locally.
  • Non-trivial go.mod changes, e.g. adding new modules, are reviewed by @DataDog/dd-trace-go-guild. (no go.mod changes in this PR)

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Config Audit

PACKAGE: contrib/cloud.google.com/go/pubsubtrace
  STATUS      CONFIG                                            CALL_SITES
  UNMIGRATED  DD_GOOGLE_CLOUD_PUBSUB_PROPAGATION_AS_SPAN_LINKS  1

PACKAGE: contrib/confluentinc/confluent-kafka-go/kafkatrace
  STATUS      CONFIG                            CALL_SITES
  UNMIGRATED  DD_TRACE_KAFKA_ANALYTICS_ENABLED  1

PACKAGE: ddtrace/opentelemetry/log
  STATUS      CONFIG                            CALL_SITES
  STILL_READ  DD_AGENT_HOST                     2
  STILL_READ  DD_ENV                            1
  STILL_READ  DD_SERVICE                        1
  STILL_READ  DD_TAGS                           1
  STILL_READ  DD_TRACE_AGENT_URL                2
  STILL_READ  DD_TRACE_REPORT_HOSTNAME          1
  STILL_READ  DD_VERSION                        1
  STILL_READ  OTEL_EXPORTER_OTLP_ENDPOINT       4
  STILL_READ  OTEL_EXPORTER_OTLP_HEADERS        2
  STILL_READ  OTEL_EXPORTER_OTLP_PROTOCOL       2
  UNMIGRATED  DD_HOSTNAME                       1
  UNMIGRATED  OTEL_BLRP_EXPORT_TIMEOUT          1
  UNMIGRATED  OTEL_BLRP_MAX_EXPORT_BATCH_SIZE   1
  UNMIGRATED  OTEL_BLRP_MAX_QUEUE_SIZE          1
  UNMIGRATED  OTEL_BLRP_SCHEDULE_DELAY          1
  UNMIGRATED  OTEL_EXPORTER_OTLP_LOGS_ENDPOINT  4
  UNMIGRATED  OTEL_EXPORTER_OTLP_LOGS_HEADERS   2
  UNMIGRATED  OTEL_EXPORTER_OTLP_LOGS_PROTOCOL  2
  UNMIGRATED  OTEL_EXPORTER_OTLP_LOGS_TIMEOUT   1
  UNMIGRATED  OTEL_EXPORTER_OTLP_TIMEOUT        1
  UNMIGRATED  OTEL_RESOURCE_ATTRIBUTES          1

PACKAGE: ddtrace/opentelemetry/metric
  STATUS      CONFIG                                             CALL_SITES
  STILL_READ  DD_AGENT_HOST                                      2
  STILL_READ  DD_ENV                                             1
  STILL_READ  DD_METRICS_OTEL_ENABLED                            1
  STILL_READ  DD_SERVICE                                         1
  STILL_READ  DD_TAGS                                            1
  STILL_READ  DD_TRACE_AGENT_URL                                 2
  STILL_READ  DD_TRACE_REPORT_HOSTNAME                           1
  STILL_READ  DD_VERSION                                         1
  STILL_READ  OTEL_EXPORTER_OTLP_ENDPOINT                        2
  STILL_READ  OTEL_EXPORTER_OTLP_HEADERS                         1
  STILL_READ  OTEL_EXPORTER_OTLP_METRICS_ENDPOINT                2
  STILL_READ  OTEL_EXPORTER_OTLP_METRICS_HEADERS                 1
  STILL_READ  OTEL_EXPORTER_OTLP_METRICS_PROTOCOL                2
  STILL_READ  OTEL_EXPORTER_OTLP_PROTOCOL                        2
  STILL_READ  OTEL_METRICS_EXPORTER                              1
  UNMIGRATED  DD_HOSTNAME                                        1
  UNMIGRATED  OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE  1
  UNMIGRATED  OTEL_EXPORTER_OTLP_TIMEOUT                         1
  UNMIGRATED  OTEL_RESOURCE_ATTRIBUTES                           1
  UNMIGRATED  OTEL_SERVICE_NAME                                  1

PACKAGE: ddtrace/tracer
  STATUS      CONFIG                                    CALL_SITES
  STILL_READ  DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT     1
  STILL_READ  DD_TRACE_PROPAGATION_EXTRACT_FIRST        1
  STILL_READ  DD_TRACE_PROPAGATION_STYLE_EXTRACT        1
  STILL_READ  DD_TRACE_PROPAGATION_STYLE_INJECT         1
  UNMIGRATED  DD_APM_TRACING_ENABLED                    1
  UNMIGRATED  DD_LLMOBS_AGENTLESS_ENABLED               1
  UNMIGRATED  DD_LLMOBS_ENABLED                         1
  UNMIGRATED  DD_LLMOBS_ML_APP                          1
  UNMIGRATED  DD_LLMOBS_PROJECT_NAME                    1
  UNMIGRATED  DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED  1
  UNMIGRATED  DD_TRACE_DEBUG_SEELOG_WORKAROUND          1
  UNMIGRATED  OTEL_TRACES_SAMPLER_ARG                   1

PACKAGE: instrumentation
  STATUS      CONFIG                                       CALL_SITES
  STILL_READ  DD_DATA_STREAMS_ENABLED                      1
  UNMIGRATED  DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED  1

PACKAGE: instrumentation/graphql
  STATUS      CONFIG                             CALL_SITES
  UNMIGRATED  DD_TRACE_GRAPHQL_ERROR_EXTENSIONS  1

PACKAGE: instrumentation/httptrace
  STATUS      CONFIG                                                 CALL_SITES
  UNMIGRATED  DD_GOOGLE_CLOUD_PUBSUB_PROPAGATION_AS_SPAN_LINKS       1
  UNMIGRATED  DD_TRACE_BAGGAGE_TAG_KEYS                              1
  UNMIGRATED  DD_TRACE_CLIENT_IP_ENABLED                             1
  UNMIGRATED  DD_TRACE_HTTP_SERVER_ERROR_STATUSES                    1
  UNMIGRATED  DD_TRACE_HTTP_URL_QUERY_STRING_ALLOWLIST               1
  UNMIGRATED  DD_TRACE_HTTP_URL_QUERY_STRING_ALLOWLIST_CLIENT        1
  UNMIGRATED  DD_TRACE_HTTP_URL_QUERY_STRING_ALLOWLIST_SERVER        1
  UNMIGRATED  DD_TRACE_HTTP_URL_QUERY_STRING_DISABLED                1
  UNMIGRATED  DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED               1
  UNMIGRATED  DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP               2
  UNMIGRATED  DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT  1
  UNMIGRATED  DD_TRACE_RESOURCE_RENAMING_ENABLED                     1

PACKAGE: instrumentation/internal/namingschema
  STATUS      CONFIG                                             CALL_SITES
  STILL_READ  DD_SERVICE                                         1
  STILL_READ  DD_TRACE_SPAN_ATTRIBUTE_SCHEMA                     1
  UNMIGRATED  DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED  1

PACKAGE: internal
  STATUS      CONFIG                         CALL_SITES
  STILL_READ  DD_AGENT_HOST                  1
  STILL_READ  DD_TAGS                        1
  STILL_READ  DD_TRACE_AGENT_PORT            1
  STILL_READ  DD_TRACE_AGENT_URL             1
  UNMIGRATED  DD_EXTERNAL_ENV                1
  UNMIGRATED  DD_GIT_COMMIT_SHA              1
  UNMIGRATED  DD_GIT_REPOSITORY_URL          1
  UNMIGRATED  DD_TRACE_GIT_METADATA_ENABLED  1

PACKAGE: internal/appsec
  STATUS      CONFIG           CALL_SITES
  UNMIGRATED  DD_APPSEC_RULES  1

PACKAGE: internal/appsec/config
  STATUS      CONFIG                                                CALL_SITES
  UNMIGRATED  DD_API_SECURITY_DOWNSTREAM_BODY_ANALYSIS_SAMPLE_RATE  1
  UNMIGRATED  DD_API_SECURITY_ENABLED                               1
  UNMIGRATED  DD_API_SECURITY_MAX_DOWNSTREAM_REQUEST_BODY_ANALYSIS  1
  UNMIGRATED  DD_API_SECURITY_PROXY_SAMPLE_RATE                     1
  UNMIGRATED  DD_API_SECURITY_REQUEST_SAMPLE_RATE                   1
  UNMIGRATED  DD_API_SECURITY_SAMPLE_DELAY                          1
  UNMIGRATED  DD_APM_TRACING_ENABLED                                1
  UNMIGRATED  DD_APPSEC_AGENTIC_ONBOARDING                          1
  UNMIGRATED  DD_APPSEC_ENABLED                                     1
  UNMIGRATED  DD_APPSEC_MAX_STACK_TRACE_DEPTH                       1
  UNMIGRATED  DD_APPSEC_RASP_ENABLED                                1
  UNMIGRATED  DD_APPSEC_RULES                                       1
  UNMIGRATED  DD_APPSEC_SCA_ENABLED                                 1
  UNMIGRATED  DD_APPSEC_STACK_TRACE_ENABLED                         1
  UNMIGRATED  DD_APPSEC_TRACE_RATE_LIMIT                            1
  UNMIGRATED  DD_APPSEC_WAF_TIMEOUT                                 1

PACKAGE: internal/bazel
  STATUS      CONFIG                                  CALL_SITES
  UNMIGRATED  DD_TEST_OPTIMIZATION_MANIFEST_FILE      1
  UNMIGRATED  DD_TEST_OPTIMIZATION_PAYLOADS_IN_FILES  1

PACKAGE: internal/civisibility/envconfig
  STATUS      CONFIG                   CALL_SITES
  STILL_READ  DD_CIVISIBILITY_ENABLED  1

PACKAGE: internal/civisibility/integrations
  STATUS      CONFIG                                               CALL_SITES
  STILL_READ  DD_SERVICE                                           1
  STILL_READ  DD_TRACE_DEBUG                                       1
  UNMIGRATED  DD_CIVISIBILITY_CODE_COVERAGE_REPORT_UPLOAD_ENABLED  1
  UNMIGRATED  DD_CIVISIBILITY_FLAKY_RETRY_COUNT                    1
  UNMIGRATED  DD_CIVISIBILITY_FLAKY_RETRY_ENABLED                  1
  UNMIGRATED  DD_CIVISIBILITY_GIT_UPLOAD_ENABLED                   1
  UNMIGRATED  DD_CIVISIBILITY_IMPACTED_TESTS_DETECTION_ENABLED     1
  UNMIGRATED  DD_CIVISIBILITY_SUBTEST_FEATURES_ENABLED             1
  UNMIGRATED  DD_CIVISIBILITY_TOTAL_FLAKY_RETRY_COUNT              1
  UNMIGRATED  DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES            1
  UNMIGRATED  DD_TEST_MANAGEMENT_ENABLED                           1

PACKAGE: internal/civisibility/integrations/gotesting
  STATUS      CONFIG                                                           CALL_SITES
  UNMIGRATED  DD_CIVISIBILITY_INTERNAL_PARALLEL_EARLY_FLAKE_DETECTION_ENABLED  1
  UNMIGRATED  DD_TEST_MANAGEMENT_ENABLED                                       1

PACKAGE: internal/civisibility/integrations/logs
  STATUS      CONFIG                        CALL_SITES
  UNMIGRATED  DD_CIVISIBILITY_LOGS_ENABLED  1

PACKAGE: internal/civisibility/utils
  STATUS      CONFIG                              CALL_SITES
  STILL_READ  DD_SERVICE                          1
  UNMIGRATED  DD_ACTION_EXECUTION_ID              1
  UNMIGRATED  DD_PIPELINE_EXECUTION_ID            1
  UNMIGRATED  DD_TEST_OPTIMIZATION_ENV_DATA_FILE  1
  UNMIGRATED  DD_TEST_SESSION_NAME                1

PACKAGE: internal/civisibility/utils/net
  STATUS      CONFIG                             CALL_SITES
  STILL_READ  DD_API_KEY                         1
  STILL_READ  DD_CIVISIBILITY_AGENTLESS_ENABLED  1
  STILL_READ  DD_CIVISIBILITY_AGENTLESS_URL      1
  STILL_READ  DD_ENV                             1
  STILL_READ  DD_SERVICE                         1
  STILL_READ  DD_SITE                            1
  STILL_READ  DD_TAGS                            1
  STILL_READ  DD_VERSION                         1
  UNMIGRATED  DD_CODE_COVERAGE_FLAGS             1

PACKAGE: internal/civisibility/utils/telemetry
  STATUS      CONFIG                                         CALL_SITES
  UNMIGRATED  DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER  1

PACKAGE: internal/clientip
  STATUS      CONFIG                     CALL_SITES
  UNMIGRATED  DD_TRACE_CLIENT_IP_HEADER  1

PACKAGE: internal/globalconfig
  STATUS      CONFIG                           CALL_SITES
  UNMIGRATED  DD_INSTRUMENTATION_INSTALL_ID    1
  UNMIGRATED  DD_INSTRUMENTATION_INSTALL_TIME  1
  UNMIGRATED  DD_INSTRUMENTATION_INSTALL_TYPE  1

PACKAGE: internal/hostname
  STATUS      CONFIG       CALL_SITES
  UNMIGRATED  DD_HOSTNAME  1

PACKAGE: internal/namingschema
  STATUS      CONFIG                                             CALL_SITES
  STILL_READ  DD_SERVICE                                         1
  STILL_READ  DD_TRACE_SPAN_ATTRIBUTE_SCHEMA                     1
  UNMIGRATED  DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED  1

PACKAGE: internal/processtags
  STATUS      CONFIG                                          CALL_SITES
  UNMIGRATED  DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED  1

PACKAGE: internal/remoteconfig
  STATUS      CONFIG                                  CALL_SITES
  STILL_READ  DD_ENV                                  1
  UNMIGRATED  DD_RC_TUF_ROOT                          1
  UNMIGRATED  DD_REMOTE_CONFIGURATION_ENABLED         1
  UNMIGRATED  DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS  1

PACKAGE: internal/telemetry
  STATUS      CONFIG                                             CALL_SITES
  STILL_READ  DD_API_KEY                                         1
  STILL_READ  DD_SITE                                            1
  UNMIGRATED  DD_API_SECURITY_ENDPOINT_COLLECTION_MESSAGE_LIMIT  1
  UNMIGRATED  DD_INSTRUMENTATION_TELEMETRY_ENABLED               1
  UNMIGRATED  DD_TELEMETRY_DEBUG                                 1
  UNMIGRATED  DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED         1
  UNMIGRATED  DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL           1
  UNMIGRATED  DD_TELEMETRY_HEARTBEAT_INTERVAL                    1
  UNMIGRATED  DD_TELEMETRY_LOG_COLLECTION_ENABLED                1
  UNMIGRATED  DD_TELEMETRY_METRICS_ENABLED                       1

PACKAGE: openfeature
  STATUS      CONFIG                                                     CALL_SITES
  STILL_READ  DD_ENV                                                     2
  STILL_READ  DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED                  1
  STILL_READ  DD_SERVICE                                                 2
  STILL_READ  DD_VERSION                                                 2
  UNMIGRATED  DD_EXPERIMENTAL_FLAGGING_PROVIDER_SPAN_ENRICHMENT_ENABLED  1
  UNMIGRATED  DD_FLAGGING_EVALUATION_COUNTS_ENABLED                      1

PACKAGE: profiler
  STATUS      CONFIG                                    CALL_SITES
  STILL_READ  DD_API_KEY                                1
  STILL_READ  DD_ENV                                    1
  STILL_READ  DD_SERVICE                                1
  STILL_READ  DD_SITE                                   1
  STILL_READ  DD_TAGS                                   1
  STILL_READ  DD_TRACE_STARTUP_LOGS                     1
  STILL_READ  DD_VERSION                                1
  UNMIGRATED  DD_PROFILING_AGENTLESS                    1
  UNMIGRATED  DD_PROFILING_DEBUG_COMPRESSION_SETTINGS   1
  UNMIGRATED  DD_PROFILING_DELTA                        1
  UNMIGRATED  DD_PROFILING_ENABLED                      3
  UNMIGRATED  DD_PROFILING_ENDPOINT_COUNT_ENABLED       1
  UNMIGRATED  DD_PROFILING_EXECUTION_TRACE_ENABLED      1
  UNMIGRATED  DD_PROFILING_EXECUTION_TRACE_LIMIT_BYTES  1
  UNMIGRATED  DD_PROFILING_EXECUTION_TRACE_PERIOD       1
  UNMIGRATED  DD_PROFILING_FLUSH_ON_EXIT                1
  UNMIGRATED  DD_PROFILING_OUTPUT_DIR                   1
  UNMIGRATED  DD_PROFILING_UPLOAD_TIMEOUT               1
  UNMIGRATED  DD_PROFILING_URL                          1

@darccio

darccio commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

@codex review

@datadog-datadog-prod-us1

This comment has been minimized.

@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: 487f15c88e

ℹ️ 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 ddtrace/tracer/option.go Outdated
Comment thread ddtrace/tracer/log.go Outdated
Comment thread ddtrace/tracer/option.go Outdated
Comment thread ddtrace/tracer/option.go Outdated
Comment thread ddtrace/tracer/tracer.go Outdated
@pr-commenter

pr-commenter Bot commented Aug 4, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-08-07 17:17:14

Comparing candidate commit 5e7ee42 in PR branch dario.castane/nostalgic-fermat-150b6e with baseline commit f8998c4 in branch main.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 326 metrics, 0 unstable metrics, 1 flaky benchmarks without significant changes.

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 ----------------------------------'

Known flaky benchmarks

These benchmarks are marked as flaky and will not trigger a failure. Modify FLAKY_BENCHMARKS_REGEX to control which benchmarks are marked as flaky.

Known flaky benchmarks without significant changes:

  • scenario:BenchmarkOTLPTraceWriterFlush

@darccio

darccio commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 50061b9ace

ℹ️ 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".

@darccio darccio added performance/ignore-performance-regression AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos labels Aug 4, 2026
@darccio
darccio force-pushed the dario.castane/nostalgic-fermat-150b6e branch from f0aea3e to a23bd62 Compare August 4, 2026 14:34
darccio added a commit to DataDog/system-tests that referenced this pull request Aug 4, 2026
The previous commit covers CSS with the v1 protocol, but that pairing
worked even while the two were coupled, so it cannot detect the coupling.
The discriminating case is the mirror: v1 pinned while CSS is off.

Released dd-trace-go gates v1 on CSS capability and silently downgrades
to /v0.4/traces the moment stats computation is disabled. CSS is
negotiated entirely out of band -- a Datadog-Client-Computed-Stats header
and a separate /v0.6/stats endpoint, both handled identically by the
Agent on either protocol -- so disabling it has no bearing on the trace
wire format. DataDog/dd-trace-go#5122 removes the gate.

Add APM_TRACING_EFFICIENT_PAYLOAD_STATS_DISABLED, which is
APM_TRACING_EFFICIENT_PAYLOAD plus DD_TRACE_STATS_COMPUTATION_ENABLED
=false, and Test_V1PayloadWithStatsDisabled asserting every trace still
goes to /v1.0/traces in v1 format. The test first asserts no /v0.6/stats
payloads exist, so it fails loudly rather than passing vacuously if CSS
were somehow active.

Declared missing_feature for golang until #5122 ships, and for nodejs and
ruby to match every other class in this file (neither has working v1).
Java is deliberately left inheriting the file-level >=1.62.0: it supports
v1 when the protocol is pinned and has no CSS coupling, so it is the
language that proves the test is meaningful rather than vacuous.

Co-Authored-By: Claude <noreply@anthropic.com>
@darccio
darccio marked this pull request as ready for review August 4, 2026 15:04
@darccio
darccio requested review from a team as code owners August 4, 2026 15:04

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

ℹ️ 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 ddtrace/tracer/tracer.go Outdated

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

This is a lot of code changes and some of them are refactoring the code. It would have been nicer to isolate those into their own commits.

Comment thread ddtrace/tracer/doc.go
Comment thread internal/config/config.go
// traceProtocol is the Datadog trace protocol version the user requested
// (TraceProtocolV04 or TraceProtocolV1). This is independent of whether the
// trace-agent actually supports it — see RequestedTraceProtocol's doc.
traceProtocol float64

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.

We should have had a dedicated type for protocol. If we don't have a lot of conversion points. We support limited numbers here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Let me address this in a follow up.

darccio added a commit that referenced this pull request Aug 5, 2026
refreshAgentFeatures treated a 404 on /info the same as any other
fetch error: keep the last-known-good snapshot untouched. But an
agent that returns 404 on /info doesn't support /info at all, and
/v1.0/traces support postdates /info support, so that response IS
positive evidence v1 is gone. Retaining v1ProtocolAvailable=true in
that case meant a v1-capable agent rolled back to a pre-/info version
left the tracer posting to /v1.0/traces indefinitely, with the agent
rejecting every payload.

errAgentFeaturesNotSupported now resets the v1 upgrade streak and
clears v1ProtocolAvailable immediately, matching the existing
downgrade-is-immediate hysteresis, while every other dynamic field
stays at its last-known-good value since a 404 carries no fresh
snapshot to refresh them from. A generic fetch error (network
failure, timeout, decode failure) still returns early and leaves
everything untouched, since that's never evidence v1 became
unavailable.

Addresses a Codex review comment on #5122:
#5122 (comment)
@darccio

darccio commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

It would have been nicer to isolate those into their own commits.

Agreed. I'm juggling this with all the code reviews and dropped the bar 😓

darccio added 4 commits August 5, 2026 15:09
…gurable

The mock agent always advertised exactly the patterns registered via
HandleTraces, which left tests unable to express "the agent serves this
endpoint but does not advertise it" — the shape agent-capability
negotiation actually has to cope with.

Add SetInfoEndpoints to decouple what /info advertises from what is
registered, and use it to pin the ddtrace/tracer inspectable-tracer
harness to v0.4 on purpose. Those suites already run on v0.4, but only as
a side effect: the mock advertises no /v0.6/stats, so client-side stats
are unavailable and the tracer's protocol gate downgrades v1.0 -> v0.4.
Making the pin explicit is a no-op today and keeps the harness on a
deterministic wire format the next time that gate is touched.

Fix handleV1Traces while here. It built a bare &payloadV1{buf: body},
leaving header nil, so decodeBuffer panicked with an index-out-of-range
inside updateHeader. The handler has been registered but unreachable since
it was written, because the gate always selected v0.4 for this mock, so
the bug never surfaced. Add TestHandleV1TracesDecodesEncodedPayload, which
reproduces the panic without the fix.

Also guard the endpoints slice with the existing mutex on both sides.
HandleTraces appended to it unlocked while handleInfo read it; harmless
in practice because all registration precedes Start, but it is the kind
of thing SetInfoEndpoints invites tests to do at a less careful moment.
…d's protocol

httpTransport held a single mutable traceURL that had to be kept in step
with the configured protocol. Keeping them in step was the caller's job:
newConfig patched traceURL by string-comparing it against the v1 path
whenever it downgraded the protocol, which only worked as long as every
future protocol decision remembered to do the same.

Hold one immutable URL per protocol instead, computed once in
newHTTPTransport, and have send() select between them from the payload's
own protocol(). A payload is encoded for exactly one protocol and carries
that with it, so wire format and destination can no longer diverge — not
because a lock protects them, but because there is no shared mutable
state left to desynchronize. newConfig's URL patch-up goes away, and
resolveTraceURL with it.

This also fixes reportAPIErrorsMetric, which passed a hardcoded
tracesAPIPath: a failed v1.0 send was reported to
datadog.tracer.api.errors tagged endpoint:/v0.4/traces.

endpoint() gains a protocol argument for the startup diagnostics probe.
It is documented as diagnostics-only — an actual send never consults it,
so it cannot reintroduce the mismatch.

No behaviour change beyond the metric tag: the protocol downgrade still
happens in config, and the writer still reads it when creating a payload.
…ocol

The name read like "the protocol in use", but the value is only what was
asked for — it says nothing about whether the trace-agent can actually
serve it. Callers have to combine it with agent capability to get the
protocol on the wire, and the old name gave no hint of that, which is how
the gate in newConfig ended up being the only place that knew the
difference.

Rename to RequestedTraceProtocol and document the distinction. No
behaviour change: the OTLP-span-metrics override stays exactly as it was.

Also add TraceProtocolVersionString, the inverse of resolveTraceProtocol,
and use it in SetTraceProtocol. The env-var path reports
DD_TRACE_AGENT_PROTOCOL_VERSION through the provider as the raw string
("1.0"), while the setter reported a float64 — the same telemetry key
arrived with two different types depending on which source set it last.
The v1.0 protocol was gated on client-side stats being available
(!canComputeStats(), commented "v1 requires CSS"), but that isn't true:

  - The Datadog Agent has accepted v1.0 payloads without CSS since the
    format's first release; its handler computes stats server-side when
    ClientComputedStats is false, exactly as it does for v0.4.
  - CSS is negotiated out-of-band, via the Datadog-Client-Computed-Stats
    header and the separate /v0.6/stats endpoint. The trace-send path is
    otherwise protocol-blind.
  - The v1 payload encoder reads no config and no agent capability state.
  - The original ETP RFC never mentions stats or CSS; its only gating rule
    is agent endpoint availability.

No commit, PR or doc states a rationale for the coupling — it arrived as
an unexplained one-line addition to a test-enablement PR. The silent
consequence: DD_TRACE_STATS_COMPUTATION_ENABLED=false (or disabling the
Agent's client_drop_p0s, e.g. via its probabilistic sampler) downgraded
the wire protocol with no log, even though 1.0 is the tracer's default.

Replace the startup gate with (*config).effectiveTraceProtocol, a pure
function of (requested protocol, agent v1 availability) evaluated at point
of use. Nothing is downgraded in config and nothing is baked into a
component, so the requested value stays inspectable and the effective one
can't drift from it. Config telemetry now reports the effective protocol
via ReportEffectiveTraceProtocol, which dedupes so repeated evaluation
cannot inflate seqIDs.

TestNewConfigKeepsV1WhenCSSDisabled pins this end-to-end at the wire
level: with CSS off and the agent advertising /v1.0/traces, the request
must land on /v1.0/traces with a msgpack map body. Before this change it
went to /v0.4/traces with an array body (0x91).
@darccio
darccio changed the base branch from main to dario.castane/tp-3-config-rename August 5, 2026 15:50
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Aug 6, 2026
…gurable (#5146)

## What does this PR do?

First in a split of [#5122](#5122) into a reviewable stack of smaller PRs (see that PR for the full sequence and rationale). This PR is standalone against `main`.

The mock agent always advertised exactly the patterns registered via `HandleTraces`, which left tests unable to express "the agent serves this endpoint but does not advertise it" — the shape agent-capability negotiation actually has to cope with.

Adds `SetInfoEndpoints` to decouple what `/info` advertises from what is registered, and uses it to pin the `ddtrace/tracer` inspectable-tracer harness to v0.4 on purpose. Those suites already run on v0.4, but only as a side effect: the mock advertises no `/v0.6/stats`, so client-side stats are unavailable and the tracer's protocol gate downgrades v1.0 -> v0.4. Making the pin explicit is a no-op today and keeps the harness on a deterministic wire format the next time that gate is touched (removed later in this stack).

Also fixes `handleV1Traces`, found while testing this stack: it built a bare `&payloadV1{buf: body}`, leaving `header` nil, so `decodeBuffer` panicked with an index-out-of-range inside `updateHeader`. The handler had been registered but unreachable since it was written, because the gate always selected v0.4 for this mock, so the bug never surfaced. `TestHandleV1TracesDecodesEncodedPayload` reproduces the panic without the fix.

Also guards the `endpoints` slice with the existing mutex on both sides — `HandleTraces` appended to it unlocked while `handleInfo` read it.

### Reviewer's Checklist

- [x] Changed code has unit tests for its functionality at or near 100% coverage.
- [x] New code doesn't break existing tests. You can check this by running `make test` locally.
- [x] New code is free of linting errors. You can check this by running `make lint` locally.
- [x] All generated files are up to date. You can check this by running `make generate` locally.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: dario.castane <dario.castane@datadoghq.com>
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Aug 6, 2026
…d's protocol (#5147)

## What does this PR do?

Second in a split of [#5122](#5122) into a reviewable stack (see that PR for the full sequence). Stacked on [#5146](#5146) — this PR's diff is scoped to just the change below; merge #5146 first.

`httpTransport` held a single mutable `traceURL` that had to be kept in step with the configured protocol. Keeping them in step was the caller's job: `newConfig` patched `traceURL` by string-comparing it against the v1 path whenever it downgraded the protocol, which only worked as long as every future protocol decision remembered to do the same.

Holds one immutable URL per protocol instead, computed once in `newHTTPTransport`, and has `send()` select between them from the payload's own `protocol()`. A payload is encoded for exactly one protocol and carries that with it, so wire format and destination can no longer diverge — not because a lock protects them, but because there is no shared mutable state left to desynchronize. `newConfig`'s URL patch-up goes away, and `resolveTraceURL` with it.

This also fixes `reportAPIErrorsMetric`, which passed a hardcoded `tracesAPIPath`: a failed v1.0 send was reported to `datadog.tracer.api.errors` tagged `endpoint:/v0.4/traces`.

`endpoint()` gains a protocol argument for the startup diagnostics probe. It is documented as diagnostics-only — an actual send never consults it, so it cannot reintroduce the mismatch.

No behaviour change beyond the metric tag: the protocol downgrade still happens in config, and the writer still reads it when creating a payload.

### Reviewer's Checklist

- [x] Changed code has unit tests for its functionality at or near 100% coverage.
- [x] New code doesn't break existing tests. You can check this by running `make test` locally.
- [x] New code is free of linting errors. You can check this by running `make lint` locally.
- [x] All generated files are up to date. You can check this by running `make generate` locally.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: dario.castane <dario.castane@datadoghq.com>
@darccio
darccio force-pushed the dario.castane/tp-3-config-rename branch from 09ee283 to d906b29 Compare August 6, 2026 14:09
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Aug 6, 2026
…ocol (#5148)

## What does this PR do?

Third in a split of [#5122](#5122) into a reviewable stack (see that PR for the full sequence). Stacked on [#5147](#5147) — this PR's diff is scoped to just the change below; merge #5147 first.

The name `TraceProtocol` read like "the protocol in use", but the value is only what was asked for — it says nothing about whether the trace-agent can actually serve it. Callers have to combine it with agent capability to get the protocol on the wire, and the old name gave no hint of that, which is how the gate in `newConfig` ended up being the only place that knew the difference.

Renames to `RequestedTraceProtocol` and documents the distinction. No behaviour change: the OTLP-span-metrics override stays exactly as it was (removed later in this stack, in a sibling PR).

Also adds `TraceProtocolVersionString`, the inverse of `resolveTraceProtocol`, and uses it in `SetTraceProtocol`. The env-var path reports `DD_TRACE_AGENT_PROTOCOL_VERSION` through the provider as the raw string (`"1.0"`), while the setter reported a `float64` — the same telemetry key arrived with two different types depending on which source set it last.

### Reviewer's Checklist

- [x] Changed code has unit tests for its functionality at or near 100% coverage.
- [x] New code doesn't break existing tests. You can check this by running `make test` locally.
- [x] New code is free of linting errors. You can check this by running `make lint` locally.
- [x] All generated files are up to date. You can check this by running `make generate` locally.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: dario.castane <dario.castane@datadoghq.com>
Base automatically changed from dario.castane/tp-3-config-rename to main August 6, 2026 15:02
darccio added a commit to DataDog/system-tests that referenced this pull request Aug 7, 2026
The previous commit covers CSS with the v1 protocol, but that pairing
worked even while the two were coupled, so it cannot detect the coupling.
The discriminating case is the mirror: v1 pinned while CSS is off.

Released dd-trace-go gates v1 on CSS capability and silently downgrades
to /v0.4/traces the moment stats computation is disabled. CSS is
negotiated entirely out of band -- a Datadog-Client-Computed-Stats header
and a separate /v0.6/stats endpoint, both handled identically by the
Agent on either protocol -- so disabling it has no bearing on the trace
wire format. DataDog/dd-trace-go#5122 removes the gate.

Add APM_TRACING_EFFICIENT_PAYLOAD_STATS_DISABLED, which is
APM_TRACING_EFFICIENT_PAYLOAD plus DD_TRACE_STATS_COMPUTATION_ENABLED
=false, and Test_V1PayloadWithStatsDisabled asserting every trace still
goes to /v1.0/traces in v1 format. The test first asserts no /v0.6/stats
payloads exist, so it fails loudly rather than passing vacuously if CSS
were somehow active.

Declared missing_feature for golang until #5122 ships, and for nodejs and
ruby to match every other class in this file (neither has working v1).
Java is deliberately left inheriting the file-level >=1.62.0: it supports
v1 when the protocol is pinned and has no CSS coupling, so it is the
language that proves the test is meaningful rather than vacuous.

Co-Authored-By: Claude <noreply@anthropic.com>
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Aug 7, 2026
…metry (#5141)

## What does this PR do?

Part of a split of [#5122](#5122) into a reviewable stack (see that PR for the full sequence and rationale for the split).

`OTEL_TRACES_SPAN_METRICS_ENABLED=false` disables native stats computation when `DD_TRACE_STATS_COMPUTATION_ENABLED` was left at its default. That was done by writing the struct field directly, which skipped `configtelemetry.Report` — so telemetry kept reporting `DD_TRACE_STATS_COMPUTATION_ENABLED` as its default (`true`) while the tracer behaved as `false`, and the discrepancy was invisible from the outside.

Routes it through `SetStatsComputationEnabled` with `OriginCalculated`, which is what every other derived value in `loadConfig` does. Safe to call here: the config being built is still local, so taking its mutex cannot contend.

### Motivation

Unrelated telemetry-accuracy fix that surfaced while working on the trace-protocol/CSS decoupling in #5122; split out because it's independent of that change.

### Reviewer's Checklist

- [x] Changed code has unit tests for its functionality at or near 100% coverage.
- [x] New code doesn't break existing tests. You can check this by running `make test` locally.
- [x] New code is free of linting errors. You can check this by running `make lint` locally.
- [x] All generated files are up to date. You can check this by running `make generate` locally.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: dario.castane <dario.castane@datadoghq.com>
darccio added a commit that referenced this pull request Aug 7, 2026
…abled

TraceProtocol special-cased OTLPSpanMetricsEnabled and returned v0.4
unconditionally, on the rationale that the trace transport "must stay on
v0.4 where the Datadog Agent can see the Datadog-Client-Computed-Stats
header". That rationale doesn't hold: the header is a request header the
Agent reads on either protocol, and OTLP span metrics are aggregated by
their own concentrator and shipped over the separate /v0.6/stats endpoint.
Neither depends on the /vX/traces wire format.

This is the same disproven reasoning as the CSS gate removed by
#5122, applied to a second knob, so it goes the same
way.

The cross-repo prerequisite this depended on is already satisfied:
DataDog/system-tests#7403 (merged 2026-07-29) added /v1.0/traces to the
trace-request filter tuple in tests/parametric/test_otlp_trace_metrics.py,
which is exactly what this change needed upstream before it could land
without breaking that test's span-metrics configuration.
darccio added a commit that referenced this pull request Aug 7, 2026
… fix

The comment above the v1->v0.4 downgrade check still described
RequestedTraceProtocol() as forcing v0.4 for OTLP span metrics, which
this PR's config fix removes. The CSS-required gate is unrelated and
still applies (tracked separately by #5122).
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 performance/ignore-performance-regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants