Skip to content

WIP: feat(tracer): align C span code with v1-compatible stub API (v2 groundwork) - #4046

Draft
Leiyks wants to merge 20 commits into
masterfrom
leiyks/dd-trace-php-v2
Draft

WIP: feat(tracer): align C span code with v1-compatible stub API (v2 groundwork)#4046
Leiyks wants to merge 20 commits into
masterfrom
leiyks/dd-trace-php-v2

Conversation

@Leiyks

@Leiyks Leiyks commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

THIS IS STILL WORK IS PROGRESS

What

Makes the PHP tracer build and send native V1 traces on the sidecar path,
using libdatadog's new index-based V1 span-builder FFI. The sidecar handles
protocol negotiation and downgrade, so the tracer always emits v1 on that path
and older agents keep working transparently.

Depends on libdatadog #2311
(pinned via the submodule bump in this PR).

Details

  • Native v1 build via the builder. The serializer builds a
    ddog_TracerPayloadV1Builder: strings go through the interned string table
    (with a per-zend_string* id cache for the fast path), promoted fields
    (service / name / resource / type / env / version / component / ids / times /
    error / kind) are set directly, attributes are emitted as typed values
    (string / int / double / bool / bytes), and span links / span events are built
    natively rather than folded into meta.
  • Sidecar path is v1-only. On the sidecar sender the tracer always emits v1;
    the sidecar negotiates against the agent /info and downgrades to v0.4 when
    the agent lacks v1 support (see [Bug]: PHPRedis infinite flushing loop #2311). In-process (PHP ≤ 8.2) stays v0.4.
  • Removed the DD_TRACE_AGENT_PROTOCOL_VERSION gate — protocol selection is
    no longer a tracer-side config knob; the sidecar decides.
  • cbindgen now emits the v1 setters directly (libdatadog defines them as
    explicit fns), so the interim hand-written components-rs/sidecar_v1_macro_ffi.h
    is gone.

Known follow-ups

  • Array / map attributes are currently serialized as JSON strings (no native
    AnyValue-array FFI yet).
  • process_tags still travel via span meta.
  • Sidecar 404 / fail-closed hardening is deferred.
  • The true /v1.0/traces wire is CI-verified.

@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Jul 17, 2026

Copy link
Copy Markdown

Pipelines  Tests

Unblock PR with BitsAI

⚠️ Warnings

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

🚦 146 Pipeline jobs failed

DataDog/apm-reliability/dd-trace-php | System Tests: [parametric] — ❌ 15 tests failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

❌ tests.parametric.test_otel_span_methods.Test_Otel_Span_Methods.test_otel_span_basic_reserved_attributes_overrides_analytics_event[FALSE-0-library_env0, param... from system_tests_suite
AssertionError: assert None == 0
 +  where None = <built-in method get of dict object at 0x7fb612007c00>('_dd1.sr.eausr')
 +    where <built-in method get of dict object at 0x7fb612007c00> = {'_dd.agent_psr': 1.0, '_sampling_priority_v1': 1.0, 'process.pid': 7.0, 'process_id': 7.0}.get

self = <tests.parametric.test_otel_span_methods.Test_Otel_Span_Methods object at 0x7fb612a17e30>
test_agent = <utils.docker_fixtures._test_agent.TestAgentAPI object at 0x7fb611ab6870>
test_library = <utils.docker_fixtures._test_clients._test_client_parametric.ParametricTestClientApi object at 0x7fb611b25b80>

    @pytest.mark.parametrize(
        ("analytics_event_value", "expected_metric_value"),
...
❌ tests.parametric.test_otel_span_methods.Test_Otel_Span_Methods.test_otel_span_basic_reserved_attributes_overrides_analytics_event[False-00-library_env0, para... from system_tests_suite
AssertionError: assert None == 0
 +  where None = <built-in method get of dict object at 0x7fb612314740>('_dd1.sr.eausr')
 +    where <built-in method get of dict object at 0x7fb612314740> = {'_dd.agent_psr': 1.0, '_sampling_priority_v1': 1.0, 'process.pid': 7.0, 'process_id': 7.0}.get

self = <tests.parametric.test_otel_span_methods.Test_Otel_Span_Methods object at 0x7fb612a17530>
test_agent = <utils.docker_fixtures._test_agent.TestAgentAPI object at 0x7fb611ab6870>
test_library = <utils.docker_fixtures._test_clients._test_client_parametric.ParametricTestClientApi object at 0x7fb611c80590>

    @pytest.mark.parametrize(
        ("analytics_event_value", "expected_metric_value"),
...
❌ tests.parametric.test_otel_span_methods.Test_Otel_Span_Methods.test_otel_span_basic_reserved_attributes_overrides_analytics_event[False-01-library_env0, para... from system_tests_suite
AssertionError: assert None == 0
 +  where None = <built-in method get of dict object at 0x7fb612bf8580>('_dd1.sr.eausr')
 +    where <built-in method get of dict object at 0x7fb612bf8580> = {'_dd.agent_psr': 1.0, '_sampling_priority_v1': 1.0, 'process.pid': 7.0, 'process_id': 7.0}.get

self = <tests.parametric.test_otel_span_methods.Test_Otel_Span_Methods object at 0x7fb612a17b60>
test_agent = <utils.docker_fixtures._test_agent.TestAgentAPI object at 0x7fb611ab6870>
test_library = <utils.docker_fixtures._test_clients._test_client_parametric.ParametricTestClientApi object at 0x7fb611b06600>

    @pytest.mark.parametrize(
        ("analytics_event_value", "expected_metric_value"),
...
↳ and 12 more — View all
DataDog/apm-reliability/dd-trace-php | System Tests: [php-fpm-8.5, default] — ❌ 5 tests failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

❌ tests.appsec.test_automated_payment_events.Test_Automated_Payment_Events_Stripe_Default_Rules.test_checkout_session[php-fpm-8.5] from system_tests_suite
KeyError: '_sampling_priority_v1'

self = <tests.appsec.test_automated_payment_events.Test_Automated_Payment_Events_Stripe_Default_Rules object at 0x7f127de2f020>

    def test_checkout_session(self):
        """R1"""
    
        def validator(span: DataDogLibrarySpan):
            assert span["meta"]["appsec.events.payments.creation.id"] == "cs_FAKE"
            assert span["metrics"]["appsec.events.payments.creation.amount_total"] == 950  # 100 * 10 * 0.9 + 50
...
❌ tests.appsec.test_automated_payment_events.Test_Automated_Payment_Events_Stripe_Default_Rules.test_payment_cancellation[php-fpm-8.5] from system_tests_suite
KeyError: '_sampling_priority_v1'

self = <tests.appsec.test_automated_payment_events.Test_Automated_Payment_Events_Stripe_Default_Rules object at 0x7f127de2eea0>

    def test_payment_cancellation(self):
        """R5"""
    
        def validator(span: DataDogLibrarySpan):
            assert span["meta"]["appsec.events.payments.cancellation.id"] == "pi_FAKE"
            assert span["metrics"]["appsec.events.payments.cancellation.amount"] == 1337
...
❌ tests.appsec.test_automated_payment_events.Test_Automated_Payment_Events_Stripe_Default_Rules.test_payment_failure[php-fpm-8.5] from system_tests_suite
KeyError: '_sampling_priority_v1'

self = <tests.appsec.test_automated_payment_events.Test_Automated_Payment_Events_Stripe_Default_Rules object at 0x7f127de2e8d0>

    def test_payment_failure(self):
        """R4"""
    
        def validator(span: DataDogLibrarySpan):
            assert span["meta"]["appsec.events.payments.failure.id"] == "pi_FAKE"
            assert span["metrics"]["appsec.events.payments.failure.amount"] == 1337
...
↳ and 2 more — View all
DataDog/apm-reliability/dd-trace-php | System Tests: [php-fpm-8.5]: [INTEGRATIONS] — ❌ 2 tests failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

❌ tests.integrations.test_db_integrations_sql.Test_MySql.test_span_kind[php-fpm-8.5] from system_tests_suite
KeyError: 'span.kind'

self = <tests.integrations.test_db_integrations_sql.Test_MySql object at 0x7f33cae988c0>
excluded_operations = ()

    def test_span_kind(self, excluded_operations: tuple[str, ...] = ()):
        """Describes the relationship between the Span, its parents, and its children in a Trace."""
    
        for _, span_meta in self.get_spans_meta(excluded_operations):
>           assert span_meta["span.kind"] == "client"
...
❌ tests.integrations.test_db_integrations_sql.Test_Postgres.test_span_kind[php-fpm-8.5] from system_tests_suite
KeyError: 'span.kind'

self = <tests.integrations.test_db_integrations_sql.Test_Postgres object at 0x7f33cae98e90>
excluded_operations = ()

    def test_span_kind(self, excluded_operations: tuple[str, ...] = ()):
        """Describes the relationship between the Span, its parents, and its children in a Trace."""
    
        for _, span_meta in self.get_spans_meta(excluded_operations):
>           assert span_meta["span.kind"] == "client"
...

View all 146 failed jobs.

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

🔄 Datadog auto-retried 1 job - 0 passed on retry View in Datadog

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 60.63% (-0.00%)

Useful? React with 👍 / 👎

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

@pr-commenter

pr-commenter Bot commented Jul 17, 2026

Copy link
Copy Markdown

Benchmarks [ tracer ]

Benchmark execution time: 2026-08-26 17:32:07

Comparing candidate commit 24cdec1 in PR branch leiyks/dd-trace-php-v2 with baseline commit 8d9060c in branch master.

Some scenarios are present only in baseline or only in candidate runs. If you didn't create or remove some scenarios in your branch, this maybe a sign of crashed benchmarks 💥💥💥
Check Gitlab CI job log to find if any benchmark has crashed.

Scenarios present only in baseline:

  • MessagePackSerializationBench/benchMessagePackSerialization
  • MessagePackSerializationBench/benchMessagePackSerialization-opcache

Found 1 performance improvements and 26 performance regressions! Performance is the same for 163 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_TeaSapiSpindown

  • 🟥 execution_time [+22.983µs; +46.112µs] or [+4.397%; +8.822%]

scenario:ContextPropagationBench/benchExtractHeaders128Bit-opcache

  • 🟩 execution_time [-980.533ns; -918.134ns] or [-54.535%; -51.064%]

scenario:HookBench/benchHookOverheadTraceFunction

  • 🟥 mem_peak [+144.760KB; +144.760KB] or [+3.211%; +3.211%]

scenario:HookBench/benchHookOverheadTraceMethod

  • 🟥 mem_peak [+144.759KB; +144.762KB] or [+3.166%; +3.166%]

scenario:HookBench/benchHookOverheadTraceMethod-opcache

  • 🟥 mem_peak [+64.312KB; +64.312KB] or [+3.012%; +3.012%]

scenario:PDOBench/benchPDOOverhead

  • 🟥 execution_time [+83.457µs; +87.627µs] or [+26.952%; +28.298%]

scenario:PDOBench/benchPDOOverhead-opcache

  • 🟥 execution_time [+85.989µs; +88.798µs] or [+28.039%; +28.955%]

scenario:PDOBench/benchPDOOverheadWithDBM

  • 🟥 execution_time [+84.941µs; +88.672µs] or [+27.475%; +28.682%]

scenario:PDOBench/benchPDOOverheadWithDBM-opcache

  • 🟥 execution_time [+83.199µs; +87.717µs] or [+27.029%; +28.496%]

scenario:PHPRedisBench/benchRedisOverhead

  • 🟥 execution_time [+368.832µs; +390.612µs] or [+29.106%; +30.824%]

scenario:PHPRedisBench/benchRedisOverhead-opcache

  • 🟥 execution_time [+367.361µs; +390.581µs] or [+28.094%; +29.870%]

scenario:SpanBench/benchDatadogAPI

  • 🟥 execution_time [+39.051µs; +41.545µs] or [+48.110%; +51.182%]

scenario:SpanBench/benchDatadogAPI-opcache

  • 🟥 execution_time [+40.089µs; +41.779µs] or [+49.624%; +51.716%]

scenario:SpanBench/benchOpenTelemetryAPI

  • 🟥 execution_time [+360.927µs; +384.727µs] or [+43.863%; +46.755%]
  • 🟥 mem_peak [+1.793MB; +1.793MB] or [+3.431%; +3.431%]

scenario:SpanBench/benchOpenTelemetryAPI-opcache

  • 🟥 execution_time [+359.432µs; +384.571µs] or [+47.267%; +50.573%]

scenario:SpanBench/benchOpenTelemetryInteroperability

  • 🟥 execution_time [+58.587µs; +61.681µs] or [+27.837%; +29.307%]
  • 🟥 mem_peak [+639.697KB; +639.706KB] or [+2.170%; +2.170%]

scenario:SpanBench/benchOpenTelemetryInteroperability-opcache

  • 🟥 execution_time [+340.937µs; +347.852µs] or [+169.435%; +172.872%]

scenario:TraceAnnotationsBench/benchTraceAnnotationOverhead-opcache

  • 🟥 mem_peak [+64.311KB; +64.314KB] or [+2.991%; +2.991%]

scenario:TraceFlushBench/benchFlushTrace

  • 🟥 execution_time [+175.944µs; +188.556µs] or [+48.745%; +52.239%]

scenario:TraceFlushBench/benchFlushTrace-opcache

  • 🟥 execution_time [+176.679µs; +192.321µs] or [+48.847%; +53.172%]

scenario:TraceSerializationBench/benchSerializeTrace

  • 🟥 execution_time [+1.567ms; +1.594ms] or [+337.343%; +343.118%]

scenario:WordPressBench/benchWordPressDdprof

  • 🟥 execution_time [+894.985µs; +1011.775µs] or [+2.820%; +3.188%]

scenario:WordPressBench/benchWordPressDdprof-opcache

  • 🟥 execution_time [+874.039µs; +1015.001µs] or [+2.752%; +3.196%]

scenario:WordPressBench/benchWordPressOverhead

  • 🟥 execution_time [+825.862µs; +1102.938µs] or [+2.803%; +3.743%]

scenario:WordPressBench/benchWordPressOverhead-opcache

  • 🟥 execution_time [+901.134µs; +1049.686µs] or [+3.050%; +3.552%]

@Leiyks
Leiyks force-pushed the leiyks/dd-trace-php-v2 branch from 2531886 to b29cd49 Compare July 27, 2026 15:20
@Leiyks
Leiyks force-pushed the leiyks/dd-trace-php-v2 branch 3 times, most recently from 10c7edf to 84351df Compare August 6, 2026 12:39
@Leiyks
Leiyks force-pushed the leiyks/dd-trace-php-v2 branch from 84351df to 73c262e Compare August 24, 2026 15:26
Leiyks added 18 commits August 25, 2026 17:33
Signed-off-by: Alexandre Rulleau <alexandre.rulleau@datadoghq.com>
Signed-off-by: Alexandre Rulleau <alexandre.rulleau@datadoghq.com>
Bring the tracer C code into consistency with the already-rewritten
v1-compatible span stub (tracer/ddtrace.stub.php), keeping the v04 wire
format byte-identical (libdatadog v1 FFI is not yet available).

- Regenerate ddtrace_arginfo.h from the stub; reorder the
  ddtrace_span_properties / ddtrace_root_span_data / ddtrace_span_stack
  structs to match the new property declaration order (PHP property
  offsets are bound to these C struct fields).
- Drop SpanEvent/SpanLink JsonSerializable + jsonSerialize(); relocate
  that logic into serializer.c so the _dd.span_links / events meta blobs
  are produced with identical bytes.
- Make component/spanKind sourced from the new SpanData properties,
  translated back into meta (span.kind/component) at serialize time so
  the v04 wire is unchanged. Register the new SpanKind class.
- Remove dead code for stub-removed functions and the
  DD_TRACE_WARN_LEGACY_DD_TRACE config key; complete the userland
  integration-analytics removal (Integration.php + call sites); delete
  tests orphaned by removed functions and rewrite the dd_trace_reset
  helper tests without gutting their coverage.

Refs APMLP-1197.
…DD_TRACE_WARN_LEGACY_DD_TRACE

The config key DD_TRACE_WARN_LEGACY_DD_TRACE was removed from
tracer/configuration.h, but metadata/supported-configurations.json was not
regenerated, causing the 'Configuration Consistency' CI job to fail. Ran
tooling/generate-supported-configurations.sh to sync.
RootSpanData extends SpanData, which already declares $env and $version.
The v1-stub alignment accidentally re-declared them on RootSpanData (they
were never on RootSpanData on master, and the ddtrace_root_span_data C struct
has no separate env/version slots -- they are inherited SpanData slots). On
PHP < 8.1 this redundant child redeclaration corrupts the RootSpanData
property table: env/version are var_dump'd twice and propagatedTags loses its
default, breaking tests/ext/active_span.phpt and span_clone.phpt on 7.0-8.0
(they passed on 8.1+). Removing the redeclaration from the stub and arginfo
aligns stub=arginfo=C struct and restores consistent output across all
versions; env/version remain available on RootSpanData via inheritance.
…on PHP 7

The new `attributes` property (stub default `= []`) was not materialized at
span/stack creation. On PHP < 8.0 array-typed property defaults become null
(see the ZVAL_EMPTY_ARRAY shim in functions.c) and are only lazily turned into
arrays when touched; since `attributes` is never touched during a plain span
lifecycle it var_dump'd as NULL on 7.0-7.4 (array(0){} on 8.0+), breaking
tests/ext/active_span.phpt and span_clone.phpt. Force-materialize it in
ddtrace_init_span and dd_alloc_span_stack (guarded to PHP < 8.0) so it is a
consistent empty array on every supported version, matching its stub default.
The chore that dropped integration (App Analytics) auto-tagging removed
Integration::addTraceAnalyticsIfEnabled and the per-integration
DD_TRACE_<integration>_ANALYTICS_* config, so the _dd1.sr.eausr metric is no
longer auto-added to integration spans. Align the tests:

- Delete the 25 TraceSearchConfigTest.php files (Laravel, Lumen, Symfony,
  ZendFramework, Custom) whose sole subject was the removed per-integration
  trace-analytics config.
- Drop the per-integration analytics setup + _dd1.sr.eausr metric assertions
  from the mixed PDO and SQLSRV integration tests, preserving all other span
  coverage.
- Remove Curl's dedicated testTraceAnalytics method + its data provider
  (per-integration analytics config matrix) and the stale DD_CURL_ANALYTICS_ENABLED
  teardown-cleanup entries in Curl/Guzzle.

The user-facing App Analytics API (Span::setMetric(Tag::ANALYTICS_KEY) ->
TraceAnalyticsProcessor, Tag::ANALYTICS_KEY constant) is intentionally kept by
this branch, so its tests (SpanTest, TraceAnalyticsProcessorTest,
UserAvailableConstantsTest, OpenTelemetry, ext/test_special_attributes) are
left intact.
Comment-only cleanup of the C span-consistency changes: trim the
multi-line explanatory blocks in serializer.c, span.c,
handlers_httpstreams.c and tracer_telemetry.c down to concise 1-2 line
comments. No behavior change.
The user-facing App Analytics API is now a deprecated no-op: it remains
callable (Tag::ANALYTICS_KEY, TraceAnalyticsProcessor, DD_TRACE_ANALYTICS_ENABLED
stay defined) but no longer applies any behavior nor emits the _dd1.sr.eausr
metric in-process or on the wire.

- serializer.c: drop the DD_TRACE_ANALYTICS_ENABLED/web-analytics emission,
  stop converting the analytics.event meta key to the metric (still consumed),
  and skip _dd1.sr.eausr in the metrics serialization loop.
- TraceAnalyticsProcessor::normalizeAnalyticsValue is now an empty no-op;
  Tag::ANALYTICS_KEY, the processor, and the api stubs are marked @deprecated.
- Tests rewritten to assert the API is callable and emits no _dd1.sr.eausr.
Bump the libdatadog submodule to PR #2156's head (938c110), which brings in
the v1 sidecar span encoder/decoder (#2145, #2174) via its main base.

Regenerate components-rs/{common,sidecar}.h with cbindgen (exposes the new
ddog_sidecar_send_trace_v1_shm / _bytes entrypoints and the
ASM_RAW_RESPONSE_BODY remote-config capability) and mirror libdatadog's
consolidated [workspace.dependencies] into the root Cargo.toml so the
path-dependency crates resolve their { workspace = true } inheritance.

Wire format is unchanged: v04 remains the default send path.
… V1 wire

Add DD_TRACE_AGENT_PROTOCOL_VERSION (default "0.4"). When set to "1"/"1.0",
assemble ddog_TracerMetadataV1 and call ddog_send_traces_to_sidecar_v1;
otherwise keep the unchanged V0.4 sidecar send. Hard gate; no /info negotiation.
Regenerate components-rs/*.h and Cargo.lock against the rebased libdatadog
submodule (v1 send FFI branch merged with libdatadog main). Picks up the
RemoteConfig DEBUG product enum, the v1 FFI comment trims, the agent_info
doc-comment tightening, and the zrip/ring lockfile additions.
@Leiyks
Leiyks force-pushed the leiyks/dd-trace-php-v2 branch from 73c262e to 0d3d03d Compare August 25, 2026 15:50
@Leiyks
Leiyks marked this pull request as ready for review August 26, 2026 11:56
@Leiyks
Leiyks requested review from a team as code owners August 26, 2026 11:56
@Leiyks
Leiyks requested review from a team as code owners August 26, 2026 11:56
@Leiyks
Leiyks requested review from dd-oleksii, greghuels and tabgok and removed request for a team August 26, 2026 11:56

@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: 0d3d03d6f7

ℹ️ 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 tracer/serializer.c Outdated
Comment on lines +1094 to +1096
static bool dd_v1_native_span_enabled(void) {
zend_string *pv = get_global_DD_TRACE_AGENT_PROTOCOL_VERSION();
return zend_string_equals_literal(pv, "1") || zend_string_equals_literal(pv, "1.0");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate native fields on the negotiated V1 path

When the protocol setting is 1/1.0 but agent info is unavailable or does not advertise /v1.0/traces, this helper still moves links and events exclusively into the native V1 fields, while auto_flush.c:75-100 deliberately falls back to the V0.4 sender. The V0.4 encoder expects the JSON values in _dd.span_links and events, so those spans silently lose all links and events during startup, with older agents, and whenever the non-sidecar sender is used. Base this decision on the same negotiated use_v1 condition as the sender, rather than the configuration value alone.

Useful? React with 👍 / 👎.

Comment thread tracer/span_stats.c
Comment on lines 112 to +114
zval *meta_env = pre->meta ? zend_hash_str_find(pre->meta, ZEND_STRL("env")) : NULL;
if (meta_env) {
pre->env_deprecated = true;
LOG(DEPRECATED, "Using \"env\" in meta is deprecated. Instead specify the env property directly on the span.");
zend_string *str = datadog_convert_to_str(meta_env);
pre->env_deprecated = false;
zval *prop_env = &span->property_env;

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 Preserve legacy env overrides during precomputation

When a span sets the supported legacy $span->meta['env'] override while its env property contains an inherited process environment, meta_env is now looked up but ignored. Consequently client-side stats are aggregated under the property environment via ddtrace_feed_span_to_concentrator() instead of the environment represented by the span, and the later property write in serializer.c:1914-1915 can replace the meta override on the wire. Restore the documented meta-first selection, even if it remains deprecated.

Useful? React with 👍 / 👎.

Comment thread tracer/span.c
Comment on lines +169 to +172
#if PHP_VERSION_ID < 80000
// PHP 7 array-typed properties default to null; materialize `attributes` to match its
// `= []` stub default (as on PHP 8).
ddtrace_property_array(&span->property_attributes);

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 Initialize attributes in the PHP 7 object creators

On PHP 7 this initialization only runs for spans allocated through the tracer's internal ddtrace_init_span() helper. Public direct construction such as new DDTrace\SpanData() or new DDTrace\RootSpanData() goes through the create_object callbacks in functions.c:244-269 instead, leaving the new attributes property as null because array defaults are deliberately rewritten to null on PHP 7. Directly constructed SpanStack objects have the same problem because their initialization was placed only in dd_alloc_span_stack(). Initialize these properties in the respective object creators so every construction path satisfies the declared array API.

Useful? React with 👍 / 👎.

Leiyks added 2 commits August 26, 2026 17:37
Stages 3+4 of the v1-native migration. The sidecar sender now always builds a
native libdatadog v1 TracerPayload via the new builder FFI and sends it with
ddog_send_traces_to_sidecar_v1; the sidecar negotiates v1-vs-v0.4 with the agent
and downgrades as needed, so the tracer-side DD_TRACE_AGENT_PROTOCOL_VERSION gate
is removed.

- serializer.c: convert each fully-built v0.4 span into the v1 builder (fields
  and meta/metrics/meta_struct via the v0.4 read getters, native links/events
  from the still-alive PHP span). Promoted fields (env/version/component/
  span.kind) use the dedicated setters and are excluded from the attribute map;
  chunk-level fields (sampling priority/origin/mechanism/128-bit trace-id/
  dropped) are routed to the chunk. Array/object attribute values, which have no
  native v1 attribute variant, are preserved as a JSON string. The v0.4 build
  stays byte-identical for the in-process sender and functions.c introspection.
- auto_flush.c: sidecar path always builds the v1 builder and sends v1; shrunk
  ddog_TracerMetadataV1 {hostname,env,app_version,runtime_id,git_commit_sha}. The
  in-process sender (PHP <= 8.2) stays on v0.4, unchanged.
- Remove the now-dead DD_TRACE_AGENT_PROTOCOL_VERSION config key and the
  ddog_agent_info_has_endpoint getter; regenerate datadog.h and
  supported-configurations.json.
- Bump libdatadog to the v1 send FFI (317c98d28) and regenerate cbindgen
  headers. Add a hand-written prototypes header (sidecar_v1_macro_ffi.h) for the
  macro-generated v1 setters that cbindgen cannot emit.
- Update the request-replayer span-event tests to assert native span events.
libdatadog now defines the v1 builder setters as explicit fns instead of
declarative-macro-generated ones, so cbindgen emits them into the generated
components-rs/sidecar.h. Bump the libdatadog submodule, regenerate sidecar.h
(now carries ddog_v1_set_span_* / ddog_v1_add_span_attr_* /
ddog_v1_add_event_attr_*), and remove the interim
components-rs/sidecar_v1_macro_ffi.h and its include in serializer.c.
@Leiyks
Leiyks marked this pull request as draft August 26, 2026 16:33
@Leiyks Leiyks changed the title feat(tracer): align C span code with v1-compatible stub API (v2 groundwork) WIP: feat(tracer): align C span code with v1-compatible stub API (v2 groundwork) Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant