Skip to content

Commit e40dd5d

Browse files
khanayan123claude
andcommitted
Implement stable session identifier headers for telemetry
Adds DD-Session-ID and DD-Root-Session-ID HTTP headers to all telemetry requests per the Stable Service Instance Identifier RFC. - DD-Session-ID is always set to the tracer's runtime_id - DD-Root-Session-ID is only set when it differs from the session ID (i.e. when running as a child process) - Root session ID is propagated to exec'd children via _DD_ROOT_CPP_SESSION_ID env var, read in finalize_config() - _DD_ROOT_CPP_SESSION_ID registered in the environment variable registry and supported-configurations.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 14280af commit e40dd5d

File tree

12 files changed

+137
-22
lines changed

12 files changed

+137
-22
lines changed

include/datadog/environment.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ namespace environment {
8181
MACRO(DD_APM_TRACING_ENABLED, BOOLEAN, true) \
8282
MACRO(DD_TRACE_RESOURCE_RENAMING_ENABLED, BOOLEAN, false) \
8383
MACRO(DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT, BOOLEAN, false) \
84-
MACRO(DD_EXTERNAL_ENV, STRING, "")
84+
MACRO(DD_EXTERNAL_ENV, STRING, "") \
85+
MACRO(_DD_ROOT_CPP_SESSION_ID, STRING, "")
8586

8687
#define ENV_DEFAULT_RESOLVED_IN_CODE(X) X
8788
#define WITH_COMMA(ARG, TYPE, DEFAULT_VALUE) ARG,
@@ -95,7 +96,7 @@ enum Variable { DD_LIST_ENVIRONMENT_VARIABLES(WITH_COMMA) };
9596
#define QUOTED_WITH_COMMA(ARG, TYPE, DEFAULT_VALUE) \
9697
WITH_COMMA(QUOTED(ARG), TYPE, DEFAULT_VALUE)
9798

98-
inline const char *const variable_names[] = {
99+
inline const char* const variable_names[] = {
99100
DD_LIST_ENVIRONMENT_VARIABLES(QUOTED_WITH_COMMA)};
100101

101102
#undef QUOTED
@@ -110,6 +111,10 @@ StringView name(Variable variable);
110111
// `nullopt` if that variable is not set in the environment.
111112
Optional<StringView> lookup(Variable variable);
112113

114+
// Set the specified environment `variable` to `value`. Does not overwrite if
115+
// already set (equivalent to setenv(..., 0) on POSIX).
116+
void set(Variable variable, StringView value);
117+
113118
std::string to_json();
114119

115120
} // namespace environment

include/datadog/tracer_config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ class FinalizedTracerConfig final {
225225
bool log_on_startup;
226226
bool generate_128bit_trace_ids;
227227
Optional<RuntimeID> runtime_id;
228+
Optional<std::string> root_session_id;
228229
Clock clock;
229230
std::string integration_name;
230231
std::string integration_version;

include/datadog/tracer_signature.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,18 @@ namespace tracing {
3333

3434
struct TracerSignature {
3535
RuntimeID runtime_id;
36+
std::string root_session_id;
3637
std::string default_service;
3738
std::string default_environment;
3839
std::string library_version;
3940
StringView library_language;
4041
StringView library_language_version;
4142

4243
TracerSignature() = delete;
43-
TracerSignature(RuntimeID id, std::string service, std::string environment)
44+
TracerSignature(RuntimeID id, std::string root_session, std::string service,
45+
std::string environment)
4446
: runtime_id(id),
47+
root_session_id(std::move(root_session)),
4548
default_service(std::move(service)),
4649
default_environment(std::move(environment)),
4750
library_version(tracer_version),

src/datadog/environment.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,28 @@ namespace environment {
1111
StringView name(Variable variable) { return variable_names[variable]; }
1212

1313
Optional<StringView> lookup(Variable variable) {
14-
const char *name = variable_names[variable];
15-
const char *value = std::getenv(name);
14+
const char* name = variable_names[variable];
15+
const char* value = std::getenv(name);
1616
if (!value) {
1717
return nullopt;
1818
}
1919
return StringView{value};
2020
}
2121

22+
void set(Variable variable, StringView value) {
23+
const char* name = variable_names[variable];
24+
#ifdef _WIN32
25+
_putenv_s(name, value.data());
26+
#else
27+
setenv(name, value.data(), /*overwrite=*/0);
28+
#endif
29+
}
30+
2231
std::string to_json() {
2332
auto result = nlohmann::json::object({});
2433

25-
for (const char *name : variable_names) {
26-
if (const char *value = std::getenv(name)) {
34+
for (const char* name : variable_names) {
35+
if (const char* value = std::getenv(name)) {
2736
result[name] = value;
2837
}
2938
}

src/datadog/telemetry/telemetry.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,13 @@ void init(FinalizedConfiguration configuration,
5353
std::shared_ptr<tracing::HTTPClient> client,
5454
std::shared_ptr<tracing::EventScheduler> event_scheduler,
5555
tracing::HTTPClient::URL agent_url, tracing::Clock clock) {
56-
instance(Ctor_param{configuration,
57-
tracing::TracerSignature(tracing::RuntimeID::generate(),
58-
tracing::get_process_name(), ""),
59-
logger, client, event_scheduler, agent_url, clock});
56+
auto runtime_id = tracing::RuntimeID::generate();
57+
auto root_session_id = runtime_id.string();
58+
instance(Ctor_param{
59+
configuration,
60+
tracing::TracerSignature(runtime_id, std::move(root_session_id),
61+
tracing::get_process_name(), ""),
62+
logger, client, event_scheduler, agent_url, clock});
6063
}
6164

6265
void init(FinalizedConfiguration configuration,

src/datadog/telemetry/telemetry_impl.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,13 +302,18 @@ void Telemetry::app_started() {
302302
auto payload = app_started_payload();
303303

304304
auto on_headers = [payload_size = payload.size(),
305-
debug_enabled = config_.debug](DictWriter& headers) {
305+
debug_enabled = config_.debug,
306+
&sig = tracer_signature_](DictWriter& headers) {
306307
headers.set("Content-Type", "application/json");
307308
headers.set("Content-Length", std::to_string(payload_size));
308309
headers.set("DD-Telemetry-API-Version", "v2");
309310
headers.set("DD-Client-Library-Language", "cpp");
310311
headers.set("DD-Client-Library-Version", tracer_version);
311312
headers.set("DD-Telemetry-Request-Type", "app-started");
313+
headers.set("DD-Session-ID", sig.runtime_id.string());
314+
if (sig.root_session_id != sig.runtime_id.string()) {
315+
headers.set("DD-Root-Session-ID", sig.root_session_id);
316+
}
312317
if (debug_enabled) {
313318
headers.set("DD-Telemetry-Debug-Enabled", "true");
314319
}
@@ -356,14 +361,18 @@ void Telemetry::app_closing() {
356361

357362
void Telemetry::send_payload(StringView request_type, std::string payload) {
358363
auto set_telemetry_headers = [request_type, payload_size = payload.size(),
359-
debug_enabled =
360-
config_.debug](DictWriter& headers) {
364+
debug_enabled = config_.debug,
365+
&sig = tracer_signature_](DictWriter& headers) {
361366
headers.set("Content-Type", "application/json");
362367
headers.set("Content-Length", std::to_string(payload_size));
363368
headers.set("DD-Telemetry-API-Version", "v2");
364369
headers.set("DD-Client-Library-Language", "cpp");
365370
headers.set("DD-Client-Library-Version", tracer_version);
366371
headers.set("DD-Telemetry-Request-Type", request_type);
372+
headers.set("DD-Session-ID", sig.runtime_id.string());
373+
if (sig.root_session_id != sig.runtime_id.string()) {
374+
headers.set("DD-Root-Session-ID", sig.root_session_id);
375+
}
367376
if (debug_enabled) {
368377
headers.set("DD-Telemetry-Debug-Enabled", "true");
369378
}

src/datadog/tracer.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ Tracer::Tracer(const FinalizedTracerConfig& config,
4848
: logger_(config.logger),
4949
runtime_id_(config.runtime_id ? *config.runtime_id
5050
: RuntimeID::generate()),
51-
signature_{runtime_id_, config.defaults.service,
52-
config.defaults.environment},
51+
signature_{runtime_id_,
52+
config.root_session_id.value_or(runtime_id_.string()),
53+
config.defaults.service, config.defaults.environment},
5354
config_manager_(std::make_shared<ConfigManager>(config)),
5455
collector_(/* see constructor body */),
5556
span_sampler_(
@@ -64,6 +65,9 @@ Tracer::Tracer(const FinalizedTracerConfig& config,
6465
baggage_extraction_enabled_(false),
6566
tracing_enabled_(config.tracing_enabled),
6667
resource_renaming_mode_(config.resource_renaming_mode) {
68+
environment::set(environment::_DD_ROOT_CPP_SESSION_ID,
69+
signature_.root_session_id);
70+
6771
telemetry::init(config.telemetry, signature_, logger_, config.http_client,
6872
config.event_scheduler, config.agent_url);
6973
if (config.report_hostname) {

src/datadog/tracer_config.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,10 @@ Expected<FinalizedTracerConfig> finalize_config(const TracerConfig &user_config,
407407
final_config.runtime_id = user_config.runtime_id;
408408
}
409409

410+
if (auto val = lookup(environment::_DD_ROOT_CPP_SESSION_ID)) {
411+
final_config.root_session_id = std::string{*val};
412+
}
413+
410414
final_config.process_tags = user_config.process_tags;
411415

412416
auto agent_finalized =

supported-configurations.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@
2828
"type": "STRING"
2929
}
3030
],
31+
"_DD_ROOT_CPP_SESSION_ID": [
32+
{
33+
"default": null,
34+
"implementation": "A",
35+
"type": "STRING"
36+
}
37+
],
3138
"DD_INSTRUMENTATION_INSTALL_ID": [
3239
{
3340
"default": "",

test/remote_config/test_remote_config.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ auto logger = std::make_shared<NullLogger>();
4747

4848
REMOTE_CONFIG_TEST("initial state payload") {
4949
// Verify the initial payload structure for a remote configuration instance.
50+
auto runtime_id = RuntimeID::generate();
5051
const TracerSignature tracer_signature{
51-
/* runtime_id = */ RuntimeID::generate(),
52+
/* runtime_id = */ runtime_id,
53+
/* root_session_id = */ runtime_id.string(),
5254
/* service = */ "testsvc",
5355
/* environment = */ "test"};
5456

@@ -92,8 +94,10 @@ REMOTE_CONFIG_TEST("initial state payload") {
9294
// TODO: test all combination of product and capabilities generation
9395

9496
REMOTE_CONFIG_TEST("response processing") {
97+
auto runtime_id = RuntimeID::generate();
9598
const TracerSignature tracer_signature{
96-
/* runtime_id = */ RuntimeID::generate(),
99+
/* runtime_id = */ runtime_id,
100+
/* root_session_id = */ runtime_id.string(),
97101
/* service = */ "testsvc",
98102
/* environment = */ "test"};
99103

0 commit comments

Comments
 (0)