From fe2f6c72fd610eda69852c98721fdb7651300406 Mon Sep 17 00:00:00 2001 From: Ayan Khan Date: Mon, 23 Mar 2026 14:41:08 -0400 Subject: [PATCH 1/2] feat(telemetry): add stable session identifier headers Add DD-Session-ID and DD-Root-Session-ID HTTP headers to all telemetry requests per the Stable Service Instance Identifier RFC. - Add SESSION_ID and ROOT_SESSION_ID header constants to http_client - Add root_session_id field to TelemetryWorkerBuilder (None = use runtime_id) - Store root_session_id on TelemetryWorker, defaulting to runtime_id when unset - Emit DD-Session-ID on every request (set to runtime_id) - Emit DD-Root-Session-ID only in child processes (when != runtime_id) Co-Authored-By: Claude Sonnet 4.6 --- libdd-telemetry/src/worker/http_client.rs | 7 ++++++ libdd-telemetry/src/worker/mod.rs | 28 +++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/libdd-telemetry/src/worker/http_client.rs b/libdd-telemetry/src/worker/http_client.rs index 5f00744b12..8d756c87be 100644 --- a/libdd-telemetry/src/worker/http_client.rs +++ b/libdd-telemetry/src/worker/http_client.rs @@ -24,6 +24,13 @@ pub mod header { /// Header key for whether to enable debug mode of telemetry. pub const DEBUG_ENABLED: HeaderName = HeaderName::from_static("dd-telemetry-debug-enabled"); + + /// Header identifying the current runtime session (equals runtime_id). + pub const SESSION_ID: HeaderName = HeaderName::from_static("dd-session-id"); + + /// Header identifying the root session (first runtime_id in the process tree). + /// Only sent when the current session is not the root (i.e. in child processes). + pub const ROOT_SESSION_ID: HeaderName = HeaderName::from_static("dd-root-session-id"); } pub type ResponseFuture = diff --git a/libdd-telemetry/src/worker/mod.rs b/libdd-telemetry/src/worker/mod.rs index 3bfa1bcccb..526d513177 100644 --- a/libdd-telemetry/src/worker/mod.rs +++ b/libdd-telemetry/src/worker/mod.rs @@ -136,6 +136,7 @@ pub struct TelemetryWorker { cancellation_token: CancellationToken, seq_id: AtomicU64, runtime_id: String, + root_session_id: String, client: Box, metrics_flush_interval: Duration, deadlines: scheduler::Scheduler, @@ -745,7 +746,7 @@ impl TelemetryWorker { telemetry_worker_log!(self, DEBUG, "Prepared payload: {:?}", tel); - let req = http_client::request_builder(&self.config)? + let mut req = http_client::request_builder(&self.config)? .method(http::Method::POST) .header(header::CONTENT_TYPE, serialize::CONTENT_TYPE_VALUE) .header( @@ -764,7 +765,18 @@ impl TelemetryWorker { .header( http_client::header::LIBRARY_VERSION, tel.application.tracer_version.clone(), + ) + .header( + http_client::header::SESSION_ID, + self.runtime_id.clone(), + ); + + if self.runtime_id != self.root_session_id { + req = req.header( + http_client::header::ROOT_SESSION_ID, + self.root_session_id.clone(), ); + } let body = http_common::Body::from(serialize::serialize(&tel)?); Ok(req.body(body)?) @@ -1033,6 +1045,7 @@ pub struct TelemetryWorkerBuilder { pub host: Host, pub application: Application, pub runtime_id: Option, + pub root_session_id: Option, pub dependencies: store::Store, pub integrations: store::Store, pub configurations: store::Store, @@ -1084,6 +1097,7 @@ impl TelemetryWorkerBuilder { ..Default::default() }, runtime_id: None, + root_session_id: None, dependencies: store::Store::new(MAX_ITEMS), integrations: store::Store::new(MAX_ITEMS), configurations: store::Store::new(MAX_ITEMS), @@ -1113,6 +1127,13 @@ impl TelemetryWorkerBuilder { let metrics_flush_interval = telemetry_heartbeat_interval.min(MetricBuckets::METRICS_FLUSH_INTERVAL); + let runtime_id = self + .runtime_id + .unwrap_or_else(|| uuid::Uuid::new_v4().to_string()); + let root_session_id = self + .root_session_id + .unwrap_or_else(|| runtime_id.clone()); + #[allow(clippy::unwrap_used)] let worker = TelemetryWorker { flavor: self.flavor, @@ -1131,9 +1152,8 @@ impl TelemetryWorkerBuilder { config, mailbox, seq_id: AtomicU64::new(1), - runtime_id: self - .runtime_id - .unwrap_or_else(|| uuid::Uuid::new_v4().to_string()), + runtime_id, + root_session_id, client, metrics_flush_interval, deadlines: scheduler::Scheduler::new(vec![ From f1dcf15c55fd705395776f69904e8b9fb21dc0a4 Mon Sep 17 00:00:00 2001 From: Ayan Khan Date: Mon, 23 Mar 2026 14:59:52 -0400 Subject: [PATCH 2/2] chore(telemetry): fix rustfmt formatting Co-Authored-By: Claude Sonnet 4.6 --- libdd-telemetry/src/worker/mod.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libdd-telemetry/src/worker/mod.rs b/libdd-telemetry/src/worker/mod.rs index 526d513177..297396fb2f 100644 --- a/libdd-telemetry/src/worker/mod.rs +++ b/libdd-telemetry/src/worker/mod.rs @@ -766,10 +766,7 @@ impl TelemetryWorker { http_client::header::LIBRARY_VERSION, tel.application.tracer_version.clone(), ) - .header( - http_client::header::SESSION_ID, - self.runtime_id.clone(), - ); + .header(http_client::header::SESSION_ID, self.runtime_id.clone()); if self.runtime_id != self.root_session_id { req = req.header( @@ -1130,9 +1127,7 @@ impl TelemetryWorkerBuilder { let runtime_id = self .runtime_id .unwrap_or_else(|| uuid::Uuid::new_v4().to_string()); - let root_session_id = self - .root_session_id - .unwrap_or_else(|| runtime_id.clone()); + let root_session_id = self.root_session_id.unwrap_or_else(|| runtime_id.clone()); #[allow(clippy::unwrap_used)] let worker = TelemetryWorker {