Skip to content

Commit fd8cf65

Browse files
authored
Change ExportResult to std::result::Result (#347)
The spec changed and ExportResult no longer includes the hint about error being retriable. Since it now only distinguishes between success and error, it makes sense to use Rust's standard Result type.
1 parent 03fe982 commit fd8cf65

File tree

10 files changed

+63
-117
lines changed

10 files changed

+63
-117
lines changed

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

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@
8686
//!
8787
//! #[async_trait]
8888
//! impl HttpClient for IsahcClient {
89-
//! async fn send(&self, request: http::Request<Vec<u8>>) -> Result<ExportResult, Box<dyn Error + Send + Sync + 'static>> {
89+
//! async fn send(&self, request: http::Request<Vec<u8>>) -> ExportResult {
9090
//! let result = self.0.send_async(request).await?;
9191
//!
9292
//! if result.status().is_success() {
93-
//! Ok(ExportResult::Success)
93+
//! Ok(())
9494
//! } else {
95-
//! Ok(ExportResult::FailedNotRetryable)
95+
//! Err(result.status().as_str().into())
9696
//! }
9797
//! }
9898
//! }
@@ -279,24 +279,13 @@ impl DatadogPipelineBuilder {
279279
impl trace::SpanExporter for DatadogExporter {
280280
/// Export spans to datadog-agent
281281
async fn export(&self, batch: Vec<SpanData>) -> trace::ExportResult {
282-
let data = match self.version.encode(&self.service_name, batch) {
283-
Ok(data) => data,
284-
Err(_) => return trace::ExportResult::FailedNotRetryable,
285-
};
286-
287-
let req = match Request::builder()
282+
let data = self.version.encode(&self.service_name, batch)?;
283+
let req = Request::builder()
288284
.method(Method::POST)
289285
.uri(self.request_url.clone())
290286
.header(http::header::CONTENT_TYPE, self.version.content_type())
291-
.body(data)
292-
{
293-
Ok(req) => req,
294-
_ => return trace::ExportResult::FailedNotRetryable,
295-
};
296-
self.client
297-
.send(req)
298-
.await
299-
.unwrap_or(trace::ExportResult::FailedNotRetryable)
287+
.body(data)?;
288+
self.client.send(req).await
300289
}
301290
}
302291

opentelemetry-jaeger/src/uploader.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,16 @@ impl BatchUploader {
1818
/// Emit a jaeger batch for the given uploader
1919
pub(crate) async fn upload(&self, batch: jaeger::Batch) -> trace::ExportResult {
2020
match self {
21-
BatchUploader::Agent(client) => match client.emit_batch(batch).await {
22-
Ok(_) => trace::ExportResult::Success,
23-
// TODO determine if the error is retryable
24-
Err(_) => trace::ExportResult::FailedNotRetryable,
25-
},
21+
BatchUploader::Agent(client) => {
22+
// TODO Implement retry behaviour
23+
client.emit_batch(batch).await?;
24+
}
2625
#[cfg(feature = "collector_client")]
2726
BatchUploader::Collector(collector) => {
28-
match collector.submit_batch(batch).await {
29-
Ok(_) => trace::ExportResult::Success,
30-
// TODO determine if the error is retryable
31-
Err(_) => trace::ExportResult::FailedNotRetryable,
32-
}
27+
// TODO Implement retry behaviour
28+
collector.submit_batch(batch).await?;
3329
}
34-
}
30+
};
31+
Ok(())
3532
}
3633
}

opentelemetry-otlp/src/span.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use async_trait::async_trait;
77
use grpcio::{
88
CallOption, Channel, ChannelBuilder, ChannelCredentialsBuilder, Environment, MetadataBuilder,
99
};
10-
use opentelemetry::exporter::trace::ExportResult::{FailedNotRetryable, Success};
1110
use opentelemetry::exporter::trace::{ExportResult, SpanData, SpanExporter};
1211
use protobuf::RepeatedField;
1312
use std::collections::HashMap;
@@ -154,7 +153,7 @@ impl SpanExporter for Exporter {
154153
cached_size: Default::default(),
155154
};
156155

157-
let mut call_options: CallOption = CallOption::default().timeout(self.timeout);
156+
let mut call_options = CallOption::default().timeout(self.timeout);
158157

159158
if let Some(headers) = self.headers.clone() {
160159
let mut metadata_builder: MetadataBuilder = MetadataBuilder::new();
@@ -166,12 +165,10 @@ impl SpanExporter for Exporter {
166165
call_options = call_options.headers(metadata_builder.build());
167166
}
168167

169-
match self.trace_exporter.export_async_opt(&request, call_options) {
170-
Ok(receiver) => match receiver.await {
171-
Ok(_) => Success,
172-
Err(_) => FailedNotRetryable,
173-
},
174-
Err(_) => FailedNotRetryable,
175-
}
168+
let receiver = self
169+
.trace_exporter
170+
.export_async_opt(&request, call_options)?;
171+
receiver.await?;
172+
Ok(())
176173
}
177174
}

opentelemetry-zipkin/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,13 @@ struct IsahcClient(isahc::HttpClient);
109109

110110
#[async_trait]
111111
impl HttpClient for IsahcClient {
112-
async fn send(&self, request: http::Request<Vec<u8>>) -> Result<ExportResult, Box<dyn Error + Send + Sync + 'static>> {
112+
async fn send(&self, request: http::Request<Vec<u8>>) -> ExportResult {
113113
let result = self.0.send_async(request).await?;
114114

115115
if result.status().is_success() {
116-
Ok(ExportResult::Success)
116+
Ok(())
117117
} else {
118-
Ok(ExportResult::FailedNotRetryable)
118+
Err(result.status().as_str().into())
119119
}
120120
}
121121
}

opentelemetry-zipkin/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,13 @@
8989
//!
9090
//! #[async_trait]
9191
//! impl HttpClient for IsahcClient {
92-
//! async fn send(&self, request: http::Request<Vec<u8>>) -> Result<ExportResult, Box<dyn Error + Send + Sync + 'static>> {
92+
//! async fn send(&self, request: http::Request<Vec<u8>>) -> ExportResult {
9393
//! let result = self.0.send_async(request).await?;
9494
//!
9595
//! if result.status().is_success() {
96-
//! Ok(ExportResult::Success)
96+
//! Ok(())
9797
//! } else {
98-
//! Ok(ExportResult::FailedNotRetryable)
98+
//! Err(result.status().as_str().into())
9999
//! }
100100
//! }
101101
//! }

opentelemetry-zipkin/src/uploader.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@ impl Uploader {
2121
/// Upload spans to Zipkin
2222
pub(crate) async fn upload(&self, spans: Vec<Span>) -> ExportResult {
2323
match self {
24-
Uploader::Http(client) => client
25-
.upload(spans)
26-
.await
27-
.unwrap_or(ExportResult::FailedNotRetryable),
24+
Uploader::Http(client) => client.upload(spans).await,
2825
}
2926
}
3027
}
@@ -36,10 +33,7 @@ pub(crate) struct JsonV2Client {
3633
}
3734

3835
impl JsonV2Client {
39-
async fn upload(
40-
&self,
41-
spans: Vec<Span>,
42-
) -> Result<ExportResult, Box<dyn std::error::Error + Send + Sync + 'static>> {
36+
async fn upload(&self, spans: Vec<Span>) -> ExportResult {
4337
let req = Request::builder()
4438
.method(Method::POST)
4539
.uri(self.collector_endpoint.clone())

opentelemetry/src/api/trace/noop.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ impl NoopSpanExporter {
182182
#[async_trait]
183183
impl SpanExporter for NoopSpanExporter {
184184
async fn export(&self, _batch: Vec<SpanData>) -> ExportResult {
185-
ExportResult::Success
185+
Ok(())
186186
}
187187
}
188188

opentelemetry/src/exporter/trace/mod.rs

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,20 @@ use crate::{
44
trace::{Event, Link, SpanContext, SpanId, SpanKind, StatusCode},
55
};
66
use async_trait::async_trait;
7+
#[cfg(feature = "http")]
8+
use http::Request;
79
#[cfg(feature = "serialize")]
810
use serde::{Deserialize, Serialize};
911
#[cfg(all(feature = "http", feature = "reqwest"))]
1012
use std::convert::TryInto;
1113
use std::fmt::Debug;
1214
use std::sync::Arc;
1315
use std::time::SystemTime;
14-
#[cfg(feature = "http")]
15-
use {http::Request, std::error::Error};
1616

1717
pub mod stdout;
1818

1919
/// Describes the result of an export.
20-
#[derive(Clone, Debug, PartialEq, Eq)]
21-
pub enum ExportResult {
22-
/// Batch is successfully exported.
23-
Success,
24-
/// Batch export failed. Caller must not retry.
25-
FailedNotRetryable,
26-
/// Batch export failed transiently. Caller should record error and may retry.
27-
FailedRetryable,
28-
}
20+
pub type ExportResult = Result<(), Box<dyn std::error::Error + Send + Sync + 'static>>;
2921

3022
/// `SpanExporter` defines the interface that protocol-specific exporters must
3123
/// implement so that they can be plugged into OpenTelemetry SDK and support
@@ -75,10 +67,7 @@ pub trait SpanExporter: Send + Sync + std::fmt::Debug {
7567
#[async_trait]
7668
pub trait HttpClient: Debug + Send + Sync {
7769
/// Send a batch of spans to collectors
78-
async fn send(
79-
&self,
80-
request: Request<Vec<u8>>,
81-
) -> Result<ExportResult, Box<dyn Error + Send + Sync + 'static>>;
70+
async fn send(&self, request: Request<Vec<u8>>) -> ExportResult;
8271
}
8372

8473
/// `SpanData` contains all the information collected by a `Span` and can be used
@@ -118,44 +107,28 @@ pub struct SpanData {
118107
#[cfg(all(feature = "reqwest", feature = "http"))]
119108
#[async_trait]
120109
impl HttpClient for reqwest::Client {
121-
async fn send(
122-
&self,
123-
request: Request<Vec<u8>>,
124-
) -> Result<ExportResult, Box<dyn Error + Send + Sync + 'static>> {
125-
let result = self.execute(request.try_into()?).await?;
126-
127-
if result.status().is_success() {
128-
Ok(ExportResult::Success)
129-
} else {
130-
Ok(ExportResult::FailedNotRetryable)
131-
}
110+
async fn send(&self, request: Request<Vec<u8>>) -> ExportResult {
111+
let _result = self
112+
.execute(request.try_into()?)
113+
.await?
114+
.error_for_status()?;
115+
Ok(())
132116
}
133117
}
134118

135119
#[cfg(all(feature = "reqwest", feature = "http"))]
136120
#[async_trait]
137121
impl HttpClient for reqwest::blocking::Client {
138-
async fn send(
139-
&self,
140-
request: Request<Vec<u8>>,
141-
) -> Result<ExportResult, Box<dyn Error + Send + Sync + 'static>> {
142-
let result = self.execute(request.try_into()?)?;
143-
144-
if result.status().is_success() {
145-
Ok(ExportResult::Success)
146-
} else {
147-
Ok(ExportResult::FailedNotRetryable)
148-
}
122+
async fn send(&self, request: Request<Vec<u8>>) -> ExportResult {
123+
let _result = self.execute(request.try_into()?)?.error_for_status()?;
124+
Ok(())
149125
}
150126
}
151127

152128
#[cfg(all(feature = "surf", feature = "http"))]
153129
#[async_trait]
154130
impl HttpClient for surf::Client {
155-
async fn send(
156-
&self,
157-
request: Request<Vec<u8>>,
158-
) -> Result<ExportResult, Box<dyn Error + Send + Sync + 'static>> {
131+
async fn send(&self, request: Request<Vec<u8>>) -> ExportResult {
159132
let (parts, body) = request.into_parts();
160133
let uri = parts.uri.to_string().parse()?;
161134

@@ -165,9 +138,9 @@ impl HttpClient for surf::Client {
165138
let result = self.send(req).await?;
166139

167140
if result.status().is_success() {
168-
Ok(ExportResult::Success)
141+
Ok(())
169142
} else {
170-
Ok(ExportResult::FailedNotRetryable)
143+
Err(result.status().canonical_reason().into())
171144
}
172145
}
173146
}

opentelemetry/src/exporter/trace/stdout.rs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -129,28 +129,19 @@ where
129129
{
130130
/// Export spans to stdout
131131
async fn export(&self, batch: Vec<SpanData>) -> ExportResult {
132-
let writer = self
132+
let mut writer = self
133133
.writer
134134
.lock()
135-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()));
136-
let result = writer.and_then(|mut w| {
137-
for span in batch {
138-
if self.pretty_print {
139-
w.write_all(format!("{:#?}\n", span).as_bytes())?;
140-
} else {
141-
w.write_all(format!("{:?}\n", span).as_bytes())?;
142-
}
135+
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
136+
for span in batch {
137+
if self.pretty_print {
138+
writer.write_all(format!("{:#?}\n", span).as_bytes())?;
139+
} else {
140+
writer.write_all(format!("{:?}\n", span).as_bytes())?;
143141
}
144-
145-
Ok(())
146-
});
147-
148-
if result.is_ok() {
149-
ExportResult::Success
150-
} else {
151-
// FIXME: determine retryable io::Error types
152-
ExportResult::FailedNotRetryable
153142
}
143+
144+
Ok(())
154145
}
155146
}
156147

opentelemetry/src/sdk/trace/span_processor.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ impl SpanProcessor for SimpleSpanProcessor {
110110
}
111111

112112
fn on_end(&self, span: SpanData) {
113-
executor::block_on(self.exporter.export(vec![span]));
113+
// TODO: Surface error through global error handler
114+
let _result = executor::block_on(self.exporter.export(vec![span]));
114115
}
115116

116117
fn shutdown(&mut self) {
@@ -239,7 +240,9 @@ impl BatchSpanProcessor {
239240
let batch = spans.split_off(
240241
spans.len().saturating_sub(config.max_export_batch_size),
241242
);
242-
exporter.export(batch).await;
243+
244+
// TODO: Surface error through global error handler
245+
let _result = exporter.export(batch).await;
243246
}
244247
}
245248
// Stream has terminated or processor is shutdown, return to finish execution.
@@ -248,7 +251,9 @@ impl BatchSpanProcessor {
248251
let batch = spans.split_off(
249252
spans.len().saturating_sub(config.max_export_batch_size),
250253
);
251-
exporter.export(batch).await;
254+
255+
// TODO: Surface error through global error handler
256+
let _result = exporter.export(batch).await;
252257
}
253258
exporter.shutdown();
254259
break;

0 commit comments

Comments
 (0)