Skip to content

Commit d01347e

Browse files
committed
add session id support to trace export
1 parent 9ec69fa commit d01347e

File tree

5 files changed

+131
-48
lines changed

5 files changed

+131
-48
lines changed

examples/ffi/trace_exporter.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ int main(int argc, char** argv)
9999
ddog_TelemetryClientConfig telemetry_config = {
100100
.interval = 60000,
101101
.runtime_id = DDOG_CHARSLICE_C("12345678-1234-1234-1234-123456789abc"),
102-
.debug_enabled = true
102+
.debug_enabled = true,
103+
.session_id = DDOG_CHARSLICE_C("12345678-1234-1234-1234-123456789abc"),
104+
.root_session_id = DDOG_CHARSLICE_C("87654321-1234-1234-1234-123456789abc"),
105+
.parent_session_id = DDOG_CHARSLICE_C(""),
103106
};
104107

105108
ret = ddog_trace_exporter_config_enable_telemetry(config, &telemetry_config);

libdd-data-pipeline-ffi/src/trace_exporter.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use libdd_common_ffi::{
1010
};
1111

1212
use libdd_data_pipeline::trace_exporter::{
13-
TelemetryConfig, TraceExporter, TraceExporterInputFormat, TraceExporterOutputFormat,
13+
TelemetryConfig, TelemetryInstrumentationSessions, TraceExporter, TraceExporterInputFormat,
14+
TraceExporterOutputFormat,
1415
};
1516
use std::{ptr::NonNull, time::Duration};
1617
use tracing::{debug, error};
@@ -43,6 +44,13 @@ pub struct TelemetryClientConfig<'a> {
4344
/// When enabled, sets the DD-Telemetry-Debug-Enabled header to true.
4445
/// Defaults to false.
4546
pub debug_enabled: bool,
47+
48+
/// HTTP header `dd-session-id` (empty = omitted).
49+
pub session_id: CharSlice<'a>,
50+
/// HTTP header `dd-root-session-id` (empty = omitted).
51+
pub root_session_id: CharSlice<'a>,
52+
/// HTTP header `dd-parent-session-id` (empty = omitted).
53+
pub parent_session_id: CharSlice<'a>,
4654
}
4755

4856
/// The TraceExporterConfig object will hold the configuration properties for the TraceExporter.
@@ -64,6 +72,7 @@ pub struct TraceExporterConfig {
6472
compute_stats: bool,
6573
client_computed_stats: bool,
6674
telemetry_cfg: Option<TelemetryConfig>,
75+
telemetry_instrumentation_sessions: TelemetryInstrumentationSessions,
6776
health_metrics_enabled: bool,
6877
process_tags: Option<String>,
6978
test_session_token: Option<String>,
@@ -302,8 +311,23 @@ pub unsafe extern "C" fn ddog_trace_exporter_config_enable_telemetry(
302311
},
303312
debug_enabled: telemetry_cfg.debug_enabled,
304313
};
305-
debug!(telemetry_cfg = ?cfg, "Configuring telemetry");
314+
let sessions = TelemetryInstrumentationSessions {
315+
session_id: match sanitize_string(telemetry_cfg.session_id) {
316+
Ok(s) => Some(s),
317+
Err(e) => return Some(e),
318+
},
319+
root_session_id: match sanitize_string(telemetry_cfg.root_session_id) {
320+
Ok(s) => Some(s),
321+
Err(e) => return Some(e),
322+
},
323+
parent_session_id: match sanitize_string(telemetry_cfg.parent_session_id) {
324+
Ok(s) => Some(s),
325+
Err(e) => return Some(e),
326+
},
327+
};
328+
debug!(telemetry_cfg = ?cfg, telemetry_sessions = ?sessions, "Configuring telemetry");
306329
config.telemetry_cfg = Some(cfg);
330+
config.telemetry_instrumentation_sessions = sessions;
307331
}
308332
None
309333
} else {
@@ -488,6 +512,9 @@ pub unsafe extern "C" fn ddog_trace_exporter_new(
488512
if let Some(cfg) = &config.telemetry_cfg {
489513
builder.enable_telemetry(cfg.clone());
490514
}
515+
builder.set_telemetry_instrumentation_sessions(
516+
config.telemetry_instrumentation_sessions.clone(),
517+
);
491518

492519
if let Some(token) = &config.test_session_token {
493520
builder.set_test_session_token(token);
@@ -831,6 +858,9 @@ mod tests {
831858
interval: 1000,
832859
runtime_id: CharSlice::from("id"),
833860
debug_enabled: false,
861+
session_id: CharSlice::empty(),
862+
root_session_id: CharSlice::empty(),
863+
parent_session_id: CharSlice::empty(),
834864
}),
835865
);
836866
assert_eq!(error.as_ref().unwrap().code, ErrorCode::InvalidArgument);
@@ -848,6 +878,9 @@ mod tests {
848878
interval: 1000,
849879
runtime_id: CharSlice::from("foo"),
850880
debug_enabled: true,
881+
session_id: CharSlice::empty(),
882+
root_session_id: CharSlice::empty(),
883+
parent_session_id: CharSlice::empty(),
851884
}),
852885
);
853886
assert!(error.is_none());
@@ -863,6 +896,40 @@ mod tests {
863896
"foo"
864897
);
865898
assert!(cfg.telemetry_cfg.as_ref().unwrap().debug_enabled);
899+
assert_eq!(
900+
cfg.telemetry_instrumentation_sessions.session_id.as_deref(),
901+
Some("")
902+
);
903+
assert_eq!(
904+
cfg.telemetry_instrumentation_sessions
905+
.root_session_id
906+
.as_deref(),
907+
Some("")
908+
);
909+
assert_eq!(
910+
cfg.telemetry_instrumentation_sessions
911+
.parent_session_id
912+
.as_deref(),
913+
Some("")
914+
);
915+
916+
let mut cfg = TraceExporterConfig::default();
917+
let error = ddog_trace_exporter_config_enable_telemetry(
918+
Some(&mut cfg),
919+
Some(&TelemetryClientConfig {
920+
interval: 500,
921+
runtime_id: CharSlice::from("rid"),
922+
debug_enabled: false,
923+
session_id: CharSlice::from("sess-z"),
924+
root_session_id: CharSlice::from("root-z"),
925+
parent_session_id: CharSlice::from("par-z"),
926+
}),
927+
);
928+
assert!(error.is_none());
929+
let s = &cfg.telemetry_instrumentation_sessions;
930+
assert_eq!(s.session_id.as_deref(), Some("sess-z"));
931+
assert_eq!(s.root_session_id.as_deref(), Some("root-z"));
932+
assert_eq!(s.parent_session_id.as_deref(), Some("par-z"));
866933
}
867934
}
868935

libdd-data-pipeline/src/telemetry/mod.rs

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,24 @@ impl TelemetryClientBuilder {
9393
self
9494
}
9595

96+
/// `dd-session-id` header (with non-empty session id).
97+
pub fn set_session_id(mut self, id: &str) -> Self {
98+
self.config.session_id = Some(id.to_string());
99+
self
100+
}
101+
102+
/// `dd-root-session-id` (omitted if equal to session id).
103+
pub fn set_root_session_id(mut self, id: &str) -> Self {
104+
self.config.root_session_id = Some(id.to_string());
105+
self
106+
}
107+
108+
/// `dd-parent-session-id` (omitted if equal to session id).
109+
pub fn set_parent_session_id(mut self, id: &str) -> Self {
110+
self.config.parent_session_id = Some(id.to_string());
111+
self
112+
}
113+
96114
/// Sets the debug enabled flag for the telemetry client.
97115
pub fn set_debug_enabled(mut self, debug: bool) -> Self {
98116
self.config.debug_enabled = debug;
@@ -808,53 +826,17 @@ mod tests {
808826

809827
#[cfg_attr(miri, ignore)]
810828
#[tokio::test]
811-
async fn runtime_id_test() {
812-
let server = MockServer::start_async().await;
813-
814-
let telemetry_srv = server
815-
.mock_async(|when, then| {
816-
when.method(POST).body_includes(r#""runtime_id":"foo""#);
817-
then.status(200).body("");
818-
})
819-
.await;
820-
821-
let (client, mut worker) = TelemetryClientBuilder::default()
822-
.set_service_name("test_service")
823-
.set_service_version("test_version")
824-
.set_env("test_env")
825-
.set_language("test_language")
826-
.set_language_version("test_language_version")
827-
.set_tracer_version("test_tracer_version")
828-
.set_url(&server.url("/"))
829-
.set_heartbeat(100)
830-
.set_runtime_id("foo")
831-
.build(Handle::current());
832-
tokio::spawn(async move { worker.run().await });
833-
834-
client.start().await;
835-
client
836-
.send(&SendPayloadTelemetry {
837-
requests_count: 1,
838-
..Default::default()
839-
})
840-
.unwrap();
841-
client.shutdown().await;
842-
while telemetry_srv.calls_async().await == 0 {
843-
sleep(Duration::from_millis(10)).await;
844-
}
845-
// One payload generate-metrics
846-
telemetry_srv.assert_calls_async(1).await;
847-
}
848-
849-
#[cfg_attr(miri, ignore)]
850-
#[tokio::test]
851-
async fn application_metadata_test() {
829+
async fn runtime_id_and_session_headers_test() {
852830
let server = MockServer::start_async().await;
853831

854832
let telemetry_srv = server
855833
.mock_async(|when, then| {
856834
when.method(POST)
857-
.body_includes(r#""application":{"service_name":"test_service","service_version":"test_version","env":"test_env","language_name":"test_language","language_version":"test_language_version","tracer_version":"test_tracer_version"}"#);
835+
.body_includes(r#""runtime_id":"foo""#)
836+
.body_includes(r#""application":{"service_name":"test_service","service_version":"test_version","env":"test_env","language_name":"test_language","language_version":"test_language_version","tracer_version":"test_tracer_version"}"#)
837+
.header("dd-session-id", "sess-e2e")
838+
.header("dd-root-session-id", "root-e2e")
839+
.header("dd-parent-session-id", "parent-e2e");
858840
then.status(200).body("");
859841
})
860842
.await;
@@ -869,6 +851,9 @@ mod tests {
869851
.set_url(&server.url("/"))
870852
.set_heartbeat(100)
871853
.set_runtime_id("foo")
854+
.set_session_id("sess-e2e")
855+
.set_root_session_id("root-e2e")
856+
.set_parent_session_id("parent-e2e")
872857
.build(Handle::current());
873858
tokio::spawn(async move { worker.run().await });
874859

libdd-data-pipeline/src/trace_exporter/builder.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ use crate::telemetry::TelemetryClientBuilder;
99
use crate::trace_exporter::agent_response::AgentResponsePayloadVersion;
1010
use crate::trace_exporter::error::BuilderErrorKind;
1111
use crate::trace_exporter::{
12-
add_path, StatsComputationStatus, TelemetryConfig, TraceExporter, TraceExporterError,
13-
TraceExporterInputFormat, TraceExporterOutputFormat, TraceExporterWorkers, TracerMetadata,
14-
INFO_ENDPOINT,
12+
add_path, StatsComputationStatus, TelemetryConfig, TelemetryInstrumentationSessions,
13+
TraceExporter, TraceExporterError, TraceExporterInputFormat, TraceExporterOutputFormat,
14+
TraceExporterWorkers, TracerMetadata, INFO_ENDPOINT,
1515
};
1616
use arc_swap::ArcSwap;
1717
use libdd_common::http_common::new_default_client;
@@ -49,6 +49,7 @@ pub struct TraceExporterBuilder {
4949
compute_stats_by_span_kind: bool,
5050
peer_tags: Vec<String>,
5151
telemetry: Option<TelemetryConfig>,
52+
telemetry_instrumentation_sessions: TelemetryInstrumentationSessions,
5253
health_metrics_enabled: bool,
5354
test_session_token: Option<String>,
5455
agent_rates_payload_version_enabled: bool,
@@ -209,6 +210,15 @@ impl TraceExporterBuilder {
209210
self
210211
}
211212

213+
/// Sets optional instrumentation session headers on telemetry requests (`dd-session-id`, etc.).
214+
pub fn set_telemetry_instrumentation_sessions(
215+
&mut self,
216+
sessions: TelemetryInstrumentationSessions,
217+
) -> &mut Self {
218+
self.telemetry_instrumentation_sessions = sessions;
219+
self
220+
}
221+
212222
/// Enables health metrics emission.
213223
pub fn enable_health_metrics(&mut self) -> &mut Self {
214224
self.health_metrics_enabled = true;
@@ -294,6 +304,7 @@ impl TraceExporterBuilder {
294304
stats = StatsComputationStatus::DisabledByAgent { bucket_size };
295305
}
296306

307+
let sessions = self.telemetry_instrumentation_sessions.clone();
297308
let telemetry = self.telemetry.map(|telemetry_config| {
298309
let mut builder = TelemetryClientBuilder::default()
299310
.set_language(&self.language)
@@ -308,6 +319,15 @@ impl TraceExporterBuilder {
308319
if let Some(id) = telemetry_config.runtime_id {
309320
builder = builder.set_runtime_id(&id);
310321
}
322+
if let Some(ref id) = sessions.session_id {
323+
builder = builder.set_session_id(id);
324+
}
325+
if let Some(ref id) = sessions.root_session_id {
326+
builder = builder.set_root_session_id(id);
327+
}
328+
if let Some(ref id) = sessions.parent_session_id {
329+
builder = builder.set_parent_session_id(id);
330+
}
311331
builder.build(runtime.handle().clone())
312332
});
313333

libdd-data-pipeline/src/trace_exporter/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ mod trace_serializer;
1010
// Re-export the builder
1111
pub use builder::TraceExporterBuilder;
1212

13+
/// Values for optional telemetry HTTP session headers (`dd-session-id`, root/parent).
14+
#[derive(Debug, Default, Clone)]
15+
pub struct TelemetryInstrumentationSessions {
16+
pub session_id: Option<String>,
17+
pub root_session_id: Option<String>,
18+
pub parent_session_id: Option<String>,
19+
}
20+
1321
use self::agent_response::AgentResponse;
1422
use self::metrics::MetricsEmitter;
1523
use self::stats::StatsComputationStatus;

0 commit comments

Comments
 (0)