From a5afbb83dc1b21a5c4be17108843266c8c6d98b0 Mon Sep 17 00:00:00 2001 From: Hartigan Date: Sun, 3 Dec 2023 14:33:27 +0100 Subject: [PATCH 01/10] Add measure flag and agent sampling --- opentelemetry-datadog/Cargo.toml | 2 ++ .../src/exporter/model/mod.rs | 4 +++ .../src/exporter/model/v05.rs | 33 +++++++++++++++++-- opentelemetry-datadog/src/lib.rs | 24 ++++++++++++++ 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/opentelemetry-datadog/Cargo.toml b/opentelemetry-datadog/Cargo.toml index 93078f1e..0617f5b5 100644 --- a/opentelemetry-datadog/Cargo.toml +++ b/opentelemetry-datadog/Cargo.toml @@ -19,6 +19,8 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [features] +measure = [] +agent-sampling = [] reqwest-blocking-client = ["reqwest/blocking", "opentelemetry-http/reqwest"] reqwest-client = ["reqwest", "opentelemetry-http/reqwest"] surf-client = ["surf", "opentelemetry-http/surf"] diff --git a/opentelemetry-datadog/src/exporter/model/mod.rs b/opentelemetry-datadog/src/exporter/model/mod.rs index f0b626a3..78200872 100644 --- a/opentelemetry-datadog/src/exporter/model/mod.rs +++ b/opentelemetry-datadog/src/exporter/model/mod.rs @@ -20,6 +20,10 @@ mod v05; // https://github.com/DataDog/dd-trace-js/blob/c89a35f7d27beb4a60165409376e170eacb194c5/packages/dd-trace/src/constants.js#L4 static SAMPLING_PRIORITY_KEY: &str = "_sampling_priority_v1"; +// https://github.com/DataDog/datadog-agent/blob/ec96f3c24173ec66ba235bda7710504400d9a000/pkg/trace/traceutil/span.go#L20 +#[cfg(feature = "measure")] +static DD_MEASURED_KEY: &str = "_dd.measured"; + /// Custom mapping between opentelemetry spans and datadog spans. /// /// User can provide custom function to change the mapping. It currently supports customizing the following diff --git a/opentelemetry-datadog/src/exporter/model/v05.rs b/opentelemetry-datadog/src/exporter/model/v05.rs index f64de885..d82d59db 100644 --- a/opentelemetry-datadog/src/exporter/model/v05.rs +++ b/opentelemetry-datadog/src/exporter/model/v05.rs @@ -1,6 +1,12 @@ use crate::exporter::intern::StringInterner; +#[cfg(feature = "measure")] +use crate::exporter::model::DD_MEASURED_KEY; use crate::exporter::model::SAMPLING_PRIORITY_KEY; use crate::exporter::{Error, ModelConfig}; +#[cfg(feature = "agent-sampling")] +use crate::propagator::TRACE_STATE_PRIORITY_SAMPLING; +#[cfg(feature = "measure")] +use crate::propagator::TRACE_STATE_MEASURE; use opentelemetry::trace::Status; use opentelemetry_sdk::export::trace::SpanData; use std::time::SystemTime; @@ -204,16 +210,39 @@ where rmp::encode::write_u32(&mut encoded, interner.intern(kv.key.as_str()))?; rmp::encode::write_u32(&mut encoded, interner.intern(kv.value.as_str().as_ref()))?; } - rmp::encode::write_map_len(&mut encoded, 1)?; + + const MEASURE_ENTRY : u32 = if cfg!(feature = "measure") { 1 } else { 0 }; + const METRICS_LEN : u32 = 1 + MEASURE_ENTRY; + + #[cfg(not(feature = "agent-sampling"))] + let sampling_priority = true; + #[cfg(feature = "agent-sampling")] + let sampling_priority = span.span_context + .trace_state() + .get(TRACE_STATE_PRIORITY_SAMPLING) + .map(|x| x == "1") + .unwrap_or(false); + + rmp::encode::write_map_len(&mut encoded, METRICS_LEN)?; rmp::encode::write_u32(&mut encoded, interner.intern(SAMPLING_PRIORITY_KEY))?; rmp::encode::write_f64( &mut encoded, - if span.span_context.is_sampled() { + if sampling_priority { 1.0 } else { 0.0 }, )?; + #[cfg(feature = "measure")] + { + let is_measure = span.span_context + .trace_state() + .get(TRACE_STATE_MEASURE) + .map(|x| if x == "1" { 1.0 } else { 0.0 }) + .unwrap_or(0.0); + rmp::encode::write_u32(&mut encoded, interner.intern(DD_MEASURED_KEY))?; + rmp::encode::write_f64(&mut encoded, is_measure)?; + } rmp::encode::write_u32(&mut encoded, span_type)?; } } diff --git a/opentelemetry-datadog/src/lib.rs b/opentelemetry-datadog/src/lib.rs index 273b9bc8..f4d55882 100644 --- a/opentelemetry-datadog/src/lib.rs +++ b/opentelemetry-datadog/src/lib.rs @@ -141,6 +141,10 @@ pub use exporter::{ ModelConfig, }; pub use propagator::DatadogPropagator; +#[cfg(feature = "agent-sampling")] +pub use propagator::TRACE_STATE_PRIORITY_SAMPLING; +#[cfg(feature = "measure")] +pub use propagator::TRACE_STATE_MEASURE; mod propagator { use once_cell::sync::Lazy; @@ -155,6 +159,10 @@ mod propagator { const DATADOG_SAMPLING_PRIORITY_HEADER: &str = "x-datadog-sampling-priority"; const TRACE_FLAG_DEFERRED: TraceFlags = TraceFlags::new(0x02); + #[cfg(feature = "agent-sampling")] + pub const TRACE_STATE_PRIORITY_SAMPLING: &str = "psr"; + #[cfg(feature = "measure")] + pub const TRACE_STATE_MEASURE: &str = "m"; static DATADOG_HEADER_FIELDS: Lazy<[String; 3]> = Lazy::new(|| { [ @@ -262,7 +270,12 @@ mod propagator { Err(_) => TRACE_FLAG_DEFERRED, }; + #[cfg(not(feature = "agent-sampling"))] let trace_state = TraceState::default(); + #[cfg(feature = "agent-sampling")] + let trace_state = TraceState::from_key_value( + [(TRACE_STATE_PRIORITY_SAMPLING, if sampled.is_sampled() { "1" } else { "0" })] + ).unwrap_or_default(); Ok(SpanContext::new( trace_id, @@ -289,11 +302,22 @@ mod propagator { ); if span_context.trace_flags() & TRACE_FLAG_DEFERRED != TRACE_FLAG_DEFERRED { + #[cfg(not(feature = "agent-sampling"))] let sampling_priority = if span_context.is_sampled() { SamplingPriority::AutoKeep } else { SamplingPriority::AutoReject }; + #[cfg(feature = "agent-sampling")] + let sampling_priority = + if span_context + .trace_state() + .get(TRACE_STATE_PRIORITY_SAMPLING) + .unwrap_or("0") == "1" { + SamplingPriority::AutoKeep + } else { + SamplingPriority::AutoReject + }; injector.set( DATADOG_SAMPLING_PRIORITY_HEADER, From 8c56f6f8a2f4534f9d964772f8f8aa8d77f445e6 Mon Sep 17 00:00:00 2001 From: Hartigan Date: Wed, 27 Dec 2023 20:49:28 +0100 Subject: [PATCH 02/10] Extract functions for agent-sampling --- opentelemetry-datadog/src/lib.rs | 57 ++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/opentelemetry-datadog/src/lib.rs b/opentelemetry-datadog/src/lib.rs index f4d55882..2e15b1ab 100644 --- a/opentelemetry-datadog/src/lib.rs +++ b/opentelemetry-datadog/src/lib.rs @@ -206,6 +206,18 @@ mod propagator { _private: (), } + #[cfg(not(feature = "agent-sampling"))] + fn create_trace_state(_trace_flags: &TraceFlags) -> TraceState { + TraceState::default() + } + + #[cfg(feature = "agent-sampling")] + fn create_trace_state(trace_flags: &TraceFlags) -> TraceState { + TraceState::from_key_value( + [(TRACE_STATE_PRIORITY_SAMPLING, if trace_flags.is_sampled() { "1" } else { "0" })] + ).unwrap_or_default() + } + impl DatadogPropagator { /// Creates a new `DatadogPropagator`. pub fn new() -> Self { @@ -270,12 +282,7 @@ mod propagator { Err(_) => TRACE_FLAG_DEFERRED, }; - #[cfg(not(feature = "agent-sampling"))] - let trace_state = TraceState::default(); - #[cfg(feature = "agent-sampling")] - let trace_state = TraceState::from_key_value( - [(TRACE_STATE_PRIORITY_SAMPLING, if sampled.is_sampled() { "1" } else { "0" })] - ).unwrap_or_default(); + let trace_state = create_trace_state(&sampled); Ok(SpanContext::new( trace_id, @@ -287,6 +294,27 @@ mod propagator { } } + #[cfg(not(feature = "agent-sampling"))] + fn get_sampling_priority(span_context: &SpanContext) -> SamplingPriority { + if span_context.is_sampled() { + SamplingPriority::AutoKeep + } else { + SamplingPriority::AutoReject + } + } + + #[cfg(feature = "agent-sampling")] + fn get_sampling_priority(span_context: &SpanContext) -> SamplingPriority { + if span_context + .trace_state() + .get(TRACE_STATE_PRIORITY_SAMPLING) + .unwrap_or("0") == "1" { + SamplingPriority::AutoKeep + } else { + SamplingPriority::AutoReject + } + } + impl TextMapPropagator for DatadogPropagator { fn inject_context(&self, cx: &Context, injector: &mut dyn Injector) { let span = cx.span(); @@ -302,22 +330,7 @@ mod propagator { ); if span_context.trace_flags() & TRACE_FLAG_DEFERRED != TRACE_FLAG_DEFERRED { - #[cfg(not(feature = "agent-sampling"))] - let sampling_priority = if span_context.is_sampled() { - SamplingPriority::AutoKeep - } else { - SamplingPriority::AutoReject - }; - #[cfg(feature = "agent-sampling")] - let sampling_priority = - if span_context - .trace_state() - .get(TRACE_STATE_PRIORITY_SAMPLING) - .unwrap_or("0") == "1" { - SamplingPriority::AutoKeep - } else { - SamplingPriority::AutoReject - }; + let sampling_priority = get_sampling_priority(&span_context); injector.set( DATADOG_SAMPLING_PRIORITY_HEADER, From 88e04f270159db42908443ba698163304a1bb5a6 Mon Sep 17 00:00:00 2001 From: Hartigan Date: Thu, 28 Dec 2023 00:33:31 +0100 Subject: [PATCH 03/10] Clean code --- opentelemetry-datadog/Cargo.toml | 1 - .../src/exporter/model/mod.rs | 1 - .../src/exporter/model/v05.rs | 67 +++++++++---------- opentelemetry-datadog/src/lib.rs | 2 - 4 files changed, 33 insertions(+), 38 deletions(-) diff --git a/opentelemetry-datadog/Cargo.toml b/opentelemetry-datadog/Cargo.toml index 0617f5b5..ef16e664 100644 --- a/opentelemetry-datadog/Cargo.toml +++ b/opentelemetry-datadog/Cargo.toml @@ -19,7 +19,6 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [features] -measure = [] agent-sampling = [] reqwest-blocking-client = ["reqwest/blocking", "opentelemetry-http/reqwest"] reqwest-client = ["reqwest", "opentelemetry-http/reqwest"] diff --git a/opentelemetry-datadog/src/exporter/model/mod.rs b/opentelemetry-datadog/src/exporter/model/mod.rs index 78200872..93b4d9ee 100644 --- a/opentelemetry-datadog/src/exporter/model/mod.rs +++ b/opentelemetry-datadog/src/exporter/model/mod.rs @@ -21,7 +21,6 @@ mod v05; static SAMPLING_PRIORITY_KEY: &str = "_sampling_priority_v1"; // https://github.com/DataDog/datadog-agent/blob/ec96f3c24173ec66ba235bda7710504400d9a000/pkg/trace/traceutil/span.go#L20 -#[cfg(feature = "measure")] static DD_MEASURED_KEY: &str = "_dd.measured"; /// Custom mapping between opentelemetry spans and datadog spans. diff --git a/opentelemetry-datadog/src/exporter/model/v05.rs b/opentelemetry-datadog/src/exporter/model/v05.rs index d82d59db..38d42ccb 100644 --- a/opentelemetry-datadog/src/exporter/model/v05.rs +++ b/opentelemetry-datadog/src/exporter/model/v05.rs @@ -1,11 +1,11 @@ use crate::exporter::intern::StringInterner; -#[cfg(feature = "measure")] -use crate::exporter::model::DD_MEASURED_KEY; -use crate::exporter::model::SAMPLING_PRIORITY_KEY; +use crate::exporter::model::{ + DD_MEASURED_KEY, + SAMPLING_PRIORITY_KEY, +}; use crate::exporter::{Error, ModelConfig}; #[cfg(feature = "agent-sampling")] use crate::propagator::TRACE_STATE_PRIORITY_SAMPLING; -#[cfg(feature = "measure")] use crate::propagator::TRACE_STATE_MEASURE; use opentelemetry::trace::Status; use opentelemetry_sdk::export::trace::SpanData; @@ -14,6 +14,7 @@ use std::time::SystemTime; use super::unified_tags::{UnifiedTagField, UnifiedTags}; const SPAN_NUM_ELEMENTS: u32 = 12; +const METRICS_LEN : u32 = 2; // Protocol documentation sourced from https://github.com/DataDog/datadog-agent/blob/c076ea9a1ffbde4c76d35343dbc32aecbbf99cb9/pkg/trace/api/version.go // @@ -120,6 +121,28 @@ fn write_unified_tag( Ok(()) } +fn get_metric_by_name(span: &SpanData, name: &str) -> f64 { + span.span_context + .trace_state() + .get(name) + .map(|x| if x == "1" { 1.0 } else { 0.0 }) + .unwrap_or(0.0) +} + +#[cfg(not(feature = "agent-sampling"))] +fn get_sampling_priority(_span: &SpanData) -> f64 { + 1.0 +} + +#[cfg(feature = "agent-sampling")] +fn get_sampling_priority(span: &SpanData) -> f64 { + get_metric_by_name(TRACE_STATE_PRIORITY_SAMPLING) +} + +fn get_is_measure(span: &SpanData) -> f64 { + get_metric_by_name(span, TRACE_STATE_MEASURE) +} + fn encode_traces( interner: &mut StringInterner, model_config: &ModelConfig, @@ -211,38 +234,14 @@ where rmp::encode::write_u32(&mut encoded, interner.intern(kv.value.as_str().as_ref()))?; } - const MEASURE_ENTRY : u32 = if cfg!(feature = "measure") { 1 } else { 0 }; - const METRICS_LEN : u32 = 1 + MEASURE_ENTRY; - - #[cfg(not(feature = "agent-sampling"))] - let sampling_priority = true; - #[cfg(feature = "agent-sampling")] - let sampling_priority = span.span_context - .trace_state() - .get(TRACE_STATE_PRIORITY_SAMPLING) - .map(|x| x == "1") - .unwrap_or(false); - rmp::encode::write_map_len(&mut encoded, METRICS_LEN)?; rmp::encode::write_u32(&mut encoded, interner.intern(SAMPLING_PRIORITY_KEY))?; - rmp::encode::write_f64( - &mut encoded, - if sampling_priority { - 1.0 - } else { - 0.0 - }, - )?; - #[cfg(feature = "measure")] - { - let is_measure = span.span_context - .trace_state() - .get(TRACE_STATE_MEASURE) - .map(|x| if x == "1" { 1.0 } else { 0.0 }) - .unwrap_or(0.0); - rmp::encode::write_u32(&mut encoded, interner.intern(DD_MEASURED_KEY))?; - rmp::encode::write_f64(&mut encoded, is_measure)?; - } + let sampling_priority = get_sampling_priority(&span); + rmp::encode::write_f64(&mut encoded, sampling_priority)?; + + rmp::encode::write_u32(&mut encoded, interner.intern(DD_MEASURED_KEY))?; + let is_measure = get_is_measure(&span); + rmp::encode::write_f64(&mut encoded, is_measure)?; rmp::encode::write_u32(&mut encoded, span_type)?; } } diff --git a/opentelemetry-datadog/src/lib.rs b/opentelemetry-datadog/src/lib.rs index 2e15b1ab..78e49c36 100644 --- a/opentelemetry-datadog/src/lib.rs +++ b/opentelemetry-datadog/src/lib.rs @@ -143,7 +143,6 @@ pub use exporter::{ pub use propagator::DatadogPropagator; #[cfg(feature = "agent-sampling")] pub use propagator::TRACE_STATE_PRIORITY_SAMPLING; -#[cfg(feature = "measure")] pub use propagator::TRACE_STATE_MEASURE; mod propagator { @@ -161,7 +160,6 @@ mod propagator { const TRACE_FLAG_DEFERRED: TraceFlags = TraceFlags::new(0x02); #[cfg(feature = "agent-sampling")] pub const TRACE_STATE_PRIORITY_SAMPLING: &str = "psr"; - #[cfg(feature = "measure")] pub const TRACE_STATE_MEASURE: &str = "m"; static DATADOG_HEADER_FIELDS: Lazy<[String; 3]> = Lazy::new(|| { From a55ca71825f9cf926d2634f354f5fa799f835fd4 Mon Sep 17 00:00:00 2001 From: Hartigan Date: Thu, 28 Dec 2023 01:24:15 +0100 Subject: [PATCH 04/10] Fix tests --- .../src/exporter/model/v05.rs | 9 ++- opentelemetry-datadog/src/lib.rs | 60 ++++++++++++++----- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/opentelemetry-datadog/src/exporter/model/v05.rs b/opentelemetry-datadog/src/exporter/model/v05.rs index 38d42ccb..e286bc0c 100644 --- a/opentelemetry-datadog/src/exporter/model/v05.rs +++ b/opentelemetry-datadog/src/exporter/model/v05.rs @@ -6,7 +6,10 @@ use crate::exporter::model::{ use crate::exporter::{Error, ModelConfig}; #[cfg(feature = "agent-sampling")] use crate::propagator::TRACE_STATE_PRIORITY_SAMPLING; -use crate::propagator::TRACE_STATE_MEASURE; +use crate::propagator::{ + TRACE_STATE_MEASURE, + TRACE_STATE_TRUE_VALUE, +}; use opentelemetry::trace::Status; use opentelemetry_sdk::export::trace::SpanData; use std::time::SystemTime; @@ -125,7 +128,7 @@ fn get_metric_by_name(span: &SpanData, name: &str) -> f64 { span.span_context .trace_state() .get(name) - .map(|x| if x == "1" { 1.0 } else { 0.0 }) + .map(|x| if x == TRACE_STATE_TRUE_VALUE { 1.0 } else { 0.0 }) .unwrap_or(0.0) } @@ -136,7 +139,7 @@ fn get_sampling_priority(_span: &SpanData) -> f64 { #[cfg(feature = "agent-sampling")] fn get_sampling_priority(span: &SpanData) -> f64 { - get_metric_by_name(TRACE_STATE_PRIORITY_SAMPLING) + get_metric_by_name(span, TRACE_STATE_PRIORITY_SAMPLING) } fn get_is_measure(span: &SpanData) -> f64 { diff --git a/opentelemetry-datadog/src/lib.rs b/opentelemetry-datadog/src/lib.rs index 78e49c36..dce93fdc 100644 --- a/opentelemetry-datadog/src/lib.rs +++ b/opentelemetry-datadog/src/lib.rs @@ -143,7 +143,11 @@ pub use exporter::{ pub use propagator::DatadogPropagator; #[cfg(feature = "agent-sampling")] pub use propagator::TRACE_STATE_PRIORITY_SAMPLING; -pub use propagator::TRACE_STATE_MEASURE; +pub use propagator::{ + TRACE_STATE_MEASURE, + TRACE_STATE_TRUE_VALUE, + TRACE_STATE_FALSE_VALUE, +}; mod propagator { use once_cell::sync::Lazy; @@ -161,6 +165,8 @@ mod propagator { #[cfg(feature = "agent-sampling")] pub const TRACE_STATE_PRIORITY_SAMPLING: &str = "psr"; pub const TRACE_STATE_MEASURE: &str = "m"; + pub const TRACE_STATE_TRUE_VALUE: &str = "1"; + pub const TRACE_STATE_FALSE_VALUE: &str = "0"; static DATADOG_HEADER_FIELDS: Lazy<[String; 3]> = Lazy::new(|| { [ @@ -205,15 +211,19 @@ mod propagator { } #[cfg(not(feature = "agent-sampling"))] - fn create_trace_state(_trace_flags: &TraceFlags) -> TraceState { - TraceState::default() + fn create_trace_state_and_flags(trace_flags: TraceFlags) -> (TraceState, TraceFlags) { + (TraceState::default(), trace_flags) } #[cfg(feature = "agent-sampling")] - fn create_trace_state(trace_flags: &TraceFlags) -> TraceState { - TraceState::from_key_value( - [(TRACE_STATE_PRIORITY_SAMPLING, if trace_flags.is_sampled() { "1" } else { "0" })] - ).unwrap_or_default() + fn create_trace_state_and_flags(trace_flags: TraceFlags) -> (TraceState, TraceFlags) { + if trace_flags & TRACE_FLAG_DEFERRED == TRACE_FLAG_DEFERRED { + (TraceState::default(), trace_flags) + } else { + (TraceState::from_key_value( + [(TRACE_STATE_PRIORITY_SAMPLING, if trace_flags.is_sampled() { TRACE_STATE_TRUE_VALUE } else { TRACE_STATE_FALSE_VALUE })] + ).unwrap_or_default(), TraceFlags::SAMPLED) + } } impl DatadogPropagator { @@ -280,12 +290,12 @@ mod propagator { Err(_) => TRACE_FLAG_DEFERRED, }; - let trace_state = create_trace_state(&sampled); + let (trace_state, trace_flags) = create_trace_state_and_flags(sampled); Ok(SpanContext::new( trace_id, span_id, - sampled, + trace_flags, true, trace_state, )) @@ -306,7 +316,7 @@ mod propagator { if span_context .trace_state() .get(TRACE_STATE_PRIORITY_SAMPLING) - .unwrap_or("0") == "1" { + .unwrap_or(TRACE_STATE_FALSE_VALUE) == TRACE_STATE_TRUE_VALUE { SamplingPriority::AutoKeep } else { SamplingPriority::AutoReject @@ -358,7 +368,18 @@ mod propagator { #[rustfmt::skip] fn extract_test_data() -> Vec<(Vec<(&'static str, &'static str)>, SpanContext)> { - vec![ + #[cfg(feature = "agent-sampling")] + return vec![ + (vec![], SpanContext::empty_context()), + (vec![(DATADOG_SAMPLING_PRIORITY_HEADER, "0")], SpanContext::empty_context()), + (vec![(DATADOG_TRACE_ID_HEADER, "garbage")], SpanContext::empty_context()), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "garbage")], SpanContext::new(TraceId::from_u128(1234), SpanId::INVALID, TRACE_FLAG_DEFERRED, true, TraceState::default())), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TRACE_FLAG_DEFERRED, true, TraceState::default())), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "0")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, TraceState::from_key_value([(TRACE_STATE_PRIORITY_SAMPLING, TRACE_STATE_FALSE_VALUE)]).unwrap())), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "1")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, TraceState::from_key_value([(TRACE_STATE_PRIORITY_SAMPLING, TRACE_STATE_TRUE_VALUE)]).unwrap())), + ]; + #[cfg(not(feature = "agent-sampling"))] + return vec![ (vec![], SpanContext::empty_context()), (vec![(DATADOG_SAMPLING_PRIORITY_HEADER, "0")], SpanContext::empty_context()), (vec![(DATADOG_TRACE_ID_HEADER, "garbage")], SpanContext::empty_context()), @@ -366,12 +387,23 @@ mod propagator { (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TRACE_FLAG_DEFERRED, true, TraceState::default())), (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "0")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::default(), true, TraceState::default())), (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "1")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, TraceState::default())), - ] + ]; } #[rustfmt::skip] fn inject_test_data() -> Vec<(Vec<(&'static str, &'static str)>, SpanContext)> { - vec![ + #[cfg(feature = "agent-sampling")] + return vec![ + (vec![], SpanContext::empty_context()), + (vec![], SpanContext::new(TraceId::INVALID, SpanId::INVALID, TRACE_FLAG_DEFERRED, true, TraceState::default())), + (vec![], SpanContext::new(TraceId::from_hex("1234").unwrap(), SpanId::INVALID, TRACE_FLAG_DEFERRED, true, TraceState::default())), + (vec![], SpanContext::new(TraceId::from_hex("1234").unwrap(), SpanId::INVALID, TraceFlags::SAMPLED, true, TraceState::default())), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TRACE_FLAG_DEFERRED, true, TraceState::default())), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "0")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, TraceState::from_key_value([(TRACE_STATE_PRIORITY_SAMPLING, TRACE_STATE_FALSE_VALUE)]).unwrap())), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "1")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, TraceState::from_key_value([(TRACE_STATE_PRIORITY_SAMPLING, TRACE_STATE_TRUE_VALUE)]).unwrap())), + ]; + #[cfg(not(feature = "agent-sampling"))] + return vec![ (vec![], SpanContext::empty_context()), (vec![], SpanContext::new(TraceId::INVALID, SpanId::INVALID, TRACE_FLAG_DEFERRED, true, TraceState::default())), (vec![], SpanContext::new(TraceId::from_hex("1234").unwrap(), SpanId::INVALID, TRACE_FLAG_DEFERRED, true, TraceState::default())), @@ -379,7 +411,7 @@ mod propagator { (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TRACE_FLAG_DEFERRED, true, TraceState::default())), (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "0")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::default(), true, TraceState::default())), (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "1")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, TraceState::default())), - ] + ]; } #[test] From 884bfe46d90fa962a7663524747b9d5bb7843332 Mon Sep 17 00:00:00 2001 From: Hartigan Date: Fri, 29 Dec 2023 21:24:32 +0100 Subject: [PATCH 05/10] Clean api for trace state --- .../src/exporter/model/v05.rs | 31 ++--- opentelemetry-datadog/src/lib.rs | 111 +++++++++++++++--- 2 files changed, 107 insertions(+), 35 deletions(-) diff --git a/opentelemetry-datadog/src/exporter/model/v05.rs b/opentelemetry-datadog/src/exporter/model/v05.rs index e286bc0c..c7b2835d 100644 --- a/opentelemetry-datadog/src/exporter/model/v05.rs +++ b/opentelemetry-datadog/src/exporter/model/v05.rs @@ -4,12 +4,7 @@ use crate::exporter::model::{ SAMPLING_PRIORITY_KEY, }; use crate::exporter::{Error, ModelConfig}; -#[cfg(feature = "agent-sampling")] -use crate::propagator::TRACE_STATE_PRIORITY_SAMPLING; -use crate::propagator::{ - TRACE_STATE_MEASURE, - TRACE_STATE_TRUE_VALUE, -}; +use crate::propagator::DatadogTraceState; use opentelemetry::trace::Status; use opentelemetry_sdk::export::trace::SpanData; use std::time::SystemTime; @@ -124,14 +119,6 @@ fn write_unified_tag( Ok(()) } -fn get_metric_by_name(span: &SpanData, name: &str) -> f64 { - span.span_context - .trace_state() - .get(name) - .map(|x| if x == TRACE_STATE_TRUE_VALUE { 1.0 } else { 0.0 }) - .unwrap_or(0.0) -} - #[cfg(not(feature = "agent-sampling"))] fn get_sampling_priority(_span: &SpanData) -> f64 { 1.0 @@ -139,11 +126,19 @@ fn get_sampling_priority(_span: &SpanData) -> f64 { #[cfg(feature = "agent-sampling")] fn get_sampling_priority(span: &SpanData) -> f64 { - get_metric_by_name(span, TRACE_STATE_PRIORITY_SAMPLING) + if span.span_context.trace_state().priority_sampling_enabled() { + 1.0 + } else { + 0.0 + } } -fn get_is_measure(span: &SpanData) -> f64 { - get_metric_by_name(span, TRACE_STATE_MEASURE) +fn get_measuring(span: &SpanData) -> f64 { + if span.span_context.trace_state().measuring_enabled() { + 1.0 + } else { + 0.0 + } } fn encode_traces( @@ -243,7 +238,7 @@ where rmp::encode::write_f64(&mut encoded, sampling_priority)?; rmp::encode::write_u32(&mut encoded, interner.intern(DD_MEASURED_KEY))?; - let is_measure = get_is_measure(&span); + let is_measure = get_measuring(&span); rmp::encode::write_f64(&mut encoded, is_measure)?; rmp::encode::write_u32(&mut encoded, span_type)?; } diff --git a/opentelemetry-datadog/src/lib.rs b/opentelemetry-datadog/src/lib.rs index dce93fdc..7c2dbcba 100644 --- a/opentelemetry-datadog/src/lib.rs +++ b/opentelemetry-datadog/src/lib.rs @@ -140,13 +140,10 @@ pub use exporter::{ new_pipeline, ApiVersion, DatadogExporter, DatadogPipelineBuilder, Error, FieldMappingFn, ModelConfig, }; -pub use propagator::DatadogPropagator; -#[cfg(feature = "agent-sampling")] -pub use propagator::TRACE_STATE_PRIORITY_SAMPLING; pub use propagator::{ - TRACE_STATE_MEASURE, - TRACE_STATE_TRUE_VALUE, - TRACE_STATE_FALSE_VALUE, + DatadogPropagator, + DatadogTraceState, + DatadogTraceStateBuilder, }; mod propagator { @@ -163,10 +160,10 @@ mod propagator { const TRACE_FLAG_DEFERRED: TraceFlags = TraceFlags::new(0x02); #[cfg(feature = "agent-sampling")] - pub const TRACE_STATE_PRIORITY_SAMPLING: &str = "psr"; - pub const TRACE_STATE_MEASURE: &str = "m"; - pub const TRACE_STATE_TRUE_VALUE: &str = "1"; - pub const TRACE_STATE_FALSE_VALUE: &str = "0"; + const TRACE_STATE_PRIORITY_SAMPLING: &str = "psr"; + const TRACE_STATE_MEASURE: &str = "m"; + const TRACE_STATE_TRUE_VALUE: &str = "1"; + const TRACE_STATE_FALSE_VALUE: &str = "0"; static DATADOG_HEADER_FIELDS: Lazy<[String; 3]> = Lazy::new(|| { [ @@ -176,6 +173,88 @@ mod propagator { ] }); + #[derive(Default)] + pub struct DatadogTraceStateBuilder { + #[cfg(feature = "agent-sampling")] + priority_sampling: bool, + measuring: bool, + } + + fn boolean_to_trace_state_flag(value: bool) -> &'static str { + if value { TRACE_STATE_TRUE_VALUE } else { TRACE_STATE_FALSE_VALUE } + } + + fn trace_flag_to_boolean(value: &str) -> bool { + value == TRACE_STATE_TRUE_VALUE + } + + impl DatadogTraceStateBuilder { + #[cfg(feature = "agent-sampling")] + pub fn with_priority_sampling(self, enabled: bool) -> Self { + Self { + priority_sampling: enabled, + ..self + } + } + + pub fn with_measuring(self, enabled: bool) -> Self { + Self { + measuring: enabled, + ..self + } + } + + pub fn build(self) -> TraceState { + #[cfg(not(feature = "agent-sampling"))] + let values = [(TRACE_STATE_MEASURE, boolean_to_trace_state_flag(self.measuring))]; + #[cfg(feature = "agent-sampling")] + let values = [ + (TRACE_STATE_MEASURE, boolean_to_trace_state_flag(self.measuring)), + (TRACE_STATE_PRIORITY_SAMPLING, boolean_to_trace_state_flag(self.priority_sampling)), + ]; + + TraceState::from_key_value(values).unwrap_or_default() + } + } + + pub trait DatadogTraceState { + fn with_measuring(&self, enabled: bool) -> TraceState; + + fn measuring_enabled(&self) -> bool; + + #[cfg(feature = "agent-sampling")] + fn with_priority_sampling(&self, enabled: bool) -> TraceState; + + #[cfg(feature = "agent-sampling")] + fn priority_sampling_enabled(&self) -> bool; + } + + impl DatadogTraceState for TraceState { + fn with_measuring(&self, enabled: bool) -> TraceState { + self.insert(TRACE_STATE_MEASURE, boolean_to_trace_state_flag(enabled)) + .unwrap_or_else(|_err| self.clone()) + } + + fn measuring_enabled(&self) -> bool { + self.get(TRACE_STATE_MEASURE) + .map(trace_flag_to_boolean) + .unwrap_or_default() + } + + #[cfg(feature = "agent-sampling")] + fn with_priority_sampling(&self, enabled: bool) -> TraceState { + self.insert(TRACE_STATE_PRIORITY_SAMPLING, boolean_to_trace_state_flag(enabled)) + .unwrap_or_else(|_err| self.clone()) + } + + #[cfg(feature = "agent-sampling")] + fn priority_sampling_enabled(&self) -> bool { + self.get(TRACE_STATE_PRIORITY_SAMPLING) + .map(trace_flag_to_boolean) + .unwrap_or_default() + } + } + enum SamplingPriority { UserReject = -1, AutoReject = 0, @@ -220,9 +299,7 @@ mod propagator { if trace_flags & TRACE_FLAG_DEFERRED == TRACE_FLAG_DEFERRED { (TraceState::default(), trace_flags) } else { - (TraceState::from_key_value( - [(TRACE_STATE_PRIORITY_SAMPLING, if trace_flags.is_sampled() { TRACE_STATE_TRUE_VALUE } else { TRACE_STATE_FALSE_VALUE })] - ).unwrap_or_default(), TraceFlags::SAMPLED) + (DatadogTraceStateBuilder::default().with_priority_sampling(trace_flags.is_sampled()).build(), TraceFlags::SAMPLED) } } @@ -375,8 +452,8 @@ mod propagator { (vec![(DATADOG_TRACE_ID_HEADER, "garbage")], SpanContext::empty_context()), (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "garbage")], SpanContext::new(TraceId::from_u128(1234), SpanId::INVALID, TRACE_FLAG_DEFERRED, true, TraceState::default())), (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TRACE_FLAG_DEFERRED, true, TraceState::default())), - (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "0")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, TraceState::from_key_value([(TRACE_STATE_PRIORITY_SAMPLING, TRACE_STATE_FALSE_VALUE)]).unwrap())), - (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "1")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, TraceState::from_key_value([(TRACE_STATE_PRIORITY_SAMPLING, TRACE_STATE_TRUE_VALUE)]).unwrap())), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "0")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, DatadogTraceStateBuilder::default().with_priority_sampling(false).build())), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "1")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, DatadogTraceStateBuilder::default().with_priority_sampling(true).build())), ]; #[cfg(not(feature = "agent-sampling"))] return vec![ @@ -399,8 +476,8 @@ mod propagator { (vec![], SpanContext::new(TraceId::from_hex("1234").unwrap(), SpanId::INVALID, TRACE_FLAG_DEFERRED, true, TraceState::default())), (vec![], SpanContext::new(TraceId::from_hex("1234").unwrap(), SpanId::INVALID, TraceFlags::SAMPLED, true, TraceState::default())), (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TRACE_FLAG_DEFERRED, true, TraceState::default())), - (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "0")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, TraceState::from_key_value([(TRACE_STATE_PRIORITY_SAMPLING, TRACE_STATE_FALSE_VALUE)]).unwrap())), - (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "1")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, TraceState::from_key_value([(TRACE_STATE_PRIORITY_SAMPLING, TRACE_STATE_TRUE_VALUE)]).unwrap())), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "0")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, DatadogTraceStateBuilder::default().with_priority_sampling(false).build())), + (vec![(DATADOG_TRACE_ID_HEADER, "1234"), (DATADOG_PARENT_ID_HEADER, "12"), (DATADOG_SAMPLING_PRIORITY_HEADER, "1")], SpanContext::new(TraceId::from_u128(1234), SpanId::from_u64(12), TraceFlags::SAMPLED, true, DatadogTraceStateBuilder::default().with_priority_sampling(true).build())), ]; #[cfg(not(feature = "agent-sampling"))] return vec![ From f2a9facaa3e617f5193678bb2bc75b220bb75410 Mon Sep 17 00:00:00 2001 From: Hartigan Date: Fri, 29 Dec 2023 21:27:19 +0100 Subject: [PATCH 06/10] Clean api for trace state --- opentelemetry-datadog/src/exporter/model/v05.rs | 4 ++-- opentelemetry-datadog/src/lib.rs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/opentelemetry-datadog/src/exporter/model/v05.rs b/opentelemetry-datadog/src/exporter/model/v05.rs index c7b2835d..b2c68453 100644 --- a/opentelemetry-datadog/src/exporter/model/v05.rs +++ b/opentelemetry-datadog/src/exporter/model/v05.rs @@ -238,8 +238,8 @@ where rmp::encode::write_f64(&mut encoded, sampling_priority)?; rmp::encode::write_u32(&mut encoded, interner.intern(DD_MEASURED_KEY))?; - let is_measure = get_measuring(&span); - rmp::encode::write_f64(&mut encoded, is_measure)?; + let measuring = get_measuring(&span); + rmp::encode::write_f64(&mut encoded, measuring)?; rmp::encode::write_u32(&mut encoded, span_type)?; } } diff --git a/opentelemetry-datadog/src/lib.rs b/opentelemetry-datadog/src/lib.rs index 7c2dbcba..2d3aa97a 100644 --- a/opentelemetry-datadog/src/lib.rs +++ b/opentelemetry-datadog/src/lib.rs @@ -392,8 +392,7 @@ mod propagator { fn get_sampling_priority(span_context: &SpanContext) -> SamplingPriority { if span_context .trace_state() - .get(TRACE_STATE_PRIORITY_SAMPLING) - .unwrap_or(TRACE_STATE_FALSE_VALUE) == TRACE_STATE_TRUE_VALUE { + .priority_sampling_enabled() { SamplingPriority::AutoKeep } else { SamplingPriority::AutoReject From 40e14c2db8df850b5b0ba190090c31f763460e05 Mon Sep 17 00:00:00 2001 From: Hartigan Date: Tue, 13 Feb 2024 00:58:50 +0100 Subject: [PATCH 07/10] Update CHANGELOG.md and README.md --- opentelemetry-datadog/CHANGELOG.md | 6 ++ opentelemetry-datadog/README.md | 1 + .../examples/agent_sampling.rs | 77 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 opentelemetry-datadog/examples/agent_sampling.rs diff --git a/opentelemetry-datadog/CHANGELOG.md b/opentelemetry-datadog/CHANGELOG.md index 1064e5a5..24c5fac9 100644 --- a/opentelemetry-datadog/CHANGELOG.md +++ b/opentelemetry-datadog/CHANGELOG.md @@ -4,6 +4,12 @@ WARNING The current version relies on features only in upstream git version. This should be modified before releasing. +### Changed + +- allow send all traces to `datadog-agent` with `agent-sampling` feature. +- allow `datadog-agent` generate metrics from spans for [APM](https://docs.datadoghq.com/tracing/metrics/). + + ## v0.9.0 ### Changed diff --git a/opentelemetry-datadog/README.md b/opentelemetry-datadog/README.md index 4a80077a..f56c0b14 100644 --- a/opentelemetry-datadog/README.md +++ b/opentelemetry-datadog/README.md @@ -24,6 +24,7 @@ to [`Datadog`]. `opentelemetry-datadog` supports following features: +- `agent-sampling`: move decision making about sampling to `datadog-agent` (see `agent_sampling.rs` example). - `reqwest-blocking-client`: use `reqwest` blocking http client to send spans. - `reqwest-client`: use `reqwest` http client to send spans. - `surf-client`: use `surf` http client to send spans. diff --git a/opentelemetry-datadog/examples/agent_sampling.rs b/opentelemetry-datadog/examples/agent_sampling.rs new file mode 100644 index 00000000..b57bfab2 --- /dev/null +++ b/opentelemetry-datadog/examples/agent_sampling.rs @@ -0,0 +1,77 @@ +use opentelemetry::{ + global::{self, shutdown_tracer_provider}, + trace::{SamplingResult, Span, TraceContextExt, Tracer}, + Key, +}; +use opentelemetry_datadog::{new_pipeline, ApiVersion, DatadogTraceStateBuilder}; +use opentelemetry_sdk::trace::{self, RandomIdGenerator, ShouldSample}; +use std::thread; +use std::time::Duration; + +fn bar() { + let tracer = global::tracer("component-bar"); + let mut span = tracer.start("bar"); + span.set_attribute(Key::new("span.type").string("sql")); + span.set_attribute(Key::new("sql.query").string("SELECT * FROM table")); + thread::sleep(Duration::from_millis(6)); + span.end() +} + +#[derive(Debug, Clone)] +struct AgentBasedSampler; + +impl ShouldSample for AgentBasedSampler { + fn should_sample( + &self, + parent_context: Option<&opentelemetry::Context>, + _trace_id: opentelemetry::trace::TraceId, + _name: &str, + _span_kind: &opentelemetry::trace::SpanKind, + _attributes: &[opentelemetry::KeyValue], + _links: &[opentelemetry::trace::Link], + ) -> opentelemetry::trace::SamplingResult { + let trace_state = parent_context + .map(|parent_context| + parent_context.span().span_context().trace_state().clone() // inherit sample decision from parent span + ) + .unwrap_or_else(|| DatadogTraceStateBuilder::default() + .with_priority_sampling(true) // always sample root span(span without remote or local parent) + .with_measuring(true) // datadog-agent will create metric for this span for APM + .build() + ); + + SamplingResult { + decision: opentelemetry::trace::SamplingDecision::RecordAndSample, // send all spans to datadog-agent + attributes: vec![], + trace_state, + } + } +} + +fn main() -> Result<(), Box> { + let tracer = new_pipeline() + .with_service_name("agent-sampling-demo") + .with_api_version(ApiVersion::Version05) + .with_trace_config( + trace::config() + .with_sampler(AgentBasedSampler) + .with_id_generator(RandomIdGenerator::default()) + ) + .install_simple()?; + + tracer.in_span("foo", |cx| { + let span = cx.span(); + span.set_attribute(Key::new("span.type").string("web")); + span.set_attribute(Key::new("http.url").string("http://localhost:8080/foo")); + span.set_attribute(Key::new("http.method").string("GET")); + span.set_attribute(Key::new("http.status_code").i64(200)); + + thread::sleep(Duration::from_millis(6)); + bar(); + thread::sleep(Duration::from_millis(6)); + }); + + shutdown_tracer_provider(); + + Ok(()) +} From 2703323358d28eea43788681e3a965c738c514f3 Mon Sep 17 00:00:00 2001 From: Hartigan Date: Sun, 18 Feb 2024 01:01:41 +0100 Subject: [PATCH 08/10] Fix build tests without 'agent-sampling' feature --- opentelemetry-datadog/Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/opentelemetry-datadog/Cargo.toml b/opentelemetry-datadog/Cargo.toml index ef16e664..76bdb690 100644 --- a/opentelemetry-datadog/Cargo.toml +++ b/opentelemetry-datadog/Cargo.toml @@ -52,3 +52,8 @@ opentelemetry_sdk = { git = "https://github.com/open-telemetry/opentelemetry-rus [[example]] name = "datadog" path = "examples/datadog.rs" + +[[example]] +name = "agent_sampling" +path = "examples/agent_sampling.rs" +required-features = ["agent-sampling"] From 859884ffdabd21d0295291afd8daaa14ff11c6fc Mon Sep 17 00:00:00 2001 From: Hartigan Date: Sat, 16 Mar 2024 17:29:54 +0100 Subject: [PATCH 09/10] Code format: 'cargo fmt --all' for opentelemetry-datadog --- .../examples/agent_sampling.rs | 17 +++---- .../src/exporter/model/v05.rs | 7 +-- opentelemetry-datadog/src/lib.rs | 47 ++++++++++++------- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/opentelemetry-datadog/examples/agent_sampling.rs b/opentelemetry-datadog/examples/agent_sampling.rs index b57bfab2..4b0b6ea0 100644 --- a/opentelemetry-datadog/examples/agent_sampling.rs +++ b/opentelemetry-datadog/examples/agent_sampling.rs @@ -31,14 +31,15 @@ impl ShouldSample for AgentBasedSampler { _links: &[opentelemetry::trace::Link], ) -> opentelemetry::trace::SamplingResult { let trace_state = parent_context - .map(|parent_context| - parent_context.span().span_context().trace_state().clone() // inherit sample decision from parent span + .map( + |parent_context| parent_context.span().span_context().trace_state().clone(), // inherit sample decision from parent span ) - .unwrap_or_else(|| DatadogTraceStateBuilder::default() - .with_priority_sampling(true) // always sample root span(span without remote or local parent) - .with_measuring(true) // datadog-agent will create metric for this span for APM - .build() - ); + .unwrap_or_else(|| { + DatadogTraceStateBuilder::default() + .with_priority_sampling(true) // always sample root span(span without remote or local parent) + .with_measuring(true) // datadog-agent will create metric for this span for APM + .build() + }); SamplingResult { decision: opentelemetry::trace::SamplingDecision::RecordAndSample, // send all spans to datadog-agent @@ -55,7 +56,7 @@ fn main() -> Result<(), Box> { .with_trace_config( trace::config() .with_sampler(AgentBasedSampler) - .with_id_generator(RandomIdGenerator::default()) + .with_id_generator(RandomIdGenerator::default()), ) .install_simple()?; diff --git a/opentelemetry-datadog/src/exporter/model/v05.rs b/opentelemetry-datadog/src/exporter/model/v05.rs index b907f8f6..9a0decaf 100644 --- a/opentelemetry-datadog/src/exporter/model/v05.rs +++ b/opentelemetry-datadog/src/exporter/model/v05.rs @@ -1,8 +1,5 @@ use crate::exporter::intern::StringInterner; -use crate::exporter::model::{ - DD_MEASURED_KEY, - SAMPLING_PRIORITY_KEY, -}; +use crate::exporter::model::{DD_MEASURED_KEY, SAMPLING_PRIORITY_KEY}; use crate::exporter::{Error, ModelConfig}; use crate::propagator::DatadogTraceState; use opentelemetry::trace::Status; @@ -12,7 +9,7 @@ use std::time::SystemTime; use super::unified_tags::{UnifiedTagField, UnifiedTags}; const SPAN_NUM_ELEMENTS: u32 = 12; -const METRICS_LEN : u32 = 2; +const METRICS_LEN: u32 = 2; const GIT_META_TAGS_COUNT: u32 = if matches!( ( option_env!("DD_GIT_REPOSITORY_URL"), diff --git a/opentelemetry-datadog/src/lib.rs b/opentelemetry-datadog/src/lib.rs index 2d3aa97a..5f0d1810 100644 --- a/opentelemetry-datadog/src/lib.rs +++ b/opentelemetry-datadog/src/lib.rs @@ -140,11 +140,7 @@ pub use exporter::{ new_pipeline, ApiVersion, DatadogExporter, DatadogPipelineBuilder, Error, FieldMappingFn, ModelConfig, }; -pub use propagator::{ - DatadogPropagator, - DatadogTraceState, - DatadogTraceStateBuilder, -}; +pub use propagator::{DatadogPropagator, DatadogTraceState, DatadogTraceStateBuilder}; mod propagator { use once_cell::sync::Lazy; @@ -181,7 +177,11 @@ mod propagator { } fn boolean_to_trace_state_flag(value: bool) -> &'static str { - if value { TRACE_STATE_TRUE_VALUE } else { TRACE_STATE_FALSE_VALUE } + if value { + TRACE_STATE_TRUE_VALUE + } else { + TRACE_STATE_FALSE_VALUE + } } fn trace_flag_to_boolean(value: &str) -> bool { @@ -206,11 +206,20 @@ mod propagator { pub fn build(self) -> TraceState { #[cfg(not(feature = "agent-sampling"))] - let values = [(TRACE_STATE_MEASURE, boolean_to_trace_state_flag(self.measuring))]; + let values = [( + TRACE_STATE_MEASURE, + boolean_to_trace_state_flag(self.measuring), + )]; #[cfg(feature = "agent-sampling")] let values = [ - (TRACE_STATE_MEASURE, boolean_to_trace_state_flag(self.measuring)), - (TRACE_STATE_PRIORITY_SAMPLING, boolean_to_trace_state_flag(self.priority_sampling)), + ( + TRACE_STATE_MEASURE, + boolean_to_trace_state_flag(self.measuring), + ), + ( + TRACE_STATE_PRIORITY_SAMPLING, + boolean_to_trace_state_flag(self.priority_sampling), + ), ]; TraceState::from_key_value(values).unwrap_or_default() @@ -243,8 +252,11 @@ mod propagator { #[cfg(feature = "agent-sampling")] fn with_priority_sampling(&self, enabled: bool) -> TraceState { - self.insert(TRACE_STATE_PRIORITY_SAMPLING, boolean_to_trace_state_flag(enabled)) - .unwrap_or_else(|_err| self.clone()) + self.insert( + TRACE_STATE_PRIORITY_SAMPLING, + boolean_to_trace_state_flag(enabled), + ) + .unwrap_or_else(|_err| self.clone()) } #[cfg(feature = "agent-sampling")] @@ -299,7 +311,12 @@ mod propagator { if trace_flags & TRACE_FLAG_DEFERRED == TRACE_FLAG_DEFERRED { (TraceState::default(), trace_flags) } else { - (DatadogTraceStateBuilder::default().with_priority_sampling(trace_flags.is_sampled()).build(), TraceFlags::SAMPLED) + ( + DatadogTraceStateBuilder::default() + .with_priority_sampling(trace_flags.is_sampled()) + .build(), + TraceFlags::SAMPLED, + ) } } @@ -385,14 +402,12 @@ mod propagator { SamplingPriority::AutoKeep } else { SamplingPriority::AutoReject - } + } } #[cfg(feature = "agent-sampling")] fn get_sampling_priority(span_context: &SpanContext) -> SamplingPriority { - if span_context - .trace_state() - .priority_sampling_enabled() { + if span_context.trace_state().priority_sampling_enabled() { SamplingPriority::AutoKeep } else { SamplingPriority::AutoReject From ee83e24fc62f214634e15f7c28c8ec3119bb95c6 Mon Sep 17 00:00:00 2001 From: Hartigan Date: Sat, 16 Mar 2024 17:34:41 +0100 Subject: [PATCH 10/10] Clippy: 'cargo clippy --all-targets --all-features' for opentelemetry-datadog --- opentelemetry-datadog/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-datadog/src/lib.rs b/opentelemetry-datadog/src/lib.rs index 5f0d1810..371475c2 100644 --- a/opentelemetry-datadog/src/lib.rs +++ b/opentelemetry-datadog/src/lib.rs @@ -429,7 +429,7 @@ mod propagator { ); if span_context.trace_flags() & TRACE_FLAG_DEFERRED != TRACE_FLAG_DEFERRED { - let sampling_priority = get_sampling_priority(&span_context); + let sampling_priority = get_sampling_priority(span_context); injector.set( DATADOG_SAMPLING_PRIORITY_HEADER,