feat(tracer): align C span code with v1-compatible stub API (v2 groundwork)#4046
feat(tracer): align C span code with v1-compatible stub API (v2 groundwork)#4046Leiyks wants to merge 9 commits into
Conversation
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.
|
Benchmarks [ tracer ]Benchmark execution time: 2026-07-22 15:28:37 Comparing candidate commit 55c6254 in PR branch 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 💥💥💥 Scenarios present only in baseline:
Found 5 performance improvements and 11 performance regressions! Performance is the same for 174 metrics, 0 unstable metrics.
|
…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.
What & why
Part of APMLP-1197 (dd-trace-php v1/v2 roadmap). The v1-compatible span
stub API (tracer/ddtrace.stub.php) landed earlier on this branch; this
brings the tracer C code into consistency with it. The v04 wire
format is intentionally kept byte-identical — libdatadog's v1 span
FFI is not yet available, so no wire/protocol switch happens here.
Changes
ddtrace_span_properties / ddtrace_root_span_data / ddtrace_span_stack in
span.h to match the new stub property order (offset parity is
ABI-critical — a mismatch is silent data corruption).
relocated the serialization into serializer.c → _dd.span_links / events
meta blobs are byte-identical.
translated back to meta (component / span.kind) at serialize time, so
the wire is unchanged; new SpanKind class registered.
finished the userland integration-analytics removal (Integration.php +
call sites); deleted orphaned tests and rewrote dd_trace_reset helper
tests without weakening coverage.
Deliberate scope decisions
until libdatadog v1 FFI is ready.
slots (to keep offsets correct) but are left unwired for now.
ZEND_ACC_DEPRECATED flags current gen_stub now emits) to match the
committed convention and avoid runtime E_DEPRECATED on hot paths;
reconciling gen_stub output is a separate follow-up.
Testing
Container build clean; 22 span-shape + 26 curl integration + 30
ConfigurationTest tests passing; links/events wire proven byte-identical.
Draft: pending full CI.
Relationship to the V1 Efficient Trace Payload protocol
This change aligns the userland span API and tracer C with the approved Efficient Trace Payload Protocol RFC and the WIP Tracer Implementation Guide for V1 Trace Payloads, without changing the wire format. The v04 payload remains byte-for-byte the sender's output because the vendored libdatadog exposes the v1 types (
libdd-trace-utils/src/span/v1/mod.rs,pb.idx.rs) only internally — the PHP FFI (components-rs/bytes.rs) still bindsddog_SpanBytes = v04::SpanBytes, so there is no v1 serializer to drive yet.Implemented now (v1-shaped API, v04 wire):
env,version,component,kindexist asSpanDataproperties (RFC idx.Span fields 13–16). Internal C producers set the property; the serializer translatescomponent/spanKindback intometa["component"]/meta["span.kind"]so v04 is unchanged.DDTrace\SpanKindconstants match the OTELSpanKindenum exactly (RFC field 16:kind = otel.SpanKind): UNSPECIFIED=0, INTERNAL=1, SERVER=2, CLIENT=3, PRODUCER=4, CONSUMER=5.Deferred until the v1 FFI lands (groundwork present, unwired):
DD_TRACE_AGENT_PROTOCOL_VERSION∈ {"1.0","1"} and the agent/infoadvertises/v1.0/traces, with mandatory fallback to v04 when absent. Intentionally not added yet to avoid a no-op config key with no serializer behind it.SpanData::$attributes/SpanStack::$attributesreserved; the initial implementation will use String/Float/Bytes and foldmeta/metrics/meta_structinto a single typed map (guide L14–16).traceIDbytes (RFC idx.TraceChunk field 6 / guide L33) andsamplingMechanismas a bare uint32 replacing_dd.p.dm:-N(RFC field 7 / guide L36) —RootSpanData::$samplingMechanismreserved.hostnamepromoted to the TracerPayload (RFC field 8) —RootSpanData::$hostnamereserved; v04 keeps emitting_dd.hostname.erroras bool (RFC idx.Span field 8) and 429 /Datadog-Send-Real-Http-Statusback-off (guide L21–24) — trace sender untouched.Note for the v1 serializer work: the promoted fields have a split source of truth (property for C producers,
metafor userland integrations such as OTelSpanBuilderand Kafka). The v1 serializer must read each promoted value from property-or-meta and remove it from the attributes map, otherwise a v1 payload would carry the value both in the promoted field and in attributes (guide L19).