Skip to content

Commit 94ec6bd

Browse files
authored
Adding Context implemenations for HeaderMap and MetadataMap (#115)
1 parent 13e5e37 commit 94ec6bd

File tree

13 files changed

+74
-80
lines changed

13 files changed

+74
-80
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ prometheus = { version = "0.7", optional = true }
2525
rand = { version = "0.7", optional = true }
2626
serde = { version = "1.0", features = ["derive", "rc"], optional = true }
2727
bincode = { version = "1.2", optional = true }
28+
http = { version = "0.2.1", optional = true }
29+
tonic = { version = "0.2.1", optional = true }
2830

2931
[dev-dependencies]
3032
criterion = "0.3.1"

examples/grpc/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ http = "0.2"
1616
tonic = "0.2"
1717
prost = "0.6"
1818
tokio = { version = "0.2", features = ["full"] }
19-
opentelemetry = { path = "../../" }
19+
opentelemetry = { path = "../../", features = ["tonic"] }
2020
opentelemetry-jaeger = { path = "../../opentelemetry-jaeger" }
2121

2222
[build-dependencies]

examples/grpc/src/client.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use opentelemetry::api::{
44
Context, HttpTextFormat, KeyValue, TraceContextExt, TraceContextPropagator, Tracer,
55
};
66
use opentelemetry::sdk::Sampler;
7-
use opentelemetry::{api, global, sdk};
7+
use opentelemetry::{global, sdk};
88

99
pub mod hello_world {
1010
tonic::include_proto!("helloworld");
@@ -36,22 +36,6 @@ fn tracing_init() -> Result<(), Box<dyn std::error::Error>> {
3636
Ok(())
3737
}
3838

39-
struct TonicMetadataMapCarrier<'a>(&'a mut tonic::metadata::MetadataMap);
40-
impl<'a> api::Carrier for TonicMetadataMapCarrier<'a> {
41-
fn get(&self, key: &'static str) -> Option<&str> {
42-
self.0.get(key).and_then(|metadata| metadata.to_str().ok())
43-
}
44-
45-
fn set(&mut self, key: &'static str, value: String) {
46-
if let Ok(key) = tonic::metadata::MetadataKey::from_bytes(key.to_lowercase().as_bytes()) {
47-
self.0.insert(
48-
key,
49-
tonic::metadata::MetadataValue::from_str(&value).unwrap(),
50-
);
51-
}
52-
}
53-
}
54-
5539
#[tokio::main]
5640
async fn main() -> Result<(), Box<dyn std::error::Error>> {
5741
tracing_init()?;
@@ -63,7 +47,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
6347
let mut request = tonic::Request::new(HelloRequest {
6448
name: "Tonic".into(),
6549
});
66-
propagator.inject_context(&cx, &mut TonicMetadataMapCarrier(request.metadata_mut()));
50+
propagator.inject_context(&cx, request.metadata_mut());
6751

6852
let response = client.say_hello(request).await?;
6953

examples/grpc/src/server.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use opentelemetry::global;
77
use opentelemetry::sdk::{self, Sampler};
88

99
pub mod hello_world {
10-
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name
10+
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name.
1111
}
1212

1313
#[derive(Debug, Default)]
@@ -20,7 +20,7 @@ impl Greeter for MyGreeter {
2020
request: Request<HelloRequest>, // Accept request of type HelloRequest
2121
) -> Result<Response<HelloReply>, Status> {
2222
let propagator = api::TraceContextPropagator::new();
23-
let parent_cx = propagator.extract(&HttpHeaderMapCarrier(request.metadata()));
23+
let parent_cx = propagator.extract(request.metadata());
2424
let span = global::tracer("greeter").start_from_context("Processing reply", &parent_cx);
2525
span.set_attribute(KeyValue::new("request", format!("{:?}", request)));
2626

@@ -59,19 +59,6 @@ fn tracing_init() -> Result<(), Box<dyn std::error::Error>> {
5959
Ok(())
6060
}
6161

62-
struct HttpHeaderMapCarrier<'a>(&'a tonic::metadata::MetadataMap);
63-
impl<'a> api::Carrier for HttpHeaderMapCarrier<'a> {
64-
fn get(&self, key: &'static str) -> Option<&str> {
65-
self.0
66-
.get(key.to_lowercase().as_str())
67-
.and_then(|value| value.to_str().ok())
68-
}
69-
70-
fn set(&mut self, _key: &'static str, _value: String) {
71-
unimplemented!()
72-
}
73-
}
74-
7562
#[tokio::main]
7663
async fn main() -> Result<(), Box<dyn std::error::Error>> {
7764
tracing_init()?;

examples/http/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ path = "src/client.rs"
1414
[dependencies]
1515
hyper = "0.13"
1616
tokio = { version = "0.2", features = ["full"] }
17-
opentelemetry = { path = "../../" }
17+
opentelemetry = { path = "../../", features = ["http"] }
1818
opentelemetry-jaeger = { path = "../../opentelemetry-jaeger" }

examples/http/src/client.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,6 @@ use hyper::{body::Body, Client};
22
use opentelemetry::api::{Context, HttpTextFormat, TraceContextExt, Tracer};
33
use opentelemetry::{api, exporter::trace::stdout, global, sdk};
44

5-
struct ClientHeaderMapCarrier<'a>(&'a mut hyper::header::HeaderMap);
6-
impl<'a> api::Carrier for ClientHeaderMapCarrier<'a> {
7-
fn get(&self, key: &'static str) -> Option<&str> {
8-
self.0.get(key).and_then(|value| value.to_str().ok())
9-
}
10-
11-
fn set(&mut self, key: &'static str, value: String) {
12-
self.0.insert(key, value.parse().unwrap());
13-
}
14-
}
15-
165
fn init_tracer() {
176
// Create stdout exporter to be able to retrieve the collected spans.
187
let exporter = stdout::Builder::default().init();
@@ -40,7 +29,7 @@ async fn main() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sy
4029
let cx = Context::current_with_span(span);
4130

4231
let mut req = hyper::Request::builder().uri("http://127.0.0.1:3000");
43-
propagator.inject_context(&cx, &mut ClientHeaderMapCarrier(req.headers_mut().unwrap()));
32+
propagator.inject_context(&cx, req.headers_mut().unwrap());
4433
let res = client.request(req.body(Body::from("Hallo!"))?).await?;
4534

4635
cx.span().add_event(

examples/http/src/server.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,9 @@ use opentelemetry::{
77
};
88
use std::{convert::Infallible, net::SocketAddr};
99

10-
struct HttpHeaderMapCarrier<'a>(&'a hyper::header::HeaderMap);
11-
impl<'a> api::Carrier for HttpHeaderMapCarrier<'a> {
12-
fn get(&self, key: &'static str) -> Option<&str> {
13-
self.0.get(key).and_then(|value| value.to_str().ok())
14-
}
15-
16-
fn set(&mut self, _key: &'static str, _value: String) {
17-
unimplemented!()
18-
}
19-
}
20-
2110
async fn handle(req: Request<Body>) -> Result<Response<Body>, Infallible> {
2211
let propagator = api::TraceContextPropagator::new();
23-
let parent_cx = propagator.extract(&HttpHeaderMapCarrier(req.headers()));
12+
let parent_cx = propagator.extract(req.headers());
2413
let span = global::tracer("example/server").start_from_context("hello", &parent_cx);
2514
span.add_event("handling this...".to_string(), Vec::new());
2615

src/api/context/propagation/composite_propagator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ mod tests {
151151

152152
for (header_name, header_value) in test_data() {
153153
let mut carrier = HashMap::new();
154-
carrier.insert(header_name, header_value.to_string());
154+
carrier.insert(header_name.to_string(), header_value.to_string());
155155
assert_eq!(
156156
composite_propagator.extract(&carrier).remote_span_context(),
157157
Some(&SpanContext::new(

src/api/context/propagation/mod.rs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,19 +170,59 @@ pub mod text_propagator;
170170
/// underlying struct like `HashMap`.
171171
pub trait Carrier {
172172
/// Get a value for a key from the underlying data.
173-
fn get(&self, key: &'static str) -> Option<&str>;
173+
fn get(&self, key: &str) -> Option<&str>;
174174
/// Add a key and value to the underlying.
175-
fn set(&mut self, key: &'static str, value: String);
175+
fn set(&mut self, key: &str, value: String);
176176
}
177177

178-
impl<S: std::hash::BuildHasher> api::Carrier for HashMap<&'static str, String, S> {
178+
impl<S: std::hash::BuildHasher> api::Carrier for HashMap<String, String, S> {
179179
/// Get a value for a key from the HashMap.
180-
fn get(&self, key: &'static str) -> Option<&str> {
180+
fn get(&self, key: &str) -> Option<&str> {
181181
self.get(key).map(|v| v.as_str())
182182
}
183183

184184
/// Set a key and value in the HashMap.
185-
fn set(&mut self, key: &'static str, value: String) {
186-
self.insert(key, value);
185+
fn set(&mut self, key: &str, value: String) {
186+
self.insert(String::from(key), value);
187+
}
188+
}
189+
190+
#[cfg(feature = "http")]
191+
impl api::Carrier for http::HeaderMap {
192+
/// Get a value for a key from the HeaderMap. If the value is not valid ASCII, returns None.
193+
fn get(&self, key: &str) -> Option<&str> {
194+
match self.get(key) {
195+
Some(val) => match val.to_str() {
196+
Ok(ascii) => Some(ascii),
197+
Err(_) => None,
198+
},
199+
None => None,
200+
}
201+
}
202+
203+
/// Set a key and value in the HeaderMap. Does nothing if the key or value are not valid inputs.
204+
fn set(&mut self, key: &str, value: String) {
205+
if let Ok(name) = http::header::HeaderName::from_bytes(key.as_bytes()) {
206+
if let Ok(val) = http::header::HeaderValue::from_str(&value) {
207+
self.insert(name, val);
208+
}
209+
}
210+
}
211+
}
212+
213+
#[cfg(feature = "tonic")]
214+
impl api::Carrier for tonic::metadata::MetadataMap {
215+
/// Get a value for a key from the MetadataMap. If the value can't be converted to &str, returns None
216+
fn get(&self, key: &str) -> Option<&str> {
217+
self.get(key).and_then(|metadata| metadata.to_str().ok())
218+
}
219+
220+
/// Set a key and value in the MetadataMap. Does nothing if the key or value are not valid inputs
221+
fn set(&mut self, key: &str, value: String) {
222+
if let Ok(key) = tonic::metadata::MetadataKey::from_bytes(key.to_lowercase().as_bytes()) {
223+
if let Ok(val) = tonic::metadata::MetadataValue::from_str(&value) {
224+
self.insert(key, val);
225+
}
226+
}
187227
}
188228
}

src/api/correlation/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//!
2121
//! // Example correlation value passed in externally via http headers
2222
//! let mut headers = HashMap::new();
23-
//! headers.insert("Correlation-Context", "user_id=1".to_string());
23+
//! headers.insert("Correlation-Context".to_string(), "user_id=1".to_string());
2424
//!
2525
//! let propagator = CorrelationContextPropagator::new();
2626
//! // can extract from any type that impls `Carrier`, usually an HTTP header map

0 commit comments

Comments
 (0)