Skip to content

Commit 64bc7ba

Browse files
authored
Revisit error handling in trace (open-telemetry#371)
1 parent ac8e4e5 commit 64bc7ba

File tree

34 files changed

+458
-199
lines changed

34 files changed

+458
-199
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
override: true
5353
- name: Run tests
5454
run: cargo --version &&
55-
cargo test --verbose --manifest-path=opentelemetry/Cargo.toml --features trace,metrics,serialize,tokio,async-std,serde,http,tonic,reqwest &&
55+
cargo test --verbose --manifest-path=opentelemetry/Cargo.toml --features trace,metrics,serialize,tokio,serde,http,tonic,reqwest &&
5656
cargo test --manifest-path=opentelemetry-jaeger/Cargo.toml &&
5757
cargo test --manifest-path=opentelemetry-zipkin/Cargo.toml
5858
meta:

CONTRIBUTING.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ patterns in the spec.
9393
For a deeper discussion, see:
9494
https://github.com/open-telemetry/opentelemetry-specification/issues/165
9595

96+
### Error Handling
97+
Currently, the Opentelemetry Rust SDK has two ways to handle errors. In the situation where errors are not allowed to return. One should call global error handler to process the errors. Otherwise, one should return the errors.
98+
99+
The Opentelemetry Rust SDK comes with an error type `openetelemetry::Error`. For different function, one error has been defined. All error returned by trace module MUST be wrapped in `opentelemetry::trace::TraceError`. All errors returned by metrics module MUST be wrapped in `opentelemetry::metrics::MetricsError`.
100+
101+
For users that want to implement their own exporters. It's RECOMMENDED to wrap all errors from the exporter into a crate-level error type, and implement `ExporterError` trait.
102+
96103
## Style Guide
97104

98105
* Run `cargo clippy --all` - this will catch common mistakes and improve

examples/actix-http/src/main.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
use actix_service::Service;
22
use actix_web::middleware::Logger;
33
use actix_web::{web, App, HttpServer};
4+
use opentelemetry::trace::TraceError;
45
use opentelemetry::{global, sdk::trace as sdktrace};
56
use opentelemetry::{
67
trace::{FutureExt, TraceContextExt, Tracer},
78
Key,
89
};
9-
use std::error::Error;
1010

11-
fn init_tracer() -> Result<
12-
(sdktrace::Tracer, opentelemetry_jaeger::Uninstall),
13-
Box<dyn Error + Send + Sync + 'static>,
14-
> {
11+
fn init_tracer() -> Result<(sdktrace::Tracer, opentelemetry_jaeger::Uninstall), TraceError> {
1512
opentelemetry_jaeger::new_pipeline()
1613
.with_collector_endpoint("http://127.0.0.1:14268/api/traces")
1714
.with_service_name("trace-http-demo")

examples/actix-udp/src/main.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
use actix_service::Service;
22
use actix_web::middleware::Logger;
33
use actix_web::{web, App, HttpServer};
4+
use opentelemetry::trace::TraceError;
45
use opentelemetry::{global, sdk::trace as sdktrace};
56
use opentelemetry::{
67
trace::{FutureExt, TraceContextExt, Tracer},
78
Key,
89
};
9-
use std::error::Error;
1010

11-
fn init_tracer() -> Result<
12-
(sdktrace::Tracer, opentelemetry_jaeger::Uninstall),
13-
Box<dyn Error + Send + Sync + 'static>,
14-
> {
11+
fn init_tracer() -> Result<(sdktrace::Tracer, opentelemetry_jaeger::Uninstall), TraceError> {
1512
opentelemetry_jaeger::new_pipeline()
1613
.with_agent_endpoint("localhost:6831")
1714
.with_service_name("trace-udp-demo")

examples/async/src/main.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
//! cargo run --example async_fn
1818
//!
1919
//! [`hello_world`]: https://github.com/tokio-rs/tokio/blob/132e9f1da5965530b63554d7a1c59824c3de4e30/tokio/examples/hello_world.rs
20+
use opentelemetry::trace::TraceError;
2021
use opentelemetry::{
2122
global,
2223
sdk::trace as sdktrace,
@@ -52,10 +53,7 @@ async fn run(addr: &SocketAddr) -> io::Result<usize> {
5253
write(&mut stream).with_context(cx).await
5354
}
5455

55-
fn init_tracer() -> Result<
56-
(sdktrace::Tracer, opentelemetry_jaeger::Uninstall),
57-
Box<dyn Error + Send + Sync + 'static>,
58-
> {
56+
fn init_tracer() -> Result<(sdktrace::Tracer, opentelemetry_jaeger::Uninstall), TraceError> {
5957
opentelemetry_jaeger::new_pipeline()
6058
.with_service_name("trace-demo")
6159
.install()

examples/basic-otlp/src/main.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use futures::stream::{Stream, StreamExt};
22
use opentelemetry::exporter;
33
use opentelemetry::sdk::metrics::PushController;
4+
use opentelemetry::trace::TraceError;
45
use opentelemetry::{
56
baggage::BaggageExt,
67
metrics::{self, MetricsError, ObserverResult},
@@ -11,9 +12,7 @@ use opentelemetry::{global, sdk::trace as sdktrace};
1112
use std::error::Error;
1213
use std::time::Duration;
1314

14-
fn init_tracer(
15-
) -> Result<(sdktrace::Tracer, opentelemetry_otlp::Uninstall), Box<dyn Error + Send + Sync + 'static>>
16-
{
15+
fn init_tracer() -> Result<(sdktrace::Tracer, opentelemetry_otlp::Uninstall), TraceError> {
1716
opentelemetry_otlp::new_pipeline().install()
1817
}
1918

examples/basic/src/main.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use futures::stream::{Stream, StreamExt};
22
use opentelemetry::exporter;
33
use opentelemetry::global;
44
use opentelemetry::sdk::{metrics::PushController, trace as sdktrace};
5+
use opentelemetry::trace::TraceError;
56
use opentelemetry::{
67
baggage::BaggageExt,
78
metrics::{self, MetricsError, ObserverResult},
@@ -11,10 +12,7 @@ use opentelemetry::{
1112
use std::error::Error;
1213
use std::time::Duration;
1314

14-
fn init_tracer() -> Result<
15-
(sdktrace::Tracer, opentelemetry_jaeger::Uninstall),
16-
Box<dyn Error + Send + Sync + 'static>,
17-
> {
15+
fn init_tracer() -> Result<(sdktrace::Tracer, opentelemetry_jaeger::Uninstall), TraceError> {
1816
opentelemetry_jaeger::new_pipeline()
1917
.with_service_name("trace-demo")
2018
.with_tags(vec![

examples/grpc/src/client.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,17 @@ use hello_world::greeter_client::GreeterClient;
22
use hello_world::HelloRequest;
33
use opentelemetry::global;
44
use opentelemetry::sdk::propagation::TraceContextPropagator;
5+
use opentelemetry::trace::TraceError;
56
use opentelemetry::{
67
trace::{TraceContextExt, Tracer},
78
Context, KeyValue,
89
};
9-
use std::error::Error;
1010

1111
pub mod hello_world {
1212
tonic::include_proto!("helloworld");
1313
}
1414

15-
fn tracing_init(
16-
) -> Result<(impl Tracer, opentelemetry_jaeger::Uninstall), Box<dyn Error + Send + Sync + 'static>>
17-
{
15+
fn tracing_init() -> Result<(impl Tracer, opentelemetry_jaeger::Uninstall), TraceError> {
1816
global::set_text_map_propagator(TraceContextPropagator::new());
1917
opentelemetry_jaeger::new_pipeline()
2018
.with_service_name("grpc-client")

examples/grpc/src/server.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use hello_world::greeter_server::{Greeter, GreeterServer};
44
use hello_world::{HelloReply, HelloRequest};
55
use opentelemetry::global;
66
use opentelemetry::sdk::propagation::TraceContextPropagator;
7+
use opentelemetry::trace::TraceError;
78
use opentelemetry::{
89
trace::{Span, Tracer},
910
KeyValue,
@@ -36,9 +37,7 @@ impl Greeter for MyGreeter {
3637
}
3738
}
3839

39-
fn tracing_init(
40-
) -> Result<(impl Tracer, opentelemetry_jaeger::Uninstall), Box<dyn Error + Send + Sync + 'static>>
41-
{
40+
fn tracing_init() -> Result<(impl Tracer, opentelemetry_jaeger::Uninstall), TraceError> {
4241
global::set_text_map_propagator(TraceContextPropagator::new());
4342
opentelemetry_jaeger::new_pipeline()
4443
.with_service_name("grpc-server")

opentelemetry-contrib/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ rustdoc-args = ["--cfg", "docsrs"]
2222
default = []
2323
base64_format = ["base64", "binary_propagator"]
2424
binary_propagator = []
25-
datadog = ["indexmap", "rmp", "async-trait"]
25+
datadog = ["indexmap", "rmp", "async-trait", "thiserror"]
2626
reqwest-blocking-client = ["reqwest/blocking", "opentelemetry/reqwest"]
2727
reqwest-client = ["reqwest", "opentelemetry/reqwest"]
2828
surf-client = ["surf", "opentelemetry/surf"]
@@ -37,6 +37,7 @@ reqwest = { version = "0.10", optional = true }
3737
surf = { version = "2.0", optional = true }
3838
http = "0.2"
3939
base64 = { version = "0.13", optional = true }
40+
thiserror = { version = "1.0", optional = true }
4041

4142
[dev-dependencies]
4243
base64 = "0.13"

opentelemetry-contrib/src/trace/exporter/datadog/mod.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
//! use opentelemetry::exporter::trace::HttpClient;
7777
//! use opentelemetry_contrib::trace::exporter::datadog::{new_pipeline, ApiVersion};
7878
//! use async_trait::async_trait;
79-
//! use std::error::Error;
79+
//! use opentelemetry_contrib::trace::exporter::datadog::Error;
8080
//!
8181
//! // `reqwest` and `surf` are supported through features, if you prefer an
8282
//! // alternate http client you can add support by implementing `HttpClient` as
@@ -87,17 +87,17 @@
8787
//! #[async_trait]
8888
//! impl HttpClient for IsahcClient {
8989
//! async fn send(&self, request: http::Request<Vec<u8>>) -> ExportResult {
90-
//! let result = self.0.send_async(request).await?;
90+
//! let result = self.0.send_async(request).await.map_err(|err| Error::Other(err.to_string()))?;
9191
//!
9292
//! if result.status().is_success() {
9393
//! Ok(())
9494
//! } else {
95-
//! Err(result.status().as_str().into())
95+
//! Err(Error::Other(result.status().to_string()).into())
9696
//! }
9797
//! }
9898
//! }
9999
//!
100-
//! fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
100+
//! fn main() -> Result<(), opentelemetry::trace::TraceError> {
101101
//! let (tracer, _uninstall) = new_pipeline()
102102
//! .with_service_name("my_app")
103103
//! .with_version(ApiVersion::Version05)
@@ -123,14 +123,14 @@ mod intern;
123123
mod model;
124124

125125
pub use model::ApiVersion;
126+
pub use model::Error;
126127

127128
use async_trait::async_trait;
128129
use http::{Method, Request, Uri};
129130
use opentelemetry::exporter::trace;
130131
use opentelemetry::exporter::trace::{HttpClient, SpanData};
132+
use opentelemetry::trace::TraceError;
131133
use opentelemetry::{global, sdk, trace::TracerProvider};
132-
use std::error::Error;
133-
use std::io;
134134

135135
/// Default Datadog collector endpoint
136136
const DEFAULT_AGENT_ENDPOINT: &str = "http://127.0.0.1:8126";
@@ -211,14 +211,12 @@ impl Default for DatadogPipelineBuilder {
211211

212212
impl DatadogPipelineBuilder {
213213
/// Create `ExporterConfig` struct from current `ExporterConfigBuilder`
214-
pub fn install(
215-
mut self,
216-
) -> Result<(sdk::trace::Tracer, Uninstall), Box<dyn Error + Send + Sync + 'static>> {
214+
pub fn install(mut self) -> Result<(sdk::trace::Tracer, Uninstall), TraceError> {
217215
if let Some(client) = self.client {
218216
let endpoint = self.agent_endpoint + self.version.path();
219217
let exporter = DatadogExporter::new(
220218
self.service_name.clone(),
221-
endpoint.parse()?,
219+
endpoint.parse().map_err::<Error, _>(Into::into)?,
222220
self.version,
223221
client,
224222
);
@@ -233,11 +231,7 @@ impl DatadogPipelineBuilder {
233231
let provider_guard = global::set_tracer_provider(provider);
234232
Ok((tracer, Uninstall(provider_guard)))
235233
} else {
236-
Err(Box::new(io::Error::new(
237-
io::ErrorKind::Other,
238-
"http client must be set, users can enable reqwest or surf feature to use http\
239-
client implementation within create",
240-
)))
234+
Err(Error::NoHttpClient.into())
241235
}
242236
}
243237

@@ -284,7 +278,8 @@ impl trace::SpanExporter for DatadogExporter {
284278
.method(Method::POST)
285279
.uri(self.request_url.clone())
286280
.header(http::header::CONTENT_TYPE, self.version.content_type())
287-
.body(data)?;
281+
.body(data)
282+
.map_err::<Error, _>(Into::into)?;
288283
self.client.send(req).await
289284
}
290285
}

opentelemetry-contrib/src/trace/exporter/datadog/model/mod.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
1-
use opentelemetry::exporter::trace;
2-
use std::fmt;
1+
use opentelemetry::exporter::{trace, ExportError};
32

43
mod v03;
54
mod v05;
65

7-
#[derive(Debug, Clone, Copy)]
8-
pub(crate) enum Error {
6+
/// Wrap type for errors from opentelemetry datadog exporter
7+
#[derive(Debug, thiserror::Error)]
8+
pub enum Error {
9+
/// Message pack error
10+
#[error("message pack error")]
911
MessagePackError,
12+
/// No http client founded. User should provide one or enable features
13+
#[error("http client must be set, users can enable reqwest or surf feature to use http client implementation within create")]
14+
NoHttpClient,
15+
/// Http requests failed with following errors
16+
#[error(transparent)]
17+
RequestError(#[from] http::Error),
18+
/// The Uri was invalid
19+
#[error(transparent)]
20+
InvalidUri(#[from] http::uri::InvalidUri),
21+
/// Other errors
22+
#[error("{0}")]
23+
Other(String),
1024
}
1125

12-
impl std::error::Error for Error {}
13-
14-
impl fmt::Display for Error {
15-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16-
match self {
17-
Error::MessagePackError => write!(f, "message pack error"),
18-
}
26+
impl ExportError for Error {
27+
fn exporter_name(&self) -> &'static str {
28+
"datadog"
1929
}
2030
}
2131

opentelemetry-jaeger/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ thrift = "0.13"
3333
tokio = { version = "0.2", features = ["udp", "sync"], optional = true }
3434
wasm-bindgen = { version = "0.2", optional = true }
3535
wasm-bindgen-futures = { version = "0.4.18", optional = true }
36+
thiserror = "1.0"
3637

3738
[dependencies.web-sys]
3839
version = "0.3.4"

0 commit comments

Comments
 (0)