Skip to content

Commit 5a55f2d

Browse files
committed
feat(process-tags): signal service name source via svc.user/svc.auto
Emit one of two mutually-exclusive process tags so the Datadog backend can distinguish user-set vs tracer-resolved service names: - `svc.user:true` when DD_SERVICE is non-empty (env, INI, OTEL fallback, remote config) - `svc.auto:<default_service_name>` when DD_SERVICE is empty and the tracer auto-resolved the name Runtime mutations of `datadog.service` (via `ini_set` or remote config) trigger a recompute. The new `ddtrace_process_tags_reload_with_service` override threads the ZAI `new_str` through because the value is not yet committed to `get_DD_SERVICE()` at the time the `ini_change` callback fires. Implements: RFC "Signal Service Name Source via Process Tags" https://docs.google.com/document/d/1c47iSTWxIOHMHfZTF2nT9xfyQaIBP9KJvI9sRn5SvpM
1 parent 1f6f251 commit 5a55f2d

9 files changed

Lines changed: 135 additions & 2 deletions

ext/ddtrace.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,10 @@ bool ddtrace_alter_dd_service(zval *old_value, zval *new_value, zend_string *new
416416
dd_alter_prop(XtOffsetOf(ddtrace_span_properties, property_service), old_value, new_value, new_str);
417417
if (DDTRACE_G(request_initialized)) {
418418
ddtrace_sidecar_submit_root_span_data_direct(&DDTRACE_G(sidecar), NULL, new_str, get_DD_ENV(), get_DD_VERSION());
419+
if (ddtrace_process_tags_enabled()) {
420+
ddtrace_process_tags_reload_with_service(new_str);
421+
ddtrace_sidecar_update_process_tags();
422+
}
419423
}
420424
return true;
421425
}

ext/process_tags.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <string.h>
1212
#include "process_tags.h"
1313
#include "configuration.h"
14+
#include "serializer.h"
1415
#include "Zend/zend_smart_str.h"
1516
#include "components-rs/ddtrace.h"
1617
#include "SAPI.h"
@@ -24,6 +25,8 @@
2425
#define TAG_ENTRYPOINT_WORKDIR "entrypoint.workdir"
2526
#define TAG_ENTRYPOINT_TYPE "entrypoint.type"
2627
#define TAG_RUNTIME_SAPI "runtime.sapi"
28+
#define TAG_SVC_USER "svc.user"
29+
#define TAG_SVC_AUTO "svc.auto"
2730

2831
#define TYPE_SCRIPT "script"
2932
#define TYPE_EXECUTABLE "executable"
@@ -44,6 +47,7 @@ typedef struct {
4447
} process_tags_t;
4548

4649
static process_tags_t process_tags = {0};
50+
static zend_string *pending_service_override = NULL;
4751

4852
static void clear_process_tags(void) {
4953
for (size_t i = 0; i < process_tags.count; i++) {
@@ -168,6 +172,17 @@ static void collect_process_tags(void) {
168172

169173
add_process_tag(TAG_RUNTIME_SAPI, sapi_module.name);
170174

175+
zend_string *dd_service = pending_service_override ? pending_service_override : get_DD_SERVICE();
176+
if (dd_service && ZSTR_LEN(dd_service) > 0) {
177+
add_process_tag(TAG_SVC_USER, "true");
178+
} else {
179+
zend_string *default_svc = ddtrace_default_service_name();
180+
if (default_svc) {
181+
add_process_tag(TAG_SVC_AUTO, ZSTR_VAL(default_svc));
182+
zend_string_release(default_svc);
183+
}
184+
}
185+
171186
const char *script = NULL;
172187
if (SG(request_info).path_translated && *SG(request_info).path_translated) {
173188
script = SG(request_info).path_translated;
@@ -336,6 +351,13 @@ void ddtrace_process_tags_reload(void) {
336351
clear_process_tags();
337352
init_process_tags();
338353
}
354+
355+
void ddtrace_process_tags_reload_with_service(zend_string *service_override) {
356+
pending_service_override = service_override;
357+
clear_process_tags();
358+
init_process_tags();
359+
pending_service_override = NULL;
360+
}
339361
void ddtrace_process_tags_mshutdown(void) {
340362
clear_process_tags();
341363
}

ext/process_tags.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
void ddtrace_process_tags_first_rinit(void);
1212
// Reload process tags in current request
1313
void ddtrace_process_tags_reload(void);
14+
// Reload process tags using the supplied service-name override. Use when the
15+
// DD_SERVICE INI is being changed but the new value has not yet been committed
16+
// to the ZAI config runtime (e.g. inside an `ini_change` callback).
17+
// Pass NULL to fall back to get_DD_SERVICE().
18+
void ddtrace_process_tags_reload_with_service(zend_string *service_override);
1419

1520
// Called at MSHUTDOWN to free resources
1621
void ddtrace_process_tags_mshutdown(void);

tests/ext/process_tags.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,6 @@ if (isset($spans[1]['meta']['_dd.process_tags'])) {
4747
?>
4848
--EXPECTF--
4949
Process tags present in root span: YES
50-
Process tags: entrypoint.basedir:ext,entrypoint.name:process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli
50+
Process tags: entrypoint.basedir:ext,entrypoint.name:process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli,svc.auto:process_tags.php
5151
Keys sorted: YES
5252
Process tags present in child span: NO

tests/ext/svc_auto_tag_cli.phpt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
Process tags include svc.auto:<default> when DD_SERVICE is unset (CLI)
3+
--ENV--
4+
DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1
5+
DD_TRACE_GENERATE_ROOT_SPAN=0
6+
DD_TRACE_AUTO_FLUSH_ENABLED=0
7+
--FILE--
8+
<?php
9+
$span = \DDTrace\start_span();
10+
$span->name = 'op';
11+
\DDTrace\close_span();
12+
13+
$spans = dd_trace_serialize_closed_spans();
14+
$processTags = $spans[0]['meta']['_dd.tags.process'];
15+
16+
echo "has svc.user: " . (strpos($processTags, 'svc.user') !== false ? 'YES' : 'NO') . "\n";
17+
echo "has svc.auto: " . (strpos($processTags, 'svc.auto:') !== false ? 'YES' : 'NO') . "\n";
18+
echo "auto value matches script: " . (strpos($processTags, 'svc.auto:svc_auto_tag_cli.php') !== false ? 'YES' : 'NO') . "\n";
19+
?>
20+
--EXPECT--
21+
has svc.user: NO
22+
has svc.auto: YES
23+
auto value matches script: YES

tests/ext/svc_auto_tag_otel.phpt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
OTEL_SERVICE_NAME counts as user-defined (emits svc.user:true)
3+
--ENV--
4+
DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1
5+
OTEL_SERVICE_NAME=otel-app
6+
DD_TRACE_GENERATE_ROOT_SPAN=0
7+
DD_TRACE_AUTO_FLUSH_ENABLED=0
8+
--FILE--
9+
<?php
10+
$span = \DDTrace\start_span();
11+
$span->name = 'op';
12+
\DDTrace\close_span();
13+
14+
$spans = dd_trace_serialize_closed_spans();
15+
$processTags = $spans[0]['meta']['_dd.tags.process'];
16+
17+
echo "DD_SERVICE resolved to: " . ini_get('datadog.service') . "\n";
18+
echo "has svc.user:true: " . (strpos($processTags, 'svc.user:true') !== false ? 'YES' : 'NO') . "\n";
19+
echo "has svc.auto: : " . (strpos($processTags, 'svc.auto:') !== false ? 'YES' : 'NO') . "\n";
20+
?>
21+
--EXPECT--
22+
DD_SERVICE resolved to: otel-app
23+
has svc.user:true: YES
24+
has svc.auto: : NO

tests/ext/svc_runtime_change.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Changing datadog.service at runtime recomputes svc.user/svc.auto process tags
3+
--ENV--
4+
DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1
5+
DD_TRACE_GENERATE_ROOT_SPAN=0
6+
DD_TRACE_AUTO_FLUSH_ENABLED=0
7+
--FILE--
8+
<?php
9+
$span1 = \DDTrace\start_span();
10+
$span1->name = 'before';
11+
\DDTrace\close_span();
12+
13+
$spans = dd_trace_serialize_closed_spans();
14+
$tagsBefore = $spans[0]['meta']['_dd.tags.process'];
15+
echo "BEFORE has svc.auto: " . (strpos($tagsBefore, 'svc.auto:') !== false ? 'YES' : 'NO') . "\n";
16+
echo "BEFORE has svc.user: " . (strpos($tagsBefore, 'svc.user') !== false ? 'YES' : 'NO') . "\n";
17+
18+
ini_set('datadog.service', 'changed-svc');
19+
20+
$span2 = \DDTrace\start_span();
21+
$span2->name = 'after';
22+
\DDTrace\close_span();
23+
24+
$spans = dd_trace_serialize_closed_spans();
25+
$tagsAfter = $spans[0]['meta']['_dd.tags.process'];
26+
echo "AFTER has svc.user:true: " . (strpos($tagsAfter, 'svc.user:true') !== false ? 'YES' : 'NO') . "\n";
27+
echo "AFTER has svc.auto: : " . (strpos($tagsAfter, 'svc.auto:') !== false ? 'YES' : 'NO') . "\n";
28+
?>
29+
--EXPECT--
30+
BEFORE has svc.auto: YES
31+
BEFORE has svc.user: NO
32+
AFTER has svc.user:true: YES
33+
AFTER has svc.auto: : NO

tests/ext/svc_user_tag.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Process tags include svc.user:true when DD_SERVICE is set
3+
--ENV--
4+
DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1
5+
DD_SERVICE=my-app
6+
DD_TRACE_GENERATE_ROOT_SPAN=0
7+
DD_TRACE_AUTO_FLUSH_ENABLED=0
8+
--FILE--
9+
<?php
10+
$span = \DDTrace\start_span();
11+
$span->name = 'op';
12+
\DDTrace\close_span();
13+
14+
$spans = dd_trace_serialize_closed_spans();
15+
$processTags = $spans[0]['meta']['_dd.tags.process'];
16+
17+
echo "has svc.user:true: " . (strpos($processTags, 'svc.user:true') !== false ? 'YES' : 'NO') . "\n";
18+
echo "has svc.auto: : " . (strpos($processTags, 'svc.auto:') !== false ? 'YES' : 'NO') . "\n";
19+
?>
20+
--EXPECT--
21+
has svc.user:true: YES
22+
has svc.auto: : NO

tests/ext/telemetry/telemetry_process_tags.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ if ($i == 300) {
4646
?>
4747
--EXPECTF--
4848
Included
49-
string(%d) "entrypoint.basedir:telemetry,entrypoint.name:telemetry_process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli"
49+
string(%d) "entrypoint.basedir:telemetry,entrypoint.name:telemetry_process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli,svc.auto:telemetry_process_tags.php"
5050
--CLEAN--
5151
<?php
5252

0 commit comments

Comments
 (0)