Skip to content

Commit 00a376c

Browse files
committed
Merge remote-tracking branch 'origin/duncan-harvey/trace-stats-peer-tags-ip-quantization' into oscarld/integrate-obfuscation-to-trace-exporter
2 parents b2d3804 + e0cd5f3 commit 00a376c

2 files changed

Lines changed: 85 additions & 17 deletions

File tree

libdd-trace-stats/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ libdd-common = { version = "4.0.0", path = "../libdd-common", default-features =
1717
libdd-ddsketch = { version = "1.0.1", path = "../libdd-ddsketch" }
1818
libdd-shared-runtime = { version = "0.1.0", path = "../libdd-shared-runtime" }
1919
libdd-trace-protobuf = { version = "3.0.1", path = "../libdd-trace-protobuf" }
20-
libdd-trace-obfuscation = { version = "2.0.0", path = "../libdd-trace-obfuscation", optional = true }
20+
libdd-trace-obfuscation = { version = "2.0.0", path = "../libdd-trace-obfuscation", default-features = false, optional = true }
2121
libdd-trace-utils = { version = "3.0.1", path = "../libdd-trace-utils", default-features = false }
2222
hashbrown = { version = "0.15" }
2323
http = "1.1"

libdd-trace-stats/src/span_concentrator/aggregation.rs

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//! span.
77
88
use hashbrown::HashMap;
9+
use libdd_trace_obfuscation::ip_address::quantize_peer_ip_addresses;
910
use libdd_trace_protobuf::pb;
1011
use libdd_trace_utils::span::SpanText;
1112
use std::borrow::Borrow;
@@ -79,19 +80,13 @@ impl<T> FixedAggregationKey<T> {
7980
/// Represent a stats aggregation key borrowed from span data
8081
pub(super) struct BorrowedAggregationKey<'a> {
8182
fixed: FixedAggregationKey<&'a str>,
82-
peer_tags: Vec<(&'a str, &'a str)>,
83+
peer_tags: Vec<(String, String)>,
8384
}
8485

8586
impl hashbrown::Equivalent<OwnedAggregationKey> for BorrowedAggregationKey<'_> {
8687
#[inline]
8788
fn equivalent(&self, other: &OwnedAggregationKey) -> bool {
88-
self.fixed == other.fixed.convert(|s| s)
89-
&& self.peer_tags.len() == other.peer_tags.len()
90-
&& self
91-
.peer_tags
92-
.iter()
93-
.zip(other.peer_tags.iter())
94-
.all(|((k1, v1), (k2, v2))| k1 == k2 && v1 == v2)
89+
self.fixed == other.fixed.convert(|s| s) && self.peer_tags == other.peer_tags
9590
}
9691
}
9792

@@ -112,11 +107,7 @@ impl From<&BorrowedAggregationKey<'_>> for OwnedAggregationKey {
112107
fn from(value: &BorrowedAggregationKey<'_>) -> Self {
113108
OwnedAggregationKey {
114109
fixed: value.fixed.convert(str::to_owned),
115-
peer_tags: value
116-
.peer_tags
117-
.iter()
118-
.map(|(k, v)| (k.to_string(), v.to_string()))
119-
.collect(),
110+
peer_tags: value.peer_tags.clone(),
120111
}
121112
}
122113
}
@@ -218,14 +209,17 @@ impl<'a> BorrowedAggregationKey<'a> {
218209
let span_kind = span.get_meta(TAG_SPANKIND).unwrap_or_default();
219210
let peer_tags = if should_track_peer_tags(span_kind) {
220211
// Parse the meta tags of the span and return a list of the peer tags based on the list
221-
// of `peer_tag_keys`
212+
// of `peer_tag_keys`. IP address values are quantized to reduce cardinality.
222213
peer_tag_keys
223214
.iter()
224-
.filter_map(|key| Some(((key.as_str()), (span.get_meta(key.as_str())?))))
215+
.filter_map(|key| {
216+
let value = span.get_meta(key.as_str())?;
217+
Some((key.clone(), quantize_peer_ip_addresses(value).into_owned()))
218+
})
225219
.collect()
226220
} else if let Some(base_service) = span.get_meta("_dd.base_service") {
227221
// Internal spans with a base service override use only _dd.base_service as peer tag
228-
vec![("_dd.base_service", base_service)]
222+
vec![("_dd.base_service".to_string(), base_service.to_string())]
229223
} else {
230224
vec![]
231225
};
@@ -974,6 +968,80 @@ mod tests {
974968
}
975969
}
976970

971+
#[test]
972+
fn test_peer_tag_ip_quantization_in_aggregation_key() {
973+
let peer_tag_keys = vec!["peer.hostname".to_string(), "db.instance".to_string()];
974+
975+
// IPv4 address peer tag gets replaced with blocked-ip-address
976+
let span_ipv4 = SpanSlice {
977+
service: "service",
978+
name: "op",
979+
resource: "res",
980+
span_id: 1,
981+
parent_id: 0,
982+
meta: HashMap::from([
983+
("span.kind", "client"),
984+
("peer.hostname", "10.1.2.3"),
985+
("db.instance", "my-db"),
986+
]),
987+
..Default::default()
988+
};
989+
let key = BorrowedAggregationKey::from_span(&span_ipv4, &peer_tag_keys);
990+
let owned = OwnedAggregationKey::from(&key);
991+
assert_eq!(
992+
owned.peer_tags,
993+
vec![
994+
(
995+
"peer.hostname".to_string(),
996+
"blocked-ip-address".to_string()
997+
),
998+
("db.instance".to_string(), "my-db".to_string()),
999+
]
1000+
);
1001+
1002+
// IPv6 address peer tag gets replaced with blocked-ip-address
1003+
let span_ipv6 = SpanSlice {
1004+
service: "service",
1005+
name: "op",
1006+
resource: "res",
1007+
span_id: 1,
1008+
parent_id: 0,
1009+
meta: HashMap::from([
1010+
("span.kind", "client"),
1011+
("peer.hostname", "2001:db8:3333:4444:CCCC:DDDD:EEEE:FFFF"),
1012+
]),
1013+
..Default::default()
1014+
};
1015+
let ipv6_keys = vec!["peer.hostname".to_string()];
1016+
let key = BorrowedAggregationKey::from_span(&span_ipv6, &ipv6_keys);
1017+
let owned = OwnedAggregationKey::from(&key);
1018+
assert_eq!(
1019+
owned.peer_tags,
1020+
vec![(
1021+
"peer.hostname".to_string(),
1022+
"blocked-ip-address".to_string()
1023+
)]
1024+
);
1025+
1026+
// Non-IP peer tags pass through unchanged
1027+
let span_non_ip = SpanSlice {
1028+
service: "service",
1029+
name: "op",
1030+
resource: "res",
1031+
span_id: 1,
1032+
parent_id: 0,
1033+
meta: HashMap::from([("span.kind", "client"), ("db.instance", "dynamo.test.us1")]),
1034+
..Default::default()
1035+
};
1036+
let non_ip_keys = vec!["db.instance".to_string()];
1037+
let key = BorrowedAggregationKey::from_span(&span_non_ip, &non_ip_keys);
1038+
let owned = OwnedAggregationKey::from(&key);
1039+
assert_eq!(
1040+
owned.peer_tags,
1041+
vec![("db.instance".to_string(), "dynamo.test.us1".to_string())]
1042+
);
1043+
}
1044+
9771045
#[test]
9781046
fn test_grpc_status_str_to_int_value() {
9791047
// Numeric strings parse directly

0 commit comments

Comments
 (0)