Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions components-rs/sidecar.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,14 @@ ddog_MaybeError ddog_sidecar_session_set_config(struct ddog_SidecarTransport **t
ddog_MaybeError ddog_sidecar_session_set_process_tags(struct ddog_SidecarTransport **transport,
const struct ddog_Vec_Tag *process_tags);

/**
* Records the default service name for the session. Empty = user-defined
* (sidecar emits `svc.user:true`); non-empty = auto-resolved with that name
* (sidecar emits `svc.auto:<name>`).
*/
ddog_MaybeError ddog_sidecar_session_set_default_service_name(struct ddog_SidecarTransport **transport,
ddog_CharSlice default_service_name);

/**
* Enqueues a telemetry log action to be processed internally.
* Non-blocking. Logs might be dropped if the internal queue is full.
Expand Down
35 changes: 34 additions & 1 deletion ext/serializer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1578,7 +1578,40 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo
if (is_first_span) {
zend_string *process_tags = ddtrace_process_tags_get_serialized();
if (ZSTR_LEN(process_tags)) {
ddog_add_str_span_meta_zstr(rust_span, "_dd.tags.process", process_tags);
// svc.* must be derived per span: process_tags are process-global but DD_SERVICE is request-local.
zend_string *dd_service = get_DD_SERVICE();
bool has_user_service = dd_service && ZSTR_LEN(dd_service) > 0;
zend_string *default_svc = NULL;
const char *svc_auto_normalized = NULL;
if (!has_user_service) {
default_svc = ddtrace_default_service_name();
if (default_svc) {
svc_auto_normalized = ddog_normalize_process_tag_value((ddog_CharSlice){
.ptr = ZSTR_VAL(default_svc), .len = ZSTR_LEN(default_svc)
});
}
}
if (has_user_service || svc_auto_normalized) {
smart_str combined = {0};
smart_str_appendl(&combined, ZSTR_VAL(process_tags), ZSTR_LEN(process_tags));

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.

Suggested change
smart_str_appendl(&combined, ZSTR_VAL(process_tags), ZSTR_LEN(process_tags));
smart_str_append(&combined, process_tags);

simpler

if (has_user_service) {
smart_str_appends(&combined, ",svc.user:true");
} else {
smart_str_appends(&combined, ",svc.auto:");
smart_str_appends(&combined, svc_auto_normalized);
}
smart_str_0(&combined);
ddog_add_str_span_meta_zstr(rust_span, "_dd.tags.process", combined.s);
smart_str_free(&combined);
} else {
ddog_add_str_span_meta_zstr(rust_span, "_dd.tags.process", process_tags);
}
if (svc_auto_normalized) {
ddog_free_normalized_tag_value(svc_auto_normalized);
}
if (default_svc) {
zend_string_release(default_svc);
}
}
}

Expand Down
24 changes: 24 additions & 0 deletions ext/sidecar.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "ddtrace_export.h"
#include "dogstatsd.h"
#include "logging.h"
#include "serializer.h"
#include <components-rs/common.h>
#include <components-rs/ddtrace.h>
#include <components-rs/sidecar.h>
Expand Down Expand Up @@ -149,6 +150,27 @@ void ddtrace_sidecar_update_process_tags(void) {
}

ddog_sidecar_session_set_process_tags(&DDTRACE_G(sidecar), process_tags);

zend_string *dd_service = get_DD_SERVICE();
if (dd_service && ZSTR_LEN(dd_service) > 0) {
Comment on lines +154 to +155

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.

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?!

ddtrace_ffi_try("Failed updating sidecar default service name",
ddog_sidecar_session_set_default_service_name(&DDTRACE_G(sidecar),
DDOG_CHARSLICE_C("")));
} else {
zend_string *default_svc = ddtrace_default_service_name();
if (default_svc) {
const char *normalized = ddog_normalize_process_tag_value((ddog_CharSlice){
.ptr = ZSTR_VAL(default_svc), .len = ZSTR_LEN(default_svc)
});
if (normalized) {
ddtrace_ffi_try("Failed updating sidecar default service name",
ddog_sidecar_session_set_default_service_name(&DDTRACE_G(sidecar),
(ddog_CharSlice){ .ptr = normalized, .len = strlen(normalized) }));
ddog_free_normalized_tag_value(normalized);
}
zend_string_release(default_svc);
}
}
}

static ddog_SidecarTransport *dd_sidecar_connection_factory_ex(bool is_fork);
Expand Down Expand Up @@ -498,6 +520,8 @@ void ddtrace_sidecar_handle_fork(void) {

if (DDTRACE_G(sidecar)) {
ddtrace_sidecar_for_signal = DDTRACE_G(sidecar);
// Fresh post-fork session has no svc.* source — re-push it.
ddtrace_sidecar_update_process_tags();
}
#endif
}
Expand Down
2 changes: 1 addition & 1 deletion libdatadog
Submodule libdatadog updated 37 files
+2 −0 .github/CODEOWNERS
+53 −4 .github/workflows/release-proposal-dispatch.yml
+4 −1 .github/workflows/release-proposal-test.yml
+93 −0 AGENTS.md
+1 −0 CLAUDE.md
+1 −1 Cargo.lock
+26 −44 bin_tests/tests/crashtracker_bin_test.rs
+24 −0 datadog-sidecar-ffi/src/lib.rs
+8 −0 datadog-sidecar/src/service/blocking.rs
+6 −0 datadog-sidecar/src/service/mod.rs
+1 −1 datadog-sidecar/src/service/runtime_info.rs
+19 −1 datadog-sidecar/src/service/sender.rs
+27 −1 datadog-sidecar/src/service/session_info.rs
+5 −0 datadog-sidecar/src/service/sidecar_interface.rs
+19 −3 datadog-sidecar/src/service/sidecar_server.rs
+1 −1 datadog-sidecar/src/service/telemetry.rs
+44 −36 docs/RFCs/0011-crashtracker-structured-log-format-V1_X.md
+618 −0 docs/RFCs/artifacts/crashtracker-unified-runtime-stack-schema-v1_8.json
+9 −7 libdd-crashtracker/src/collector_windows/api.rs
+17 −17 libdd-crashtracker/src/crash_info/builder.rs
+71 −29 libdd-crashtracker/src/crash_info/error_data.rs
+9 −8 libdd-crashtracker/src/crash_info/errors_intake.rs
+2 −2 libdd-crashtracker/src/crash_info/mod.rs
+1 −1 libdd-crashtracker/src/crash_info/telemetry.rs
+6 −9 libdd-crashtracker/src/receiver/receive_report.rs
+1 −0 libdd-data-pipeline-ffi/Cargo.toml
+7 −2 libdd-data-pipeline-ffi/cbindgen.toml
+1 −0 libdd-data-pipeline-ffi/src/lib.rs
+22 −46 libdd-data-pipeline-ffi/src/response.rs
+1 −1 libdd-data-pipeline-ffi/src/trace_exporter.rs
+690 −0 libdd-data-pipeline-ffi/src/tracer.rs
+18 −0 libdd-library-config/CHANGELOG.md
+1 −1 libdd-library-config/Cargo.toml
+1 −1 libdd-sampling/Cargo.toml
+1 −0 libdd-trace-utils/src/span/mod.rs
+468 −0 libdd-trace-utils/src/span/vec_map.rs
+1 −1 libdd-trace-utils/src/test_utils/datadog_test_agent.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace App;

class SetServiceController
{
public function render()
{
ini_set('datadog.service', 'request-svc');
header('Content-type: text/plain; charset=utf-8');
echo 'service set';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

return function(FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/simple', '\App\SimpleController');
$r->addRoute('GET', '/set_service', '\App\SetServiceController');
$r->addRoute('GET', '/simple_view', '\App\SimpleViewController');
$r->addRoute('GET', '/error', '\App\ErrorController');
$r->addRoute('GET', '/telemetry', '\App\TelemetryFlushController');
Expand Down
24 changes: 24 additions & 0 deletions tests/Integrations/Custom/Autoloaded/ProcessTagsWebTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,28 @@ public function testProcessTagsEnabledForWebSapi()
);
$this->assertEquals($tags['entrypoint.type'], 'script');
}

/**
* Proves the per-span svc.* design has no static-state leak between
* requests served by the same FPM worker: request 1 calls
* ini_set('datadog.service', ...) and must report svc.user:true; request 2
* reuses the same worker but does not override the service, and must
* report svc.auto:<default> (not the leaked svc.user from request 1).
*/
public function testSvcTagDoesNotLeakBetweenRequests()
{
$tracesUser = $this->tracesFromWebRequest(function () {
return $this->call(new RequestSpec(__FUNCTION__ . '_user', 'GET', '/set_service', []));
});
$userTags = $tracesUser[0][0]['meta']['_dd.tags.process'];
$this->assertStringContainsString('svc.user:true', $userTags);
$this->assertStringNotContainsString('svc.auto:', $userTags);

$tracesAuto = $this->tracesFromWebRequest(function () {
return $this->call(new RequestSpec(__FUNCTION__ . '_auto', 'GET', '/simple', []));
});
$autoTags = $tracesAuto[0][0]['meta']['_dd.tags.process'];
$this->assertStringNotContainsString('svc.user', $autoTags);
$this->assertStringContainsString('svc.auto:', $autoTags);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,5 @@ reset_request_replayer();
?>
--EXPECTF--
Process tags found in payload
string(%d) "entrypoint.basedir:live-debugger,entrypoint.name:debugger_log_probe_process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli"
string(%d) "entrypoint.basedir:live-debugger,entrypoint.name:debugger_log_probe_process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli,svc.auto:debugger_log_probe_process_tags.php"

2 changes: 1 addition & 1 deletion tests/ext/process_tags.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ if (isset($spans[1]['meta']['_dd.process_tags'])) {
?>
--EXPECTF--
Process tags present in root span: YES
Process tags: entrypoint.basedir:ext,entrypoint.name:process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli
Process tags: entrypoint.basedir:ext,entrypoint.name:process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli,svc.auto:process_tags.php
Keys sorted: YES
Process tags present in child span: NO
1 change: 1 addition & 0 deletions tests/ext/remote_config/rc_process_tags.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ entrypoint.name:rc_process_tags
entrypoint.type:script
entrypoint.workdir:%s
runtime.sapi:cli
svc.auto:rc_process_tags.php
23 changes: 23 additions & 0 deletions tests/ext/svc_auto_tag_cli.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
Process tags include svc.auto:<default> when DD_SERVICE is unset (CLI)
--ENV--
DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1
DD_TRACE_GENERATE_ROOT_SPAN=0
DD_TRACE_AUTO_FLUSH_ENABLED=0
--FILE--
<?php
$span = \DDTrace\start_span();
$span->name = 'op';
\DDTrace\close_span();

$spans = dd_trace_serialize_closed_spans();
$processTags = $spans[0]['meta']['_dd.tags.process'];

echo "has svc.user: " . (strpos($processTags, 'svc.user') !== false ? 'YES' : 'NO') . "\n";
echo "has svc.auto: " . (strpos($processTags, 'svc.auto:') !== false ? 'YES' : 'NO') . "\n";
echo "auto value matches script: " . (strpos($processTags, 'svc.auto:svc_auto_tag_cli.php') !== false ? 'YES' : 'NO') . "\n";
?>
--EXPECT--
has svc.user: NO
has svc.auto: YES
auto value matches script: YES
24 changes: 24 additions & 0 deletions tests/ext/svc_auto_tag_otel.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
OTEL_SERVICE_NAME counts as user-defined (emits svc.user:true)
--ENV--
DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1
OTEL_SERVICE_NAME=otel-app
DD_TRACE_GENERATE_ROOT_SPAN=0
DD_TRACE_AUTO_FLUSH_ENABLED=0
--FILE--
<?php
$span = \DDTrace\start_span();
$span->name = 'op';
\DDTrace\close_span();

$spans = dd_trace_serialize_closed_spans();
$processTags = $spans[0]['meta']['_dd.tags.process'];

echo "DD_SERVICE resolved to: " . ini_get('datadog.service') . "\n";
echo "has svc.user:true: " . (strpos($processTags, 'svc.user:true') !== false ? 'YES' : 'NO') . "\n";
echo "has svc.auto: : " . (strpos($processTags, 'svc.auto:') !== false ? 'YES' : 'NO') . "\n";
?>
--EXPECT--
DD_SERVICE resolved to: otel-app
has svc.user:true: YES
has svc.auto: : NO
37 changes: 37 additions & 0 deletions tests/ext/svc_runtime_change.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
Changing datadog.service at runtime recomputes svc.user/svc.auto process tags per-span
--ENV--
DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1
DD_TRACE_GENERATE_ROOT_SPAN=0
DD_TRACE_AUTO_FLUSH_ENABLED=0
--FILE--
<?php
function assert_tags($label) {
$spans = dd_trace_serialize_closed_spans();
$tags = $spans[0]['meta']['_dd.tags.process'];
$hasUser = strpos($tags, 'svc.user:true') !== false;
$hasAuto = strpos($tags, 'svc.auto:') !== false;
echo "$label svc.user=" . ($hasUser ? 'YES' : 'NO') . " svc.auto=" . ($hasAuto ? 'YES' : 'NO') . "\n";
}

$span1 = \DDTrace\start_span();
$span1->name = 'before';
\DDTrace\close_span();
assert_tags('BEFORE ');

ini_set('datadog.service', 'changed-svc');
$span2 = \DDTrace\start_span();
$span2->name = 'after_set';
\DDTrace\close_span();
assert_tags('AFTER ');

ini_restore('datadog.service');
$span3 = \DDTrace\start_span();
$span3->name = 'after_restore';
\DDTrace\close_span();
assert_tags('REVERTED');
?>
--EXPECT--
BEFORE svc.user=NO svc.auto=YES
AFTER svc.user=YES svc.auto=NO
REVERTED svc.user=NO svc.auto=YES
22 changes: 22 additions & 0 deletions tests/ext/svc_user_tag.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Process tags include svc.user:true when DD_SERVICE is set
--ENV--
DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1
DD_SERVICE=my-app
DD_TRACE_GENERATE_ROOT_SPAN=0
DD_TRACE_AUTO_FLUSH_ENABLED=0
--FILE--
<?php
$span = \DDTrace\start_span();
$span->name = 'op';
\DDTrace\close_span();

$spans = dd_trace_serialize_closed_spans();
$processTags = $spans[0]['meta']['_dd.tags.process'];

echo "has svc.user:true: " . (strpos($processTags, 'svc.user:true') !== false ? 'YES' : 'NO') . "\n";
echo "has svc.auto: : " . (strpos($processTags, 'svc.auto:') !== false ? 'YES' : 'NO') . "\n";
?>
--EXPECT--
has svc.user:true: YES
has svc.auto: : NO
2 changes: 1 addition & 1 deletion tests/ext/telemetry/telemetry_process_tags.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ if ($i == 300) {
?>
--EXPECTF--
Included
string(%d) "entrypoint.basedir:telemetry,entrypoint.name:telemetry_process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli"
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"
--CLEAN--
<?php

Expand Down
Loading