Skip to content

Commit 7803a9e

Browse files
khanayan123claude
andcommitted
Implement stable session identifier headers for telemetry
Add DD-Session-ID and DD-Root-Session-ID headers to all telemetry requests per the Stable Service Instance Identifier RFC. - DD-Session-ID (= runtime_id) sent on every telemetry request - DD-Root-Session-ID sent only when root != current runtime_id - Root session ID inherited from _DD_ROOT_CPP_SESSION_ID env var (for exec-based child processes) or defaults to first runtime_id - setenv propagates root session ID to exec'd children automatically - Fork propagation is automatic (memory survives fork) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 14280af commit 7803a9e

File tree

7 files changed

+116
-15
lines changed

7 files changed

+116
-15
lines changed

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,
45+
std::string service, 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/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: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <algorithm>
1515
#include <cassert>
16+
#include <cstdlib>
1617
#include <filesystem>
1718

1819
#include "config_manager.h"
@@ -36,6 +37,17 @@ namespace fs = std::filesystem;
3637
namespace datadog {
3738
namespace tracing {
3839

40+
namespace {
41+
42+
std::string get_root_session_id(const std::string& runtime_id) {
43+
if (const char* env = std::getenv("_DD_ROOT_CPP_SESSION_ID")) {
44+
return std::string(env);
45+
}
46+
return runtime_id;
47+
}
48+
49+
} // namespace
50+
3951
void to_json(nlohmann::json& j, const PropagationStyle& style) {
4052
j = to_string_view(style);
4153
}
@@ -48,7 +60,9 @@ Tracer::Tracer(const FinalizedTracerConfig& config,
4860
: logger_(config.logger),
4961
runtime_id_(config.runtime_id ? *config.runtime_id
5062
: RuntimeID::generate()),
51-
signature_{runtime_id_, config.defaults.service,
63+
signature_{runtime_id_,
64+
get_root_session_id(runtime_id_.string()),
65+
config.defaults.service,
5266
config.defaults.environment},
5367
config_manager_(std::make_shared<ConfigManager>(config)),
5468
collector_(/* see constructor body */),
@@ -64,6 +78,8 @@ Tracer::Tracer(const FinalizedTracerConfig& config,
6478
baggage_extraction_enabled_(false),
6579
tracing_enabled_(config.tracing_enabled),
6680
resource_renaming_mode_(config.resource_renaming_mode) {
81+
setenv("_DD_ROOT_CPP_SESSION_ID", signature_.root_session_id.c_str(), 1);
82+
6783
telemetry::init(config.telemetry, signature_, logger_, config.http_client,
6884
config.event_scheduler, config.agent_url);
6985
if (config.report_hostname) {

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

test/telemetry/test_telemetry.cpp

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,10 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") {
8989
auto client = std::make_shared<MockHTTPClient>();
9090
auto scheduler = std::make_shared<FakeEventScheduler>();
9191

92+
auto runtime_id = RuntimeID::generate();
9293
const TracerSignature tracer_signature{
93-
/* runtime_id = */ RuntimeID::generate(),
94+
/* runtime_id = */ runtime_id,
95+
/* root_session_id = */ runtime_id.string(),
9496
/* service = */ "testsvc",
9597
/* environment = */ "test"};
9698

@@ -353,6 +355,65 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") {
353355
}
354356
}
355357

358+
TELEMETRY_IMPLEMENTATION_TEST("session ID headers") {
359+
auto logger = std::make_shared<MockLogger>();
360+
auto client = std::make_shared<MockHTTPClient>();
361+
auto scheduler = std::make_shared<FakeEventScheduler>();
362+
auto url = HTTPClient::URL::parse("http://localhost:8000");
363+
364+
SECTION("root process: DD-Session-ID present, DD-Root-Session-ID absent") {
365+
auto rid = RuntimeID::generate();
366+
const TracerSignature sig{rid, rid.string(), "testsvc", "test"};
367+
368+
Telemetry telemetry{*finalize_config(), sig, logger, client, scheduler,
369+
*url};
370+
371+
auto it = client->request_headers.items.find("DD-Session-ID");
372+
REQUIRE(it != client->request_headers.items.end());
373+
CHECK(it->second == rid.string());
374+
375+
CHECK(client->request_headers.items.find("DD-Root-Session-ID") ==
376+
client->request_headers.items.end());
377+
}
378+
379+
SECTION("child process: DD-Root-Session-ID present when different") {
380+
auto rid = RuntimeID::generate();
381+
auto root_rid = RuntimeID::generate();
382+
const TracerSignature sig{rid, root_rid.string(), "testsvc", "test"};
383+
384+
Telemetry telemetry{*finalize_config(), sig, logger, client, scheduler,
385+
*url};
386+
387+
auto session_it = client->request_headers.items.find("DD-Session-ID");
388+
REQUIRE(session_it != client->request_headers.items.end());
389+
CHECK(session_it->second == rid.string());
390+
391+
auto root_it = client->request_headers.items.find("DD-Root-Session-ID");
392+
REQUIRE(root_it != client->request_headers.items.end());
393+
CHECK(root_it->second == root_rid.string());
394+
}
395+
396+
SECTION("heartbeat includes session headers") {
397+
auto rid = RuntimeID::generate();
398+
auto root_rid = RuntimeID::generate();
399+
const TracerSignature sig{rid, root_rid.string(), "testsvc", "test"};
400+
401+
Telemetry telemetry{*finalize_config(), sig, logger, client, scheduler,
402+
*url};
403+
404+
client->request_headers.items.clear();
405+
scheduler->trigger_heartbeat();
406+
407+
auto session_it = client->request_headers.items.find("DD-Session-ID");
408+
REQUIRE(session_it != client->request_headers.items.end());
409+
CHECK(session_it->second == rid.string());
410+
411+
auto root_it = client->request_headers.items.find("DD-Root-Session-ID");
412+
REQUIRE(root_it != client->request_headers.items.end());
413+
CHECK(root_it->second == root_rid.string());
414+
}
415+
}
416+
356417
TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") {
357418
const Clock clock = [] {
358419
TimePoint result;
@@ -364,8 +425,10 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") {
364425
auto client = std::make_shared<MockHTTPClient>();
365426
auto scheduler = std::make_shared<FakeEventScheduler>();
366427

428+
auto runtime_id = RuntimeID::generate();
367429
const TracerSignature tracer_signature{
368-
/* runtime_id = */ RuntimeID::generate(),
430+
/* runtime_id = */ runtime_id,
431+
/* root_session_id = */ runtime_id.string(),
369432
/* service = */ "testsvc",
370433
/* environment = */ "test"};
371434

@@ -869,8 +932,10 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry configuration") {
869932
auto client = std::make_shared<MockHTTPClient>();
870933
auto scheduler = std::make_shared<FakeEventScheduler>();
871934

935+
auto runtime_id = RuntimeID::generate();
872936
const TracerSignature tracer_signature{
873-
/* runtime_id = */ RuntimeID::generate(),
937+
/* runtime_id = */ runtime_id,
938+
/* root_session_id = */ runtime_id.string(),
874939
/* service = */ "testsvc",
875940
/* environment = */ "test"};
876941

test/test_datadog_agent.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ DATADOG_AGENT_TEST("Remote Configuration") {
199199
auto finalized = finalize_config(config);
200200
REQUIRE(finalized);
201201

202-
const TracerSignature signature(RuntimeID::generate(), "testsvc", "test");
202+
auto rid = RuntimeID::generate();
203+
const TracerSignature signature(rid, rid.string(), "testsvc", "test");
203204

204205
// TODO: set telemetry mock
205206
auto config_manager = std::make_shared<ConfigManager>(*finalized);

0 commit comments

Comments
 (0)