use std::{collections::HashMap, env, ffi::OsString, iter::IntoIterator};
use opentelemetry::propagation::Extractor;
pub(crate) struct EnvExtractor {
extracted: HashMap<String, String>,
}
impl EnvExtractor {
pub(crate) fn from_env() -> Self {
Self::from_iter(env::vars_os())
}
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = (OsString, OsString)>,
{
let mut extracted = HashMap::new();
for (var, value) in iter.into_iter() {
if let (Some(var), Some(value)) = (var.to_str(), value.to_str()) {
if var == "TRACEPARENT" || var == "TRACESTATE" {
extracted.insert(var.to_ascii_lowercase(), value.to_owned());
}
}
}
Self { extracted }
}
}
impl Extractor for EnvExtractor {
fn get(&self, key: &str) -> Option<&str> {
self.extracted.get(key).map(|v| &v[..])
}
fn keys(&self) -> Vec<&str> {
self.extracted.keys().map(|v| &v[..]).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_standard_headers() {
let traceparent_var = OsString::from("TRACEPARENT");
let traceparent_val =
OsString::from("00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01");
let other_var = OsString::from("OTHER");
let other_val = OsString::from("VALUE");
let fake_env =
vec![(traceparent_var, traceparent_val), (other_var, other_val)];
let extractor = EnvExtractor::from_iter(fake_env);
assert_eq!(
extractor.get("traceparent"),
Some("00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01")
);
assert_eq!(extractor.get("other"), None);
assert_eq!(extractor.keys(), vec!["traceparent"]);
}
}