Skip to content

Commit f4c85cc

Browse files
committed
feat(traces): migrate trace propagation to dd-trace-rs
Replace local trace extraction/propagation implementation with datadog-opentelemetry crate from dd-trace-rs. This removes maintenance burden for Datadog/TraceContext propagator logic. - Add datadog-opentelemetry dependency - Remove local propagation modules (context, error, text_map_propagator) - Use DatadogCompositePropagator from dd-trace-rs with thin wrapper for ot-baggage-* header extraction (not yet supported upstream) - Update all consumers to import directly from datadog-opentelemetry - Adapt to u128 trace_id, Sampling struct, SamplingPriority types
1 parent 7b86bfc commit f4c85cc

20 files changed

Lines changed: 829 additions & 1572 deletions

bottlecap/Cargo.lock

Lines changed: 602 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bottlecap/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ libdd-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "c812
7676
libdd-trace-normalization = { git = "https://github.com/DataDog/libdatadog", rev = "c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09" }
7777
libdd-trace-obfuscation = { git = "https://github.com/DataDog/libdatadog", rev = "c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09" }
7878
libdd-trace-stats = { git = "https://github.com/DataDog/libdatadog", rev = "c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09" }
79+
datadog-opentelemetry = { git = "https://github.com/DataDog/dd-trace-rs", rev = "d5b07ee235f169d166d5f7f7f749444ad36d5fe8", default-features = false }
7980
dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "28f796bf767fff56caf08153ade5cd80c8e8f705", default-features = false }
8081
datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "28f796bf767fff56caf08153ade5cd80c8e8f705", default-features = false }
8182
libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] }

bottlecap/src/config/env.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ use crate::{
2424
},
2525
processing_rule::{ProcessingRule, deserialize_processing_rules},
2626
service_mapping::deserialize_service_mapping,
27-
trace_propagation_style::{TracePropagationStyle, deserialize_trace_propagation_style},
27+
trace_propagation_style::deserialize_trace_propagation_style,
2828
},
2929
merge_hashmap, merge_option, merge_option_to_value, merge_string, merge_vec,
3030
};
31+
use datadog_opentelemetry::propagation::TracePropagationStyle;
3132

3233
#[derive(Debug, PartialEq, Deserialize, Clone, Default)]
3334
#[serde(default)]
@@ -719,8 +720,8 @@ mod tests {
719720
flush_strategy::{FlushStrategy, PeriodicStrategy},
720721
log_level::LogLevel,
721722
processing_rule::{Kind, ProcessingRule},
722-
trace_propagation_style::TracePropagationStyle,
723723
};
724+
use datadog_opentelemetry::propagation::TracePropagationStyle;
724725

725726
#[test]
726727
#[allow(clippy::too_many_lines)]
@@ -802,7 +803,7 @@ mod tests {
802803
jail.set_env("DD_METRICS_CONFIG_COMPRESSION_LEVEL", "3");
803804
// Trace Propagation
804805
jail.set_env("DD_TRACE_PROPAGATION_STYLE", "datadog");
805-
jail.set_env("DD_TRACE_PROPAGATION_STYLE_EXTRACT", "b3");
806+
jail.set_env("DD_TRACE_PROPAGATION_STYLE_EXTRACT", "tracecontext");
806807
jail.set_env("DD_TRACE_PROPAGATION_EXTRACT_FIRST", "true");
807808
jail.set_env("DD_TRACE_PROPAGATION_HTTP_BAGGAGE_ENABLED", "true");
808809
jail.set_env("DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED", "true");
@@ -984,7 +985,7 @@ mod tests {
984985
"debug:^true$".to_string(),
985986
]),
986987
trace_propagation_style: vec![TracePropagationStyle::Datadog],
987-
trace_propagation_style_extract: vec![TracePropagationStyle::B3],
988+
trace_propagation_style_extract: vec![TracePropagationStyle::TraceContext],
988989
trace_propagation_extract_first: true,
989990
trace_propagation_http_baggage_enabled: true,
990991
trace_aws_service_representation_enabled: true,

bottlecap/src/config/mod.rs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ use crate::config::{
2929
log_level::LogLevel,
3030
logs_additional_endpoints::LogsAdditionalEndpoint,
3131
processing_rule::{ProcessingRule, deserialize_processing_rules},
32-
trace_propagation_style::TracePropagationStyle,
3332
yaml::YamlConfigSource,
3433
};
34+
use datadog_opentelemetry::propagation::TracePropagationStyle;
3535

3636
/// Helper macro to merge Option<String> fields to String fields
3737
///
@@ -488,6 +488,38 @@ impl Default for Config {
488488
}
489489
}
490490

491+
impl datadog_opentelemetry::propagation::PropagationConfig for Config {
492+
fn trace_propagation_style(&self) -> Option<&[TracePropagationStyle]> {
493+
if self.trace_propagation_style.is_empty() {
494+
None
495+
} else {
496+
Some(&self.trace_propagation_style)
497+
}
498+
}
499+
500+
fn trace_propagation_style_extract(&self) -> Option<&[TracePropagationStyle]> {
501+
if self.trace_propagation_style_extract.is_empty() {
502+
None
503+
} else {
504+
Some(&self.trace_propagation_style_extract)
505+
}
506+
}
507+
508+
fn trace_propagation_style_inject(&self) -> Option<&[TracePropagationStyle]> {
509+
// Bottlecap does not configure injection styles separately
510+
None
511+
}
512+
513+
fn trace_propagation_extract_first(&self) -> bool {
514+
self.trace_propagation_extract_first
515+
}
516+
517+
fn datadog_tags_max_length(&self) -> usize {
518+
// Default max length matching dd-trace-rs
519+
512
520+
}
521+
}
522+
491523
#[allow(clippy::module_name_repetitions)]
492524
#[inline]
493525
#[must_use]
@@ -819,8 +851,8 @@ pub mod tests {
819851
flush_strategy::{FlushStrategy, PeriodicStrategy},
820852
log_level::LogLevel,
821853
processing_rule::ProcessingRule,
822-
trace_propagation_style::TracePropagationStyle,
823854
};
855+
use datadog_opentelemetry::propagation::TracePropagationStyle;
824856

825857
#[test]
826858
fn test_default_logs_intake_url() {
@@ -1301,15 +1333,13 @@ pub mod tests {
13011333
jail.clear_env();
13021334
jail.set_env(
13031335
"DD_TRACE_PROPAGATION_STYLE",
1304-
"datadog,tracecontext,b3,b3multi",
1336+
"datadog,tracecontext",
13051337
);
13061338
let config = get_config(Path::new(""));
13071339

13081340
let expected_styles = vec![
13091341
TracePropagationStyle::Datadog,
13101342
TracePropagationStyle::TraceContext,
1311-
TracePropagationStyle::B3,
1312-
TracePropagationStyle::B3Multi,
13131343
];
13141344
assert_eq!(config.trace_propagation_style, expected_styles);
13151345
assert_eq!(config.trace_propagation_style_extract, expected_styles);

bottlecap/src/config/trace_propagation_style.rs

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,9 @@
1-
use std::{fmt::Display, str::FromStr};
1+
use std::str::FromStr;
22

3+
use datadog_opentelemetry::propagation::TracePropagationStyle;
34
use serde::{Deserialize, Deserializer};
45
use tracing::error;
56

6-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7-
pub enum TracePropagationStyle {
8-
Datadog,
9-
B3Multi,
10-
B3,
11-
TraceContext,
12-
None,
13-
}
14-
15-
impl FromStr for TracePropagationStyle {
16-
type Err = String;
17-
18-
fn from_str(s: &str) -> Result<Self, Self::Err> {
19-
match s.to_lowercase().as_str() {
20-
"datadog" => Ok(TracePropagationStyle::Datadog),
21-
"b3multi" => Ok(TracePropagationStyle::B3Multi),
22-
"b3" => Ok(TracePropagationStyle::B3),
23-
"tracecontext" => Ok(TracePropagationStyle::TraceContext),
24-
"none" => Ok(TracePropagationStyle::None),
25-
_ => {
26-
error!("Trace propagation style is invalid: {:?}, using None", s);
27-
Ok(TracePropagationStyle::None)
28-
}
29-
}
30-
}
31-
}
32-
33-
impl Display for TracePropagationStyle {
34-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35-
let style = match self {
36-
TracePropagationStyle::Datadog => "datadog",
37-
TracePropagationStyle::B3Multi => "b3multi",
38-
TracePropagationStyle::B3 => "b3",
39-
TracePropagationStyle::TraceContext => "tracecontext",
40-
TracePropagationStyle::None => "none",
41-
};
42-
write!(f, "{style}")
43-
}
44-
}
45-
467
#[allow(clippy::module_name_repetitions)]
478
pub fn deserialize_trace_propagation_style<'de, D>(
489
deserializer: D,
@@ -57,7 +18,7 @@ where
5718
|style| match TracePropagationStyle::from_str(style.trim()) {
5819
Ok(parsed_style) => Some(parsed_style),
5920
Err(e) => {
60-
tracing::error!("Failed to parse trace propagation style: {}, ignoring", e);
21+
error!("Failed to parse trace propagation style: {}, ignoring", e);
6122
None
6223
}
6324
},

bottlecap/src/config/yaml.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::time::Duration;
22
use std::{collections::HashMap, path::PathBuf};
33

4+
use datadog_opentelemetry::propagation::TracePropagationStyle;
5+
46
use crate::{
57
config::{
68
Config, ConfigError, ConfigSource, ProcessingRule,
@@ -15,7 +17,7 @@ use crate::{
1517
log_level::LogLevel,
1618
logs_additional_endpoints::LogsAdditionalEndpoint,
1719
service_mapping::deserialize_service_mapping,
18-
trace_propagation_style::{TracePropagationStyle, deserialize_trace_propagation_style},
20+
trace_propagation_style::deserialize_trace_propagation_style,
1921
},
2022
merge_hashmap, merge_option, merge_option_to_value, merge_string, merge_vec,
2123
};
@@ -826,7 +828,7 @@ service_mapping: old-service:new-service
826828
827829
# Trace Propagation
828830
trace_propagation_style: "datadog"
829-
trace_propagation_style_extract: "b3"
831+
trace_propagation_style_extract: "tracecontext"
830832
trace_propagation_extract_first: true
831833
trace_propagation_http_baggage_enabled: true
832834
trace_aws_service_representation_enabled: true
@@ -972,7 +974,7 @@ api_security_sample_delay: 60 # Seconds
972974
),
973975
]),
974976
trace_propagation_style: vec![TracePropagationStyle::Datadog],
975-
trace_propagation_style_extract: vec![TracePropagationStyle::B3],
977+
trace_propagation_style_extract: vec![TracePropagationStyle::TraceContext],
976978
trace_propagation_extract_first: true,
977979
trace_propagation_http_baggage_enabled: true,
978980
trace_aws_service_representation_enabled: true,

bottlecap/src/lifecycle/invocation/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
lifecycle::invocation::processor::MS_TO_NS, metrics::enhanced::lambda::EnhancedMetricData,
3-
traces::context::SpanContext,
43
};
4+
use datadog_opentelemetry::propagation::context::SpanContext;
55
use std::{
66
collections::{HashMap, VecDeque},
77
time::{SystemTime, UNIX_EPOCH},

bottlecap/src/lifecycle/invocation/processor.rs

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ use std::{
55
};
66

77
use chrono::{DateTime, Utc};
8+
use datadog_opentelemetry::propagation::{
9+
context::SpanContext,
10+
datadog::{
11+
DATADOG_PARENT_ID_KEY, DATADOG_SAMPLING_PRIORITY_KEY, DATADOG_TAGS_KEY,
12+
DATADOG_TRACE_ID_KEY,
13+
},
14+
};
815
use libdd_trace_protobuf::pb::Span;
916
use libdd_trace_utils::tracer_header_tags;
1017
use serde_json::Value;
@@ -31,14 +38,7 @@ use crate::{
3138
},
3239
tags::{lambda::tags::resolve_runtime_from_proc, provider},
3340
traces::{
34-
context::SpanContext,
35-
propagation::{
36-
DatadogCompositePropagator, Propagator,
37-
text_map_propagator::{
38-
DATADOG_PARENT_ID_KEY, DATADOG_SAMPLING_PRIORITY_KEY, DATADOG_SPAN_ID_KEY,
39-
DATADOG_TRACE_ID_KEY, DatadogHeaderPropagator,
40-
},
41-
},
41+
propagation::{DatadogCompositePropagator, carrier::JsonCarrier},
4242
trace_processor::SendingTraceProcessor,
4343
},
4444
};
@@ -52,6 +52,7 @@ pub const DATADOG_INVOCATION_ERROR_MESSAGE_KEY: &str = "x-datadog-invocation-err
5252
pub const DATADOG_INVOCATION_ERROR_TYPE_KEY: &str = "x-datadog-invocation-error-type";
5353
pub const DATADOG_INVOCATION_ERROR_STACK_KEY: &str = "x-datadog-invocation-error-stack";
5454
pub const DATADOG_INVOCATION_ERROR_KEY: &str = "x-datadog-invocation-error";
55+
const DATADOG_SPAN_ID_KEY: &str = "x-datadog-span-id";
5556
const TAG_SAMPLING_PRIORITY: &str = "_sampling_priority_v1";
5657

5758
pub struct Processor {
@@ -979,7 +980,7 @@ impl Processor {
979980

980981
// Set the extracted trace context to the spans
981982
if let Some(sc) = &context.extracted_span_context {
982-
context.invocation_span.trace_id = sc.trace_id;
983+
context.invocation_span.trace_id = sc.trace_id as u64;
983984
context.invocation_span.parent_id = sc.span_id;
984985

985986
// Set the right data to the correct root level span,
@@ -1082,7 +1083,7 @@ impl Processor {
10821083
pub fn extract_span_context(
10831084
headers: &HashMap<String, String>,
10841085
payload_value: &Value,
1085-
propagator: Arc<impl Propagator>,
1086+
propagator: Arc<DatadogCompositePropagator>,
10861087
) -> Option<SpanContext> {
10871088
if let Some(sc) =
10881089
span_inferrer::extract_span_context(payload_value, Arc::clone(&propagator))
@@ -1093,14 +1094,14 @@ impl Processor {
10931094
if let Some(sc) = payload_value
10941095
.get("request")
10951096
.and_then(|req| req.get("headers"))
1096-
.and_then(|headers| propagator.extract(headers))
1097+
.and_then(|headers| propagator.extract(&JsonCarrier(headers)))
10971098
{
10981099
debug!("Extracted trace context from event.request.headers");
10991100
return Some(sc);
11001101
}
11011102

11021103
if let Some(payload_headers) = payload_value.get("headers")
1103-
&& let Some(sc) = propagator.extract(payload_headers)
1104+
&& let Some(sc) = propagator.extract(&JsonCarrier(payload_headers))
11041105
{
11051106
debug!("Extracted trace context from event headers");
11061107
return Some(sc);
@@ -1202,14 +1203,14 @@ impl Processor {
12021203
self.inferrer.set_status_code(status_code_as_string);
12031204
}
12041205

1205-
let mut trace_id = 0;
1206-
let mut parent_id = 0;
1206+
let mut trace_id: u64 = 0;
1207+
let mut parent_id: u64 = 0;
12071208
let mut tags: HashMap<String, String> = HashMap::new();
12081209

12091210
// If we have a trace context, this means we got it from
12101211
// distributed tracing
12111212
if let Some(sc) = &context.extracted_span_context {
1212-
trace_id = sc.trace_id;
1213+
trace_id = sc.trace_id as u64;
12131214
parent_id = sc.span_id;
12141215
tags.extend(sc.tags.clone());
12151216
}
@@ -1235,9 +1236,8 @@ impl Processor {
12351236
.insert(TAG_SAMPLING_PRIORITY.to_string(), priority);
12361237
}
12371238

1238-
// Extract tags from headers
1239-
// Used for 128 bit trace ids
1240-
tags = DatadogHeaderPropagator::extract_tags(&headers);
1239+
// Extract _dd.p.* propagation tags from x-datadog-tags header
1240+
tags = extract_propagation_tags(&headers);
12411241
}
12421242

12431243
// We should always use the generated span id from the tracer
@@ -1344,6 +1344,21 @@ impl Processor {
13441344
}
13451345
}
13461346

1347+
fn extract_propagation_tags(carrier: &HashMap<String, String>) -> HashMap<String, String> {
1348+
let carrier_tags = carrier.get(DATADOG_TAGS_KEY).map_or("", String::as_str);
1349+
carrier_tags
1350+
.split(',')
1351+
.filter_map(|pair| {
1352+
let (k, v) = pair.split_once('=')?;
1353+
if k.starts_with("_dd.p.") {
1354+
Some((k.to_string(), v.to_string()))
1355+
} else {
1356+
None
1357+
}
1358+
})
1359+
.collect()
1360+
}
1361+
13471362
#[cfg(test)]
13481363
#[allow(clippy::unwrap_used)]
13491364
mod tests {
@@ -2048,8 +2063,8 @@ mod tests {
20482063
fn test_extract_span_context_priority_order() {
20492064
let config = Arc::new(config::Config {
20502065
trace_propagation_style_extract: vec![
2051-
config::trace_propagation_style::TracePropagationStyle::Datadog,
2052-
config::trace_propagation_style::TracePropagationStyle::TraceContext,
2066+
datadog_opentelemetry::propagation::TracePropagationStyle::Datadog,
2067+
datadog_opentelemetry::propagation::TracePropagationStyle::TraceContext,
20532068
],
20542069
..config::Config::default()
20552070
});
@@ -2086,8 +2101,8 @@ mod tests {
20862101
fn test_extract_span_context_no_request_headers() {
20872102
let config = Arc::new(config::Config {
20882103
trace_propagation_style_extract: vec![
2089-
config::trace_propagation_style::TracePropagationStyle::Datadog,
2090-
config::trace_propagation_style::TracePropagationStyle::TraceContext,
2104+
datadog_opentelemetry::propagation::TracePropagationStyle::Datadog,
2105+
datadog_opentelemetry::propagation::TracePropagationStyle::TraceContext,
20912106
],
20922107
..config::Config::default()
20932108
});

bottlecap/src/lifecycle/invocation/processor_service.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{collections::HashMap, sync::Arc};
22

33
use chrono::{DateTime, Utc};
4+
use datadog_opentelemetry::propagation::context::SpanContext;
45
use dogstatsd::aggregator::AggregatorHandle;
56
use libdd_trace_protobuf::pb::Span;
67
use serde_json::Value;
@@ -19,7 +20,7 @@ use crate::{
1920
},
2021
tags::provider,
2122
traces::{
22-
context::SpanContext, propagation::DatadogCompositePropagator,
23+
propagation::DatadogCompositePropagator,
2324
trace_processor::SendingTraceProcessor,
2425
},
2526
};

0 commit comments

Comments
 (0)