Skip to content

Commit 8483914

Browse files
authored
fix: send propagator error to global error handler (#1640)
1 parent 936c466 commit 8483914

File tree

7 files changed

+117
-40
lines changed

7 files changed

+117
-40
lines changed

opentelemetry-jaeger-propagator/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## vNext
44

5+
### Changed
6+
7+
- Propagation error will be reported to global error handler [#1640](https://github.com/open-telemetry/opentelemetry-rust/pull/1640)
8+
59
## v0.1.0
610

711
### Added

opentelemetry-jaeger-propagator/src/propagator.rs

+33-18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use opentelemetry::propagation::PropagationError;
12
use opentelemetry::{
23
global::{self, Error},
34
propagation::{text_map_propagator::FieldIter, Extractor, Injector, TextMapPropagator},
@@ -69,7 +70,7 @@ impl Propagator {
6970
}
7071

7172
/// Extract span context from header value
72-
fn extract_span_context(&self, extractor: &dyn Extractor) -> Result<SpanContext, ()> {
73+
fn extract_span_context(&self, extractor: &dyn Extractor) -> Option<SpanContext> {
7374
let mut header_value = Cow::from(extractor.get(self.header_name).unwrap_or(""));
7475
// if there is no :, it means header_value could be encoded as url, try decode first
7576
if !header_value.contains(':') {
@@ -78,17 +79,31 @@ impl Propagator {
7879

7980
let parts = header_value.split_terminator(':').collect::<Vec<&str>>();
8081
if parts.len() != 4 {
81-
return Err(());
82+
global::handle_error(Error::Propagation(PropagationError::extract(
83+
"invalid jaeger header format",
84+
"JaegerPropagator",
85+
)));
86+
return None;
8287
}
8388

84-
// extract trace id
85-
let trace_id = self.extract_trace_id(parts[0])?;
86-
let span_id = self.extract_span_id(parts[1])?;
87-
// Ignore parent span id since it's deprecated.
88-
let flags = self.extract_trace_flags(parts[3])?;
89-
let state = self.extract_trace_state(extractor)?;
90-
91-
Ok(SpanContext::new(trace_id, span_id, flags, true, state))
89+
match (
90+
self.extract_trace_id(parts[0]),
91+
self.extract_span_id(parts[1]),
92+
// Ignore parent span id since it's deprecated.
93+
self.extract_trace_flags(parts[3]),
94+
self.extract_trace_state(extractor),
95+
) {
96+
(Ok(trace_id), Ok(span_id), Ok(flags), Ok(state)) => {
97+
Some(SpanContext::new(trace_id, span_id, flags, true, state))
98+
}
99+
_ => {
100+
global::handle_error(Error::Propagation(PropagationError::extract(
101+
"invalid jaeger header format",
102+
"JaegerPropagator",
103+
)));
104+
None
105+
}
106+
}
92107
}
93108

94109
/// Extract trace id from the header.
@@ -188,7 +203,7 @@ impl TextMapPropagator for Propagator {
188203
fn extract_with_context(&self, cx: &Context, extractor: &dyn Extractor) -> Context {
189204
self.extract_span_context(extractor)
190205
.map(|sc| cx.with_remote_span_context(sc))
191-
.unwrap_or_else(|_| cx.clone())
206+
.unwrap_or_else(|| cx.clone())
192207
}
193208

194209
fn fields(&self) -> FieldIter<'_> {
@@ -430,7 +445,7 @@ mod tests {
430445
);
431446
assert_eq!(
432447
propagator_with_custom_header.extract_span_context(&map),
433-
Ok(SpanContext::new(
448+
Some(SpanContext::new(
434449
TraceId::from_hex("12345").unwrap(),
435450
SpanId::from_hex("54321").unwrap(),
436451
TRACE_FLAG_DEBUG | TraceFlags::SAMPLED,
@@ -447,7 +462,7 @@ mod tests {
447462
);
448463
assert_eq!(
449464
propagator_with_custom_header.extract_span_context(&map),
450-
Ok(SpanContext::new(
465+
Some(SpanContext::new(
451466
TraceId::from_hex("12345").unwrap(),
452467
SpanId::from_hex("54321").unwrap(),
453468
TRACE_FLAG_DEBUG | TraceFlags::SAMPLED,
@@ -463,7 +478,7 @@ mod tests {
463478
);
464479
assert_eq!(
465480
propagator_with_custom_header.extract_span_context(&map),
466-
Err(())
481+
None,
467482
);
468483

469484
map.clear();
@@ -473,7 +488,7 @@ mod tests {
473488
);
474489
assert_eq!(
475490
propagator_with_custom_header.extract_span_context(&map),
476-
Err(())
491+
None,
477492
);
478493

479494
map.clear();
@@ -483,7 +498,7 @@ mod tests {
483498
);
484499
assert_eq!(
485500
propagator_with_custom_header.extract_span_context(&map),
486-
Err(())
501+
None,
487502
);
488503

489504
map.clear();
@@ -493,7 +508,7 @@ mod tests {
493508
);
494509
assert_eq!(
495510
propagator_with_custom_header.extract_span_context(&map),
496-
Err(())
511+
None,
497512
);
498513

499514
map.clear();
@@ -506,7 +521,7 @@ mod tests {
506521
map.set(&too_long_baggage_key, "baggage_value".to_owned());
507522
assert_eq!(
508523
propagator_with_custom_header.extract_span_context(&map),
509-
Err(())
524+
None,
510525
);
511526
}
512527

opentelemetry-sdk/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- **Breaking** [#1624](https://github.com/open-telemetry/opentelemetry-rust/pull/1624) Remove `OsResourceDetector` and
1313
`ProcessResourceDetector` resource detectors, use the
1414
[`opentelemetry-resource-detector`](https://crates.io/crates/opentelemetry-resource-detectors) instead.
15+
- Baggage propagation error will be reported to global error handler [#1640](https://github.com/open-telemetry/opentelemetry-rust/pull/1640)
1516

1617
## v0.22.1
1718

opentelemetry-sdk/src/propagation/baggage.rs

+38-22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use once_cell::sync::Lazy;
2+
use opentelemetry::propagation::PropagationError;
23
use opentelemetry::{
34
baggage::{BaggageExt, KeyValueMetadata},
5+
global,
46
propagation::{text_map_propagator::FieldIter, Extractor, Injector, TextMapPropagator},
57
Context,
68
};
@@ -99,30 +101,44 @@ impl TextMapPropagator for BaggagePropagator {
99101
{
100102
let mut iter = name_and_value.split('=');
101103
if let (Some(name), Some(value)) = (iter.next(), iter.next()) {
102-
let name = percent_decode_str(name).decode_utf8().map_err(|_| ())?;
103-
let value = percent_decode_str(value).decode_utf8().map_err(|_| ())?;
104+
let decode_name = percent_decode_str(name).decode_utf8();
105+
let decode_value = percent_decode_str(value).decode_utf8();
104106

105-
// Here we don't store the first ; into baggage since it should be treated
106-
// as separator rather part of metadata
107-
let decoded_props = props
108-
.iter()
109-
.flat_map(|prop| percent_decode_str(prop).decode_utf8())
110-
.map(|prop| prop.trim().to_string())
111-
.collect::<Vec<String>>()
112-
.join(";"); // join with ; because we deleted all ; when calling split above
107+
if let (Ok(name), Ok(value)) = (decode_name, decode_value) {
108+
// Here we don't store the first ; into baggage since it should be treated
109+
// as separator rather part of metadata
110+
let decoded_props = props
111+
.iter()
112+
.flat_map(|prop| percent_decode_str(prop).decode_utf8())
113+
.map(|prop| prop.trim().to_string())
114+
.collect::<Vec<String>>()
115+
.join(";"); // join with ; because we deleted all ; when calling split above
113116

114-
Ok(KeyValueMetadata::new(
115-
name.trim().to_owned(),
116-
value.trim().to_string(),
117-
decoded_props.as_str(),
118-
))
117+
Some(KeyValueMetadata::new(
118+
name.trim().to_owned(),
119+
value.trim().to_string(),
120+
decoded_props.as_str(),
121+
))
122+
} else {
123+
global::handle_error(PropagationError::extract(
124+
"invalid UTF8 string in key values",
125+
"BaggagePropagator",
126+
));
127+
None
128+
}
119129
} else {
120-
// Invalid name-value format
121-
Err(())
130+
global::handle_error(PropagationError::extract(
131+
"invalid baggage key-value format",
132+
"BaggagePropagator",
133+
));
134+
None
122135
}
123136
} else {
124-
// Invalid baggage value format
125-
Err(())
137+
global::handle_error(PropagationError::extract(
138+
"invalid baggage format",
139+
"BaggagePropagator",
140+
));
141+
None
126142
}
127143
});
128144
cx.with_baggage(baggage)
@@ -172,7 +188,7 @@ mod tests {
172188
vec![
173189
(Key::new("key1"), (Value::from("value1"), BaggageMetadata::from("property1;property2"))),
174190
(Key::new("key2"), (Value::from("value2"), BaggageMetadata::default())),
175-
(Key::new("key3"), (Value::from("value3"), BaggageMetadata::from("propertyKey=propertyValue")))
191+
(Key::new("key3"), (Value::from("value3"), BaggageMetadata::from("propertyKey=propertyValue"))),
176192
].into_iter().collect()),
177193
]
178194
}
@@ -220,12 +236,12 @@ mod tests {
220236
vec![
221237
KeyValueMetadata::new("key1", "val1", "prop1"),
222238
KeyValue::new("key2", "val2").into(),
223-
KeyValueMetadata::new("key3", "val3", "anykey=anyvalue")
239+
KeyValueMetadata::new("key3", "val3", "anykey=anyvalue"),
224240
],
225241
vec![
226242
"key1=val1;prop1",
227243
"key2=val2",
228-
"key3=val3;anykey=anyvalue"
244+
"key3=val3;anykey=anyvalue",
229245
],
230246
)
231247
]

opentelemetry/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Added
66

77
- [#1623](https://github.com/open-telemetry/opentelemetry-rust/pull/1623) Add global::meter_provider_shutdown
8+
- [#1640](https://github.com/open-telemetry/opentelemetry-rust/pull/1640) Add `PropagationError`
89

910
### Removed
1011

opentelemetry/src/global/error_handler.rs

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::sync::RwLock;
55
use crate::logs::LogError;
66
#[cfg(feature = "metrics")]
77
use crate::metrics::MetricsError;
8+
use crate::propagation::PropagationError;
89
#[cfg(feature = "trace")]
910
use crate::trace::TraceError;
1011
use once_cell::sync::Lazy;
@@ -32,6 +33,10 @@ pub enum Error {
3233
/// Failed to export logs.
3334
Log(#[from] LogError),
3435

36+
#[error(transparent)]
37+
/// Error happens when injecting and extracting information using propagators.
38+
Propagation(#[from] PropagationError),
39+
3540
#[error("{0}")]
3641
/// Other types of failures not covered by the variants above.
3742
Other(String),
@@ -61,6 +66,9 @@ pub fn handle_error<T: Into<Error>>(err: T) {
6166
#[cfg(feature = "logs")]
6267
#[cfg_attr(docsrs, doc(cfg(feature = "logs")))]
6368
Error::Log(err) => eprintln!("OpenTelemetry log error occurred. {}", err),
69+
Error::Propagation(err) => {
70+
eprintln!("OpenTelemetry propagation error occurred. {}", err)
71+
}
6472
Error::Other(err_msg) => eprintln!("OpenTelemetry error occurred. {}", err_msg),
6573
},
6674
}

opentelemetry/src/propagation/mod.rs

+32
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
//! [`Context`]: crate::Context
2121
2222
use std::collections::HashMap;
23+
use thiserror::Error;
2324

2425
pub mod composite;
2526
pub mod text_map_propagator;
@@ -61,6 +62,37 @@ impl<S: std::hash::BuildHasher> Extractor for HashMap<String, String, S> {
6162
}
6263
}
6364

65+
/// Error when extracting or injecting context data(i.e propagating) across application boundaries.
66+
#[derive(Error, Debug)]
67+
#[error("Cannot {} from {}, {}", ops, message, propagator_name)]
68+
pub struct PropagationError {
69+
message: &'static str,
70+
// which propagator does this error comes from
71+
propagator_name: &'static str,
72+
// are we extracting or injecting information across application boundaries
73+
ops: &'static str,
74+
}
75+
76+
impl PropagationError {
77+
/// Error happens when extracting information
78+
pub fn extract(message: &'static str, propagator_name: &'static str) -> Self {
79+
PropagationError {
80+
message,
81+
propagator_name,
82+
ops: "extract",
83+
}
84+
}
85+
86+
/// Error happens when extracting information
87+
pub fn inject(message: &'static str, propagator_name: &'static str) -> Self {
88+
PropagationError {
89+
message,
90+
propagator_name,
91+
ops: "inject",
92+
}
93+
}
94+
}
95+
6496
#[cfg(test)]
6597
mod tests {
6698
use super::*;

0 commit comments

Comments
 (0)