Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: send propagator error to global error handler #1640

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions opentelemetry-jaeger-propagator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## vNext

### Changed

- Propagation error will be reported to global error handler [#1640](https://github.com/open-telemetry/opentelemetry-rust/pull/1640)

## v0.1.0

### Added
Expand Down
51 changes: 33 additions & 18 deletions opentelemetry-jaeger-propagator/src/propagator.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use opentelemetry::propagation::PropagationError;
use opentelemetry::{
global::{self, Error},
propagation::{text_map_propagator::FieldIter, Extractor, Injector, TextMapPropagator},
Expand Down Expand Up @@ -69,7 +70,7 @@ impl Propagator {
}

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

let parts = header_value.split_terminator(':').collect::<Vec<&str>>();
if parts.len() != 4 {
return Err(());
global::handle_error(Error::Propagation(PropagationError::extract(
"invalid jaeger header format",
"JaegerPropagator",
)));
return None;
}

// extract trace id
let trace_id = self.extract_trace_id(parts[0])?;
let span_id = self.extract_span_id(parts[1])?;
// Ignore parent span id since it's deprecated.
let flags = self.extract_trace_flags(parts[3])?;
let state = self.extract_trace_state(extractor)?;

Ok(SpanContext::new(trace_id, span_id, flags, true, state))
match (
self.extract_trace_id(parts[0]),
self.extract_span_id(parts[1]),
// Ignore parent span id since it's deprecated.
self.extract_trace_flags(parts[3]),
self.extract_trace_state(extractor),
) {
(Ok(trace_id), Ok(span_id), Ok(flags), Ok(state)) => {
Some(SpanContext::new(trace_id, span_id, flags, true, state))
}
_ => {
global::handle_error(Error::Propagation(PropagationError::extract(
"invalid jaeger header format",
"JaegerPropagator",
)));
None
}
}
}

/// Extract trace id from the header.
Expand Down Expand Up @@ -188,7 +203,7 @@ impl TextMapPropagator for Propagator {
fn extract_with_context(&self, cx: &Context, extractor: &dyn Extractor) -> Context {
self.extract_span_context(extractor)
.map(|sc| cx.with_remote_span_context(sc))
.unwrap_or_else(|_| cx.clone())
.unwrap_or_else(|| cx.clone())
}

fn fields(&self) -> FieldIter<'_> {
Expand Down Expand Up @@ -430,7 +445,7 @@ mod tests {
);
assert_eq!(
propagator_with_custom_header.extract_span_context(&map),
Ok(SpanContext::new(
Some(SpanContext::new(
TraceId::from_hex("12345").unwrap(),
SpanId::from_hex("54321").unwrap(),
TRACE_FLAG_DEBUG | TraceFlags::SAMPLED,
Expand All @@ -447,7 +462,7 @@ mod tests {
);
assert_eq!(
propagator_with_custom_header.extract_span_context(&map),
Ok(SpanContext::new(
Some(SpanContext::new(
TraceId::from_hex("12345").unwrap(),
SpanId::from_hex("54321").unwrap(),
TRACE_FLAG_DEBUG | TraceFlags::SAMPLED,
Expand All @@ -463,7 +478,7 @@ mod tests {
);
assert_eq!(
propagator_with_custom_header.extract_span_context(&map),
Err(())
None,
);

map.clear();
Expand All @@ -473,7 +488,7 @@ mod tests {
);
assert_eq!(
propagator_with_custom_header.extract_span_context(&map),
Err(())
None,
);

map.clear();
Expand All @@ -483,7 +498,7 @@ mod tests {
);
assert_eq!(
propagator_with_custom_header.extract_span_context(&map),
Err(())
None,
);

map.clear();
Expand All @@ -493,7 +508,7 @@ mod tests {
);
assert_eq!(
propagator_with_custom_header.extract_span_context(&map),
Err(())
None,
);

map.clear();
Expand All @@ -506,7 +521,7 @@ mod tests {
map.set(&too_long_baggage_key, "baggage_value".to_owned());
assert_eq!(
propagator_with_custom_header.extract_span_context(&map),
Err(())
None,
);
}

Expand Down
1 change: 1 addition & 0 deletions opentelemetry-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- **Breaking** [#1624](https://github.com/open-telemetry/opentelemetry-rust/pull/1624) Remove `OsResourceDetector` and
`ProcessResourceDetector` resource detectors, use the
[`opentelemetry-resource-detector`](https://crates.io/crates/opentelemetry-resource-detectors) instead.
- Baggage propagation error will be reported to global error handler [#1640](https://github.com/open-telemetry/opentelemetry-rust/pull/1640)

## v0.22.1

Expand Down
60 changes: 38 additions & 22 deletions opentelemetry-sdk/src/propagation/baggage.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use once_cell::sync::Lazy;
use opentelemetry::propagation::PropagationError;
use opentelemetry::{
baggage::{BaggageExt, KeyValueMetadata},
global,
propagation::{text_map_propagator::FieldIter, Extractor, Injector, TextMapPropagator},
Context,
};
Expand Down Expand Up @@ -99,30 +101,44 @@
{
let mut iter = name_and_value.split('=');
if let (Some(name), Some(value)) = (iter.next(), iter.next()) {
let name = percent_decode_str(name).decode_utf8().map_err(|_| ())?;
let value = percent_decode_str(value).decode_utf8().map_err(|_| ())?;
let decode_name = percent_decode_str(name).decode_utf8();
let decode_value = percent_decode_str(value).decode_utf8();

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

Ok(KeyValueMetadata::new(
name.trim().to_owned(),
value.trim().to_string(),
decoded_props.as_str(),
))
Some(KeyValueMetadata::new(
name.trim().to_owned(),
value.trim().to_string(),
decoded_props.as_str(),
))
} else {
global::handle_error(PropagationError::extract(
"invalid UTF8 string in key values",
"BaggagePropagator",
));
None

Check warning on line 127 in opentelemetry-sdk/src/propagation/baggage.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/propagation/baggage.rs#L123-L127

Added lines #L123 - L127 were not covered by tests
}
} else {
// Invalid name-value format
Err(())
global::handle_error(PropagationError::extract(
"invalid baggage key-value format",
"BaggagePropagator",
));
None
}
} else {
// Invalid baggage value format
Err(())
global::handle_error(PropagationError::extract(
"invalid baggage format",
"BaggagePropagator",
));
None

Check warning on line 141 in opentelemetry-sdk/src/propagation/baggage.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/propagation/baggage.rs#L137-L141

Added lines #L137 - L141 were not covered by tests
}
});
cx.with_baggage(baggage)
Expand Down Expand Up @@ -172,7 +188,7 @@
vec![
(Key::new("key1"), (Value::from("value1"), BaggageMetadata::from("property1;property2"))),
(Key::new("key2"), (Value::from("value2"), BaggageMetadata::default())),
(Key::new("key3"), (Value::from("value3"), BaggageMetadata::from("propertyKey=propertyValue")))
(Key::new("key3"), (Value::from("value3"), BaggageMetadata::from("propertyKey=propertyValue"))),
].into_iter().collect()),
]
}
Expand Down Expand Up @@ -220,12 +236,12 @@
vec![
KeyValueMetadata::new("key1", "val1", "prop1"),
KeyValue::new("key2", "val2").into(),
KeyValueMetadata::new("key3", "val3", "anykey=anyvalue")
KeyValueMetadata::new("key3", "val3", "anykey=anyvalue"),
],
vec![
"key1=val1;prop1",
"key2=val2",
"key3=val3;anykey=anyvalue"
"key3=val3;anykey=anyvalue",
],
)
]
Expand Down
1 change: 1 addition & 0 deletions opentelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Added

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

### Removed

Expand Down
8 changes: 8 additions & 0 deletions opentelemetry/src/global/error_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::sync::RwLock;
use crate::logs::LogError;
#[cfg(feature = "metrics")]
use crate::metrics::MetricsError;
use crate::propagation::PropagationError;
#[cfg(feature = "trace")]
use crate::trace::TraceError;
use once_cell::sync::Lazy;
Expand Down Expand Up @@ -32,6 +33,10 @@ pub enum Error {
/// Failed to export logs.
Log(#[from] LogError),

#[error(transparent)]
/// Error happens when injecting and extracting information using propagators.
Propagation(#[from] PropagationError),

#[error("{0}")]
/// Other types of failures not covered by the variants above.
Other(String),
Expand Down Expand Up @@ -61,6 +66,9 @@ pub fn handle_error<T: Into<Error>>(err: T) {
#[cfg(feature = "logs")]
#[cfg_attr(docsrs, doc(cfg(feature = "logs")))]
Error::Log(err) => eprintln!("OpenTelemetry log error occurred. {}", err),
Error::Propagation(err) => {
eprintln!("OpenTelemetry propagation error occurred. {}", err)
}
Error::Other(err_msg) => eprintln!("OpenTelemetry error occurred. {}", err_msg),
},
}
Expand Down
32 changes: 32 additions & 0 deletions opentelemetry/src/propagation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
//! [`Context`]: crate::Context

use std::collections::HashMap;
use thiserror::Error;

pub mod composite;
pub mod text_map_propagator;
Expand Down Expand Up @@ -61,6 +62,37 @@
}
}

/// Error when extracting or injecting context data(i.e propagating) across application boundaries.
#[derive(Error, Debug)]
#[error("Cannot {} from {}, {}", ops, message, propagator_name)]
pub struct PropagationError {
message: &'static str,
// which propagator does this error comes from
propagator_name: &'static str,
// are we extracting or injecting information across application boundaries
ops: &'static str,
}

impl PropagationError {
/// Error happens when extracting information
pub fn extract(message: &'static str, propagator_name: &'static str) -> Self {
PropagationError {
message,
propagator_name,
ops: "extract",
}
}

/// Error happens when extracting information
pub fn inject(message: &'static str, propagator_name: &'static str) -> Self {
PropagationError {
message,
propagator_name,
ops: "inject",
}
}

Check warning on line 93 in opentelemetry/src/propagation/mod.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry/src/propagation/mod.rs#L87-L93

Added lines #L87 - L93 were not covered by tests
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading