Skip to content

Commit eaca267

Browse files
iunanuacijothomas
andauthored
feat: support multi-value key propagation extraction (#3008)
Co-authored-by: Cijo Thomas <[email protected]>
1 parent 7b3db0b commit eaca267

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

opentelemetry-http/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## vNext
44

5+
- Implementation of `Extractor::get_all` for `HeaderExtractor`
6+
57
## 0.30.0
68

79
Released 2025-May-23

opentelemetry-http/src/lib.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ impl Extractor for HeaderExtractor<'_> {
4343
.map(|value| value.as_str())
4444
.collect::<Vec<_>>()
4545
}
46+
47+
/// Get all the values for a key from the HeaderMap
48+
fn get_all(&self, key: &str) -> Option<Vec<&str>> {
49+
let all_iter = self.0.get_all(key).iter();
50+
if let (0, Some(0)) = all_iter.size_hint() {
51+
return None;
52+
}
53+
54+
Some(all_iter.filter_map(|value| value.to_str().ok()).collect())
55+
}
4656
}
4757

4858
pub type HttpError = Box<dyn std::error::Error + Send + Sync + 'static>;
@@ -236,6 +246,8 @@ impl<T> ResponseExt for Response<T> {
236246

237247
#[cfg(test)]
238248
mod tests {
249+
use http::HeaderValue;
250+
239251
use super::*;
240252

241253
#[test]
@@ -250,6 +262,32 @@ mod tests {
250262
)
251263
}
252264

265+
#[test]
266+
fn http_headers_get_all() {
267+
let mut carrier = http::HeaderMap::new();
268+
carrier.append("headerName", HeaderValue::from_static("value"));
269+
carrier.append("headerName", HeaderValue::from_static("value2"));
270+
carrier.append("headerName", HeaderValue::from_static("value3"));
271+
272+
assert_eq!(
273+
HeaderExtractor(&carrier).get_all("HEADERNAME"),
274+
Some(vec!["value", "value2", "value3"]),
275+
"all values from a key extraction"
276+
)
277+
}
278+
279+
#[test]
280+
fn http_headers_get_all_missing_key() {
281+
let mut carrier = http::HeaderMap::new();
282+
carrier.append("headerName", HeaderValue::from_static("value"));
283+
284+
assert_eq!(
285+
HeaderExtractor(&carrier).get_all("not_existing"),
286+
None,
287+
"all values from a missing key extraction"
288+
)
289+
}
290+
253291
#[test]
254292
fn http_headers_keys() {
255293
let mut carrier = http::HeaderMap::new();

opentelemetry/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## vNext
44

5+
- Add `get_all` method to `opentelemetry::propagation::Extractor` to return all values of the given propagation key and provide a default implementation.
6+
57
## 0.30.0
68

79
Released 2025-May-23

opentelemetry/src/propagation/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ pub trait Extractor {
4040

4141
/// Collect all the keys from the underlying data.
4242
fn keys(&self) -> Vec<&str>;
43+
44+
/// Get all values from a key from the underlying data.
45+
fn get_all(&self, key: &str) -> Option<Vec<&str>> {
46+
self.get(key).map(|value| vec![value])
47+
}
4348
}
4449

4550
impl<S: std::hash::BuildHasher> Injector for HashMap<String, String, S> {
@@ -77,6 +82,30 @@ mod tests {
7782
);
7883
}
7984

85+
#[test]
86+
fn hash_map_get_all() {
87+
let mut carrier = HashMap::new();
88+
carrier.set("headerName", "value".to_string());
89+
90+
assert_eq!(
91+
Extractor::get_all(&carrier, "HEADERNAME"),
92+
Some(vec!["value"]),
93+
"case insensitive get_all extraction"
94+
);
95+
}
96+
97+
#[test]
98+
fn hash_map_get_all_missing_key() {
99+
let mut carrier = HashMap::new();
100+
carrier.set("headerName", "value".to_string());
101+
102+
assert_eq!(
103+
Extractor::get_all(&carrier, "missing_key"),
104+
None,
105+
"case insensitive get_all extraction"
106+
);
107+
}
108+
80109
#[test]
81110
fn hash_map_keys() {
82111
let mut carrier = HashMap::new();

0 commit comments

Comments
 (0)