feat(process-tags): signal service name source via svc.user/svc.auto#3921
feat(process-tags): signal service name source via svc.user/svc.auto#3921Leiyks wants to merge 1 commit into
Conversation
|
Benchmarks [ tracer ]Benchmark execution time: 2026-06-02 15:21:16 Comparing candidate commit 84b004e in PR branch Found 0 performance improvements and 6 performance regressions! Performance is the same for 188 metrics, 0 unstable metrics.
|
cfaa401 to
a210c1c
Compare
| } | ||
| if (has_user_service || svc_auto_normalized) { | ||
| smart_str combined = {0}; | ||
| smart_str_appendl(&combined, ZSTR_VAL(process_tags), ZSTR_LEN(process_tags)); |
There was a problem hiding this comment.
| smart_str_appendl(&combined, ZSTR_VAL(process_tags), ZSTR_LEN(process_tags)); | |
| smart_str_append(&combined, process_tags); |
simpler
| zend_string *dd_service = get_DD_SERVICE(); | ||
| if (dd_service && ZSTR_LEN(dd_service) > 0) { |
There was a problem hiding this comment.
DD_SERVICE is dynamic per request, not per session.
Some request may have it, another not.
You probably can store ddtrace_default_service_name() on the sidecar as session bound (at which point setting that one via ddog_sidecar_session_set_config is enough), but the DD_SERVICE may or may not exist for any particular request, and change between requests. You may have to submit that one alongside with ddog_sidecar_set_universal_service_tags().
... let's talk about that?!
7f653bf to
081af4a
Compare
Implements the PHP-tracer side of RFC "Signal Service Name Source via Process Tags". Surfaces one of two mutually-exclusive process tags so the backend can distinguish user-set vs tracer-auto-resolved service names: - svc.user:true — DD_SERVICE non-empty (env, INI, OTEL fallback, RC) - svc.auto:<name> — DD_SERVICE empty; tracer auto-resolved the default Per the RFC caveats, no conclusions are drawn from the absence of both. In ddtrace_serialize_span_to_rust_span's is_first_span block, the auto-resolved default name is read directly from the root span's property_service when its _dd.svc_src is absent (Service Override Source Attribution RFC: cleared svc_src ↔ service is the global default), avoiding a second pass through datadog_default_service_name(). Each span sees its own request's state — no FPM cross-request leak. datadog_sidecar_update_process_tags now also calls ddog_sidecar_session_set_default_service_name(transport, …): - Empty CharSlice → sidecar injects svc.user:true - Normalized default → sidecar injects svc.auto:<default> Injection happens at payload emission time in libdatadog (companion PR DataDog/libdatadog#2053), so telemetry / remote-config / runtime-info / stats payloads all see consistent svc.* tagging without baking it into the static process_tags string. - New CLI .phpt tests covering svc.user, svc.auto, OTEL fallback as user-defined, and ini_set-driven runtime mutation. - New web-SAPI test ProcessTagsWebTest::testSvcTagDoesNotLeakBetweenRequests proving the per-span design holds across FPM workers. - Existing process_tags.phpt / telemetry_process_tags.phpt updated to expect the appended svc.auto tag.
081af4a to
f9c7288
Compare
Summary
Implements the PHP-tracer side of RFC Signal Service Name Source via Process Tags.
Surfaces one of two mutually-exclusive process tags so the Datadog backend can distinguish user-set vs tracer-auto-resolved service names:
svc.user:true— whenDD_SERVICEis non-empty (env var, INI, OTEL fallback, remote config)svc.auto:<default_service_name>— whenDD_SERVICEis empty and the tracer auto-resolved the name (e.g.web.request, script basename,cli.command)Per the RFC caveats, no conclusions are drawn from the absence of both tags.
Architecture
Process tags are per-process; the active service name in PHP is per-request (mutable via
ini_set, OTEL fallbacks, remote-config-driven INI updates). The earlier approach of bakingsvc.user/svc.autointo the static process_tags string leaked the latest request's override into subsequent FPM requests served by the same worker — addressed by the senior review.Two cooperating paths now:
1. Per-span emission (traces) —
ext/serializer.cIn
ddtrace_serialize_span_to_rust_span, after attaching the static_dd.tags.processstring, the per-spansvc.user:true/svc.auto:<normalized-default>tag is appended based on the request-active state (get_DD_SERVICE()at serialization time, normalized viaddog_normalize_process_tag_value). Each span sees its own request's state — cross-request leak is impossible by construction.2. Sidecar (telemetry / remote config / runtime info) —
ext/sidecar.cddtrace_sidecar_update_process_tagsnow also calls the new libdatadog FFIddog_sidecar_session_set_default_service_name(transport, default_service_name):default_service_name→ sidecar treats it as user-defined and injectssvc.user:truedefault_service_name(pre-normalized) → sidecar injectssvc.auto:<default>The sidecar performs the injection at payload emission time (via the new
SessionInfo::process_tags_with_svc_source()helper), so all of telemetry / remote config / runtime_info / stats payloads see consistent svc.* tagging without the tracer having to bake it into the static string.The libdatadog half lives in DataDog/libdatadog#2053; the submodule pointer in this PR is bumped to that branch tip and must be moved to the merged SHA before this PR merges.
Behavior
_dd.tags.processDD_SERVICE=...env varsvc.user:truesvc.user:truedatadog.service=...system INIsvc.user:truesvc.user:trueOTEL_SERVICE_NAME=...(fallback)svc.user:truesvc.user:trueOTEL_RESOURCE_ATTRIBUTES=service.name=...(fallback)svc.user:truesvc.user:trueini_set('datadog.service', ...)(per-request)svc.user:true(this span only)svc.auto:<basename>.php(CLI) /svc.auto:web.request(web)Companion PR
DataDog/libdatadog#2053 — exposes
ddog_sidecar_session_set_default_service_nameand the sidecar-side injection logic. This PR's CI will be red on the submodule pointer until #2053 lands.