Skip to content

feat(svc-src): emit _dd.svc_src per Service Override Source Attribution RFC#3948

Open
Leiyks wants to merge 18 commits into
masterfrom
leiyks/svc-override-source-attribution
Open

feat(svc-src): emit _dd.svc_src per Service Override Source Attribution RFC#3948
Leiyks wants to merge 18 commits into
masterfrom
leiyks/svc-override-source-attribution

Conversation

@Leiyks

@Leiyks Leiyks commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Implements Service Override Source Attribution for the PHP tracer.

Every span whose service was actively chosen (vs. the tracer's default) now carries a _dd.svc_src meta tag identifying who chose it. The tag is cleared on default-service spans (DD_SERVICE-set or auto-resolved) per the RFC.

Source values

Source Value Set by
Integration override <integration_name> Integration::handleInternalSpanServiceName (Curl, Guzzle, PDO, Mysqli, SQLSRV, MongoDB, Memcache(d), Predis, PHPRedis, Eloquent, AMQP, …)
Config split-by-X opt.http_client_split_by_domain Curl, Guzzle, Psr18, Ratchet
opt.db_client_split_by_instance PDO, Mysqli, SQLSRV
opt.redis_client_split_by_host PHPRedis
Framework root-span <integration_name> (only when DD_SERVICE not user-set) new Integration::tagFrameworkServiceSource helper — Laravel, LaravelQueue, Drupal, Laminas, Lumen, Slim, SymfonyMessenger, Roadrunner, Ratchet (web), CakePHP
Manual API m serializer.c fallback — span's service differs from root's and no other layer tagged svc_src
Default (DD_SERVICE / auto) not set per RFC

Child spans inherit _dd.svc_src from their parent at span-creation time (serializer.c).

Tests

  • 3 new .phpt tests covering the contract (svc_src_default_cleared, svc_src_inheritance, svc_src_manual_override)
  • Updated affected integration-test expectations across the matrix

@Leiyks Leiyks changed the title feat(process-tags): per-RFC Service Override Source Attribution feat(process-tags): Service Override Source Attribution Jun 3, 2026
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Jun 3, 2026

Copy link
Copy Markdown

Pipelines  Tests

Fix all issues with BitsAI

⚠️ Warnings

🚦 260 Pipeline jobs failed

DataDog/apm-reliability/dd-trace-php | ASAN test_c: [8.0, arm64]   View in Datadog   GitLab

🧪 4 Tests failed

tmp/build_extension/tests/ext/start_span_with_all_properties.phpt (Set DDTrace\start_span() properties) from PHP.tmp.build_extension.tests.ext   View in Datadog (Fix with Cursor)
--
         [&#34;type&#34;]=&gt;
         string(6) &#34;runner&#34;
         [&#34;meta&#34;]=&gt;
071&#43;     array(5) {
071-     array(4) {
           [&#34;_dd.p.dm&#34;]=&gt;
           string(2) &#34;-0&#34;
           [&#34;_dd.p.tid&#34;]=&gt;
076&#43;       [&#34;_dd.svc_src&#34;]=&gt;
...
tmp/build_extension/tests/ext/sandbox/dd_trace_function_alias.phpt (dd_trace_function() is aliased to DDTrace\trace_function()) from PHP.tmp.build_extension.tests.ext.sandbox   View in Datadog (Fix with Cursor)
--
     spans(\DDTrace\SpanData) (1) {
       bar (alias, bar, cli)
         _dd.p.dm =&gt; -0
006&#43;     _dd.svc_src =&gt; m
     }
View all 4 test failures

DataDog/apm-reliability/dd-trace-php | ASAN test_c: [8.5, arm64]   View in Datadog   GitLab

🧪 4 Tests failed

tmp/build_extension/tests/ext/start_span_with_all_properties.phpt (Set DDTrace\start_span() properties) from php.tmp.build_extension.tests.ext   View in Datadog (Fix with Cursor)
--
         [&#34;type&#34;]=&gt;
         string(6) &#34;runner&#34;
         [&#34;meta&#34;]=&gt;
071-     array(4) {
071&#43;     array(5) {
           [&#34;_dd.p.dm&#34;]=&gt;
           string(2) &#34;-0&#34;
           [&#34;_dd.p.tid&#34;]=&gt;
           string(16) &#34;6a2adc5200000000&#34;
...
tmp/build_extension/tests/ext/sandbox/dd_trace_function_alias.phpt (dd_trace_function() is aliased to DDTrace\trace_function()) from php.tmp.build_extension.tests.ext.sandbox   View in Datadog (Fix with Cursor)
--
       bar (alias, bar, cli)
         _dd.p.dm =&gt; -0
         _dd.p.tid =&gt; %s
006&#43;     _dd.svc_src =&gt; m
     }
View all 4 test failures

DataDog/apm-reliability/dd-trace-php | test_web_symfony_52: [8.0, cgi-fcgi]   View in Datadog   GitLab

🧪 1 Test failed

testScenario from symfony-52-test.DDTrace\Tests\Integrations\Symfony\V5_2\TraceSearchConfigTest   View in Datadog (Fix with Cursor)
DDTrace\Tests\Integrations\Symfony\V5_2\TraceSearchConfigTest::testScenario
symfony.request: Unexpected extra values for &#39;tags&#39;:
Array
(
    [_dd.svc_src] =&gt; m
)

Failed asserting that an array is empty.
Received Spans graph:
symfony.request (service: symfony, resource: simple, type: web)
...

View all 260 failed jobs.

🧪 8 Tests failed

    testPreloadDDTraceNotUsedManualTracing from composer-tests.DDTrace\Tests\Composer\ComposerInteroperabilityTest (Fix with Cursor)

    testPreloadDDTraceNotUsedWithComposerManualTracing from composer-tests.DDTrace\Tests\Composer\ComposerInteroperabilityTest (Fix with Cursor)

View all 8 test failures

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 54.12% (-0.04%)

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: a370649 | Docs | Datadog PR Page | Give us feedback!

Leiyks added 7 commits June 9, 2026 11:09
…svc_src)

Implements the RFC "Service Override Source Attribution": tags every span
whose service was actively chosen (vs. tracer's default) with a
`_dd.svc_src` meta value identifying the source. Cleared for the default
case (DD_SERVICE-set or auto-resolved).

Sources emitted, per RFC categories:
- `<integration_name>` — when the integration sets the service (Curl,
  Guzzle, PDO, Mysqli, SQLSRV, MongoDB, Memcached, AMQP, Kafka, ... via
  `Integration::handleInternalSpanServiceName`)
- `opt.<option>` — when a config-driven split changes the service:
  * `opt.http_client_split_by_domain` (Curl, Guzzle, Psr18, Ratchet)
  * `opt.db_client_split_by_instance` (PDO, Mysqli, SQLSRV)
  * `opt.redis_client_split_by_host` (PHPRedis)
- Framework root-span overrides (Laravel, LaravelQueue, Drupal, Laminas,
  Lumen, Slim, SymfonyMessenger, Roadrunner, Ratchet web mode, CakePHP)
  use the new `Integration::tagFrameworkServiceSource` helper: cleared
  when user-set DD_SERVICE drove the value, else tagged with the
  integration name.
- `m` — manual API override at serialization-time fallback in
  `ddtrace_serialize_span_to_rust_span` when the span's service differs
  from the root's and no other tag was set.

Inheritance per RFC: `ddtrace_inherit_span_properties` copies
`_dd.svc_src` from parent meta at span creation; no back-propagation.

Tests:
- 3 new `.phpt` covering default-cleared, manual `'m'`, and parent->child
  inheritance.
- Existing `.phpt` expectations updated where manual service overrides
  now correctly emit `_dd.svc_src = 'm'`.

Out of scope (follow-up):
- Predis SPLIT_BY_HOST: stores service via meta override
  (`service.name`) rather than `$span->service`. Different mechanism;
  worth a separate discussion.

Refs RFC "Service Override Source Attribution".
Mirrors the existing pattern for _dd.p.dm / _dd.p.ksr / _dd.p.tid /
runtime-id / _dd.code_origin.*: when not explicitly asserted, drop
_dd.svc_src from the strict "extra tags" check so per-integration
test suites don't need every test updated.

Fixes 14 Memcache (and similar) integration-test failures on CI.
…lock

For each `Tag::COMPONENT => '<name>'` entry across the PHPUnit
integration suite, inject `'_dd.svc_src' => '<same value>'` so the
RFC contract is verified explicitly per test (instead of being
filtered out at the SpanChecker level).

Mechanical, 576 sites across 94 test files. Catches drift between
the integration's NAME constant and what shows up on spans.

(Reverts the SpanChecker filter from 89d443e; this is the
proper-per-test enforcement the senior asked for.)
The previous mechanical pass (31f8140) inserted `_dd.svc_src` next to
every Tag::COMPONENT line, assuming svc_src always equals the component
value. That assumption holds for plain integrations but is wrong in four
cases that the runtime actually produces:

  * Split-by-X paths (Guzzle DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN,
    PHPRedis DD_TRACE_REDIS_CLIENT_SPLIT_BY_HOST): svc_src is the option
    name (opt.<flag>), not the component.
  * Integrations with DEFAULT_SERVICE_NAME != NAME (Predis): svc_src is
    the fallback service name (redis), not the integration NAME (predis).
  * Frameworks that don't call handleInternalSpanServiceName / call
    tagFrameworkServiceSource with DD_SERVICE set (Symfony, Nette,
    CodeIgniter, ZendFramework, plus DD_SERVICE-configured CakePHP/Slim
    scenarios): no svc_src is emitted at all.
  * Inherited spans (Laravel V4/V5_7 Eloquent): svc_src is inherited from
    the framework root (laravel), not the eloquent component.
  * Symfony console commands (CLI scenarios + ConsoleCommandTest):
    \$span->service is set manually by the integration, so the serializer
    default-tags svc_src=m.

Also extends SnapshotTestTrait::stopAndCompareSnapshotSession to always
add 'meta._dd.svc_src' to the ignore list, so snapshot tests don't drift
on this new internal field.
…losures

trace_method/install_hook rebind closure scope to the target class at
runtime, so `self::NAME` inside non-static closures resolves to the
hooked class (e.g. Illuminate\View\View) rather than the lexical
integration class. PHP 8.x throws "Undefined constant <hooked>::NAME"
and the entire integration hook fails.

This was breaking Laravel/Lumen/LaravelQueue scenarios across many test
targets (Lumen 100/52/81, Laravel 9x/10x/11x/Latest/Octane, etc).

Switches all self::NAME / Integration::tagFrameworkServiceSource calls
in these integrations to the explicit <Integration>::NAME form, matching
the pre-existing pattern in the same files (e.g.
LaravelIntegration::getServiceName() on the line above the fix).

Also drops two svc_src expected lines my earlier sed missed (Swoole
CommonScenariosTest, Zend V1_21 TraceSearchConfigTest with double
quotes).
RatchetIntegration calls handleInternalSpanServiceName/tagFrameworkServiceSource
which now tags _dd.svc_src='ratchet', and the websocket send/receive/close
spans inherit svc_src from their handshake span (see line 264-266 of
RatchetIntegration). My earlier mechanical pass missed this file because
its assertions use lowercase 'component' => 'ratchet' rather than
Tag::COMPONENT constant.
@Leiyks Leiyks force-pushed the leiyks/svc-override-source-attribution branch from 48bb658 to 2e14e97 Compare June 9, 2026 09:09
Critical: tagFrameworkServiceSource declared `: void`, which PHP 7.0
parses as a class reference in the current namespace. This raised
TypeError "Return value must be an instance of DDTrace\Integrations\void"
on every CakePHP V2_8 / V3_10 / Laravel 4/5_8 invocation, breaking all
their integration tests. Drops the return type to match the codebase's
PHP 7.0 baseline. Also drops the `string` parameter type for the same
reason (consistency).

Test expectation fixes:
- Curl: split-by-domain svc_src='opt.http_client_split_by_domain' (was
  'curl'), and drop svc_src in testNoFakeServices (DD_SERVICE set).
- PHPRedis V3/V4 ClusterTest WithClusterName + ClusterNameAndSeeds: add
  svc_src='opt.redis_client_split_by_host' to the inline + baseTags()
  overrides.
- Laravel V5_8/V8_x EloquentTest, V8_x InternalExceptionsTest /
  RouteCachingTest / TraceSearchConfigTest, V5_7 TraceSearchConfigTest,
  Lumen V5_2 TraceSearchConfigTest: add svc_src='laravel' or 'lumen'
  next to existing TAG::COMPONENT entries (uppercase TAG, missed by the
  earlier mechanical pass).
- CLI CakePHP V3_10 CommonScenariosTest (inherited by V4_5): drop the
  two 'cakephp.console' svc_src expectations (DD_SERVICE clears them).
- Laravel Octane Latest CommonScenariosTest: drop all 12 svc_src=laravel
  lines (DD_SERVICE='swoole_test_app' clears framework svc_src).
- Ratchet V0_4: drop svc_src='ratchet' from the line-83 websocket.send
  with service='phpunit' (outgoingMessage doesn't set svc_src and the
  span doesn't inherit from a ratchet root). Add svc_src='ratchet' to
  testRatchetConnectFail's Connector.__invoke expectation (double-quote
  style missed by the earlier sweep).
@pr-commenter

pr-commenter Bot commented Jun 9, 2026

Copy link
Copy Markdown

Benchmarks [ tracer ]

Benchmark execution time: 2026-06-10 11:50:42

Comparing candidate commit 3eb74bc in PR branch leiyks/svc-override-source-attribution with baseline commit 08d5785 in branch master.

Found 4 performance improvements and 2 performance regressions! Performance is the same for 188 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:ContextPropagationBench/benchExtractHeaders64Bit-opcache

  • 🟥 execution_time [+729.674ns; +810.326ns] or [+60.055%; +66.694%]

scenario:ContextPropagationBench/benchInject64Bit-opcache

  • 🟩 execution_time [-711.457ns; -634.543ns] or [-23.898%; -21.315%]

scenario:LogsInjectionBench/benchLogsInfoBaseline-opcache

  • 🟩 execution_time [-226.697ns; -179.303ns] or [-12.370%; -9.784%]

scenario:LogsInjectionBench/benchLogsNullBaseline-opcache

  • 🟥 execution_time [+1.011µs; +1.175µs] or [+4.975%; +5.781%]

scenario:LogsInjectionBench/benchLogsNullInjection-opcache

  • 🟩 execution_time [-1.178µs; -0.964µs] or [-5.494%; -4.500%]

scenario:SamplingRuleMatchingBench/benchRegexMatching1-opcache

  • 🟩 execution_time [-196.125ns; -89.675ns] or [-11.410%; -5.217%]

Leiyks added 7 commits June 9, 2026 14:28
- CakePHP V2_8/V3_10 (web): drop stray 'cakephp' svc_src lines my earlier
  sed missed (only touched V4_5 paths).
- Yii Latest (4 files): drop \"yii\" double-quoted svc_src lines; Yii
  integration doesn't call tagFrameworkServiceSource so spans have no
  svc_src.
- Laravel V8_x EloquentTest / InternalExceptionsTest / RouteCachingTest
  / TraceSearchConfigTest: change 'laravel' → 'Laravel' (V8 app config
  default APP_NAME is capitalized; getAppName() returns it as-is).
- Laravel V8_x QueueTest: add '_dd.svc_src' to withExistingTagsNames in
  spanEventJobProcessing/Processed helpers (SpanChecker.php filters
  existing-tags out of the strict-extra check; without this svc_src
  triggers an 'extra' failure).
- Mysqli: parameterize baseTags($svcSrc='mysqli') so testNoFakeServices
  can pass null (DD_SERVICE set, no svc_src on span); add '_dd.svc_src'
  to testConstructorConnectError's withExistingTagsNames.
Last iteration overcorrected — only EloquentTest goes through
Eloquent's getAppName() (which returns the V8 app config name
'Laravel'). Every other V8_x span emits from Laravel's own loader
via tagFrameworkServiceSource(\$span, LaravelIntegration::NAME), so
svc_src='laravel' (lowercase NAME constant).

- InternalExceptionsTest / RouteCachingTest / TraceSearchConfigTest:
  revert 'Laravel' → 'laravel'.
- InternalExceptionsTest testNotImplemented / testUnauthorized: add
  the missing svc_src on the laravel.request and laravel.view.render
  spans that triggered \"extra\" failures.
- ZendFramework V1 TraceSearchConfigTest: drop one stray svc_src line
  the earlier V1_21-focused sed missed.
Earlier sed loop only matched CommonScenariosTest / TraceSearchConfigTest;
these slipped through:

- Symfony V3_4 AutofinishedTracesSymfony34Test / TemplateEnginesTest:
  drop svc_src='symfony' (SymfonyIntegration doesn't tag svc_src).
- Frankenphp CommonScenariosTest: drop svc_src='frankenphp'
  (FrankenphpIntegration sets \$rootSpan->service directly without
  calling tagFrameworkServiceSource).
…-instance

Same pattern as the earlier Predis/Mysqli fix: parameterize baseTags() to
accept an optional svc_src override (defaulting to integration name) so
testNoFakeServices can pass null when DD_SERVICE is set + flat services
strip svc_src from spans.

Files: Memcache, Memcached, MongoDB Latest, PDO, PHPRedis V5 Cluster,
SQLSRV.

PDO split-by-instance: 4 tests (testPDOSplitByDomain,
testPDOServiceMappedSplitByDomain, testPDOStatementSplitByDomain,
testPDOStatementSplitByDomainAndServiceFlattening) — svc_src='pdo' →
'opt.db_client_split_by_instance' via the new baseTags param.

Guzzle V5 testAppendHostnameToServiceName /
testAppendHostnameToServiceNameInlineCredentials: svc_src='guzzle' →
'opt.http_client_split_by_domain' (matches the V6/Latest fix that was
already in).
- PHPRedis V5 PHPRedisTest: add inline '_dd.svc_src' => 'phpredis' on
  41 sites where the assertion uses
  \"Tag::COMPONENT => 'phpredis', Tag::DB_SYSTEM => 'redis', Tag::TARGET_HOST\"
  on a single line (the earlier mechanical pass only matched
  Tag::COMPONENT on its own line, so missed these).
- PHPRedis V5 ClusterTest testSplitByDomainWithClusterName /
  testSplitByDomainWithClusterNameAndSeeds: pass
  'opt.redis_client_split_by_host' as the new baseTags(\$svcSrc) param
  (runtime overrides svc_src when DD_TRACE_REDIS_CLIENT_SPLIT_BY_HOST is
  set). The PeerService variants do NOT set that env and keep the
  default 'phpredis'.
- Laravel V5_8 EloquentTest: svc_src 'laravel' → 'Laravel' (V5_8 app
  config uses APP_NAME=Laravel, same as V8_x).
- Laravel V5_8 QueueTest spanEventJobProcessing/Processed: add
  '_dd.svc_src' to withExistingTagsNames (SpanChecker filters
  existing-tags from the strict-extra check; same fix as V8_x).
- CLI CakePHP V2_8 CommonScenariosTest: drop two stray svc_src='cakephp'
  lines (DD_SERVICE='cake_console_test_app' is set, framework spans
  carry no svc_src).
…ices

- Laravel V5_7 EloquentTest: svc_src 'laravel' → 'Laravel'. Same APP_NAME
  capitalization as V5_8 / V8_x — Eloquent's getAppName() returns the
  configured app name, which is 'Laravel' in the test fixture app.
- PHPRedis V5 PHPRedisTest::testNoFakeServices: drop the stray
  svc_src='phpredis' on the Redis.save assertion. My earlier
  41-site mechanical replace caught this inline line too, but
  testNoFakeServices sets DD_SERVICE + flat services so the runtime
  emits no svc_src.

Skipped (not svc_src related):
- Elasticsearch V1 testConstructor: 'Missing or additional spans' from
  the integration emitting many sub-namespace __construct spans the
  test doesn't expect — same pre-existing issue seen in V7.
- Laravel V5_7 PipelineTracingTest tests: PHPUnit markTestSkipped
  (\"Pipeline are not properly traced\").
- PHPRedis V5 ClusterTest::testScriptingFunctions: markTestSkipped
  (\"This is flaky in CI\").
Root cause of the 'Missing or additional spans' failure in
test_integrations_elasticsearch{1,7}:

  withExactTags([Tag::COMPONENT => 'elasticsearch'])

is on a SINGLE line with the closing ']' immediately after the value,
so my earlier line-anchored regex (which required a trailing comma or
end-of-line) didn't add '_dd.svc_src'. At runtime the integration's
handleInternalSpanServiceName tags svc_src='elasticsearch' on the
Client.__construct span, so withExactTags fails on the FIRST run with
'unexpected extra _dd.svc_src'.

PHPUnit's RetryTrait then re-runs the test in the SAME PHP process. On
the first run, the Client.__construct posthook registered trace hooks
for every namespace ::__construct method (line 30 of
ElasticSearchIntegration's init posthook). Those hooks persist, so the
RETRY's call to ClientBuilder::build() now produces a span for every
namespace constructor — boom, 'Missing or additional spans' with 30+
NamespaceX.__construct spans the test never expected.

Adding '_dd.svc_src' to the expected tags lets run 1 pass, no retry,
no namespace-hook firing, test stays at the single expected span.

V7 (and Latest) extend V1 so this single fix covers them all.
@Leiyks Leiyks changed the title feat(process-tags): Service Override Source Attribution feat(svc-src): emit _dd.svc_src per Service Override Source Attribution RFC Jun 10, 2026
@Leiyks Leiyks marked this pull request as ready for review June 10, 2026 10:33
@Leiyks Leiyks requested review from a team as code owners June 10, 2026 10:33
@Leiyks Leiyks requested review from LobeTia and removed request for a team June 10, 2026 10:33

@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: 3eb74bc25d

ℹ️ 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 thread tracer/serializer.c Outdated
Comment thread src/DDTrace/Integrations/Laminas/LaminasIntegration.php Outdated
- serializer.c inherit hook: use Z_TRY_ADDREF_P + zend_hash_str_update
  directly instead of copying the parent zval.
- Add Integration::setComponentMetadata(\$span, \$component, \$service = null)
  helper consolidating service / _dd.svc_src / Tag::COMPONENT in one call.
  Refactored 19 adjacent 3-line patterns in Drupal, Laminas, Laravel,
  CakePHP V2/V3, Slim. tagFrameworkServiceSource kept for the remaining
  partial-pattern callers (root-span-only, etc.).
- Move the _dd.svc_src='m' fallback out of ddtrace_serialize_span_to_rust_span
  into the ddtrace_span_data_readonly write hook (tracer/functions.c).
  Fires only when service is being changed on a non-root span to a value
  differing from the root's service and meta has no _dd.svc_src yet.
  Writes the tag to the PHP meta zval (instead of just the serialized rust
  span), so ddtrace_feed_span_to_concentrator now sees the source too.
Comment thread tracer/functions.c Outdated
@Leiyks Leiyks force-pushed the leiyks/svc-override-source-attribution branch from 3b0159b to 8010587 Compare June 10, 2026 15:04
@bwoebi

bwoebi commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Actually, the failing tests raise a good point:
what about the default service names web.request and <entrypoint-name> respectively? We don't really have an integration name for those, but we need to assign something to _dd.svc_src for these, to distinguish from DD_SERVICE, maybe web and cli for these "integrations"?

Comment thread tracer/functions.c Outdated
Comment on lines +506 to +508
if (!is_top_level_root && span->root != NULL && Z_TYPE_P(value) == IS_STRING
&& Z_TYPE(span->root->property_service) == IS_STRING
&& !zend_string_equals(Z_STR_P(value), Z_STR(span->root->property_service))) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why this check? What is the root span service important here for?

Per bwoebi's follow-up — the write hook's exists check was wrong: a
manual \$span->service override would not be reflected on a span that
already had a pre-existing integration-set svc_src.

- Remove the !zend_hash_str_exists guard so the write hook always stamps
  _dd.svc_src='m' on a non-root manual service override.
- Drop ddtrace_config_app_name in setComponentMetadata; the DD_SERVICE
  check is the same. Both service and svc_src are now assigned only
  inside the !DD_SERVICE branch, so when the user configured DD_SERVICE
  we don't touch the span's service or svc_src.
- Reorder handleInternalSpanServiceName to assign \$span->service first
  and svc_src after, so the write hook's 'm' is immediately overwritten
  by the integration's intended source.
@Leiyks Leiyks force-pushed the leiyks/svc-override-source-attribution branch from 8010587 to a370649 Compare June 11, 2026 14:59
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.

2 participants