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

chore: modify LogExporter and TraceExporter interfaces to support returning failure #2381

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
3 changes: 1 addition & 2 deletions opentelemetry-otlp/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Changelog

## vNext

- Bump msrv to 1.75.0.

- `OtlpHttpClient.shutdown` `TonicLogsClient.shutdown`, and `TonicTracesClient.shutdown` now explicitly return a result.

## 0.27.0

Expand Down
7 changes: 4 additions & 3 deletions opentelemetry-otlp/src/exporter/http/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use async_trait::async_trait;
use http::{header::CONTENT_TYPE, Method};
use opentelemetry::otel_debug;
use opentelemetry_sdk::export::logs::{LogBatch, LogExporter};
use opentelemetry_sdk::export::logs::{LogBatch, LogExporter, ShutdownResult};
use opentelemetry_sdk::logs::{LogError, LogResult};

use super::OtlpHttpClient;
Expand Down Expand Up @@ -49,8 +49,9 @@
Ok(())
}

fn shutdown(&mut self) {
let _ = self.client.lock().map(|mut c| c.take());
fn shutdown(&mut self) -> ShutdownResult {
let _ = self.client.lock()?.take();
scottgerring marked this conversation as resolved.
Show resolved Hide resolved
Ok(())

Check warning on line 54 in opentelemetry-otlp/src/exporter/http/logs.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-otlp/src/exporter/http/logs.rs#L52-L54

Added lines #L52 - L54 were not covered by tests
}

fn set_resource(&mut self, resource: &opentelemetry_sdk::Resource) {
Expand Down
10 changes: 6 additions & 4 deletions opentelemetry-otlp/src/exporter/http/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

use futures_core::future::BoxFuture;
use http::{header::CONTENT_TYPE, Method};
use opentelemetry::{otel_debug, trace::TraceError};
use opentelemetry_sdk::export::trace::{ExportResult, SpanData, SpanExporter};
use opentelemetry::otel_debug;
use opentelemetry::trace::TraceError;
use opentelemetry_sdk::export::trace::{ExportResult, ShutdownResult, SpanData, SpanExporter};

use super::OtlpHttpClient;

Expand Down Expand Up @@ -64,8 +65,9 @@
})
}

fn shutdown(&mut self) {
let _ = self.client.lock().map(|mut c| c.take());
fn shutdown(&mut self) -> ShutdownResult {
let _ = self.client.lock()?.take();
scottgerring marked this conversation as resolved.
Show resolved Hide resolved
Ok(())

Check warning on line 70 in opentelemetry-otlp/src/exporter/http/trace.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-otlp/src/exporter/http/trace.rs#L68-L70

Added lines #L68 - L70 were not covered by tests
}

fn set_resource(&mut self, resource: &opentelemetry_sdk::Resource) {
Expand Down
5 changes: 3 additions & 2 deletions opentelemetry-otlp/src/exporter/tonic/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use opentelemetry_proto::tonic::collector::logs::v1::{
logs_service_client::LogsServiceClient, ExportLogsServiceRequest,
};
use opentelemetry_sdk::export::logs::{LogBatch, LogExporter};
use opentelemetry_sdk::export::logs::{LogBatch, LogExporter, ShutdownResult};
use opentelemetry_sdk::logs::{LogError, LogResult};
use tonic::{codegen::CompressionEncoding, service::Interceptor, transport::Channel, Request};

Expand Down Expand Up @@ -89,8 +89,9 @@
Ok(())
}

fn shutdown(&mut self) {
fn shutdown(&mut self) -> ShutdownResult {

Check warning on line 92 in opentelemetry-otlp/src/exporter/tonic/logs.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-otlp/src/exporter/tonic/logs.rs#L92

Added line #L92 was not covered by tests
let _ = self.inner.take();
Ok(())

Check warning on line 94 in opentelemetry-otlp/src/exporter/tonic/logs.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-otlp/src/exporter/tonic/logs.rs#L94

Added line #L94 was not covered by tests
}

fn set_resource(&mut self, resource: &opentelemetry_sdk::Resource) {
Expand Down
8 changes: 4 additions & 4 deletions opentelemetry-otlp/src/exporter/tonic/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
use opentelemetry_proto::tonic::collector::trace::v1::{
trace_service_client::TraceServiceClient, ExportTraceServiceRequest,
};
use opentelemetry_sdk::export::trace::{ExportResult, SpanData, SpanExporter};
use tonic::{codegen::CompressionEncoding, service::Interceptor, transport::Channel, Request};

use opentelemetry_proto::transform::trace::tonic::group_spans_by_resource_and_scope;
use opentelemetry_sdk::export::trace::{ExportResult, ShutdownResult, SpanData, SpanExporter};
use tonic::{codegen::CompressionEncoding, service::Interceptor, transport::Channel, Request};

use super::BoxInterceptor;

Expand Down Expand Up @@ -92,8 +91,9 @@
})
}

fn shutdown(&mut self) {
fn shutdown(&mut self) -> ShutdownResult {

Check warning on line 94 in opentelemetry-otlp/src/exporter/tonic/trace.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-otlp/src/exporter/tonic/trace.rs#L94

Added line #L94 was not covered by tests
let _ = self.inner.take();
Ok(())

Check warning on line 96 in opentelemetry-otlp/src/exporter/tonic/trace.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-otlp/src/exporter/tonic/trace.rs#L96

Added line #L96 was not covered by tests
}

fn set_resource(&mut self, resource: &opentelemetry_sdk::Resource) {
Expand Down
7 changes: 7 additions & 0 deletions opentelemetry-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## vNext

- If you are an exporter author, the trait functions `LogExporter.shutdown` and `TraceExporter.shutdown` must now return a result. Note that implementing shutdown is optional as the trait provides a default implementation that returns Ok(()).

- The trait functions `LogExporter.shutdown` and `TraceExporter.shutdown` now explicitly return a result. The
semantics of the method have not changed, but you will have a new lint encouraging you to consume these results.

- *Breaking(Affects custom metric exporter authors only)* `start_time` and `time` is moved from DataPoints to aggregations (Sum, Gauge, Histogram, ExpoHistogram) see [#2377](https://github.com/open-telemetry/opentelemetry-rust/pull/2377) and [#2411](https://github.com/open-telemetry/opentelemetry-rust/pull/2411), to reduce memory.

- *Breaking* `start_time` is no longer optional for `Sum` aggregation, see [#2367](https://github.com/open-telemetry/opentelemetry-rust/pull/2367), but is still optional for `Gauge` aggregation see [#2389](https://github.com/open-telemetry/opentelemetry-rust/pull/2389).
Expand All @@ -14,6 +19,7 @@
[#2338](https://github.com/open-telemetry/opentelemetry-rust/pull/2338)
- `ResourceDetector.detect()` no longer supports timeout option.
- `opentelemetry::global::shutdown_tracer_provider()` Removed from the API, should now use `tracer_provider.shutdown()` see [#2369](https://github.com/open-telemetry/opentelemetry-rust/pull/2369) for a migration example. "Tracer provider" is cheaply cloneable, so users are encouraged to set a clone of it as the global (ex: `global::set_tracer_provider(provider.clone()))`, so that instrumentations and other components can obtain tracers from `global::tracer()`. The tracer_provider must be kept around to call shutdown on it at the end of application (ex: `tracer_provider.shutdown()`)

- *Feature*: Add `ResourceBuilder` for an easy way to create new `Resource`s
- *Breaking*: Remove `Resource::{new,empty,from_detectors,new_with_defaults,from_schema_url,merge,default}` from public api. To create Resources you should only use `Resource::builder()` or `Resource::builder_empty()`. See [#2322](https://github.com/open-telemetry/opentelemetry-rust/pull/2322) for a migration guide.
Example Usage:
Expand Down Expand Up @@ -156,6 +162,7 @@ metadata, a feature introduced in version 0.1.40. [#2418](https://github.com/ope
- Continue enabling one of the async runtime feature flags: `rt-tokio`,
`rt-tokio-current-thread`, or `rt-async-std`.


## 0.27.1

Released 2024-Nov-27
Expand Down
10 changes: 8 additions & 2 deletions opentelemetry-sdk/src/export/logs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Log exporters
use crate::logs::LogRecord;
use crate::logs::{LogError, LogResult};
use crate::logs::{LogError, LogResult, ShutdownError};
use crate::Resource;
use async_trait::async_trait;
#[cfg(feature = "spec_unstable_logs_enabled")]
Expand Down Expand Up @@ -83,7 +83,10 @@ pub trait LogExporter: Send + Sync + Debug {
///
async fn export(&self, batch: LogBatch<'_>) -> LogResult<()>;
/// Shuts down the exporter.
fn shutdown(&mut self) {}
fn shutdown(&mut self) -> ShutdownResult {
Ok(())
}

#[cfg(feature = "spec_unstable_logs_enabled")]
/// Chek if logs are enabled.
fn event_enabled(&self, _level: Severity, _target: &str, _name: &str) -> bool {
Expand All @@ -96,3 +99,6 @@ pub trait LogExporter: Send + Sync + Debug {

/// Describes the result of an export.
pub type ExportResult = Result<(), LogError>;

/// Describes the result of a shutdown in the log SDK.
pub type ShutdownResult = Result<(), ShutdownError>;
43 changes: 39 additions & 4 deletions opentelemetry-sdk/src/export/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@
use opentelemetry::{InstrumentationScope, KeyValue};
use std::borrow::Cow;
use std::fmt::Debug;
use std::time::SystemTime;
use std::sync::PoisonError;
use std::time::{Duration, SystemTime};
use thiserror::Error;

/// Describes the result of an export.
/// Results of an export operation
pub type ExportResult = Result<(), TraceError>;

/// Result of a shutdown operation
pub type ShutdownResult = Result<(), ShutdownError>;

/// `SpanExporter` defines the interface that protocol-specific exporters must
/// implement so that they can be plugged into OpenTelemetry SDK and support
/// sending of telemetry data.
Expand All @@ -30,7 +35,7 @@
///
/// Any retry logic that is required by the exporter is the responsibility
/// of the exporter.
fn export(&mut self, batch: Vec<SpanData>) -> BoxFuture<'static, ExportResult>;
fn export(&mut self, batch: Vec<SpanData>) -> BoxFuture<'static, Result<(), TraceError>>;

/// Shuts down the exporter. Called when SDK is shut down. This is an
/// opportunity for exporter to do any cleanup required.
Expand All @@ -43,7 +48,9 @@
/// flush the data and the destination is unavailable). SDK authors
/// can decide if they want to make the shutdown timeout
/// configurable.
fn shutdown(&mut self) {}
fn shutdown(&mut self) -> ShutdownResult {
Ok(())
}

/// This is a hint to ensure that the export of any Spans the exporter
/// has received prior to the call to this function SHOULD be completed
Expand Down Expand Up @@ -98,3 +105,31 @@
/// Instrumentation scope that produced this span
pub instrumentation_scope: InstrumentationScope,
}

/// Errors returned by shutdown operations in the Export API.
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ShutdownError {
/// The exporter has already been shut down.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still unsure of this....I can understand that a Provider's shutdown method, if invoked more than once, can return AlreadyShutdown error. How would an Exporter's shutdown be invoked more than once, since provider protects the processor/exporter from entering that situation?

I am not even sure if processor/exporter should even have a variable like is_shutdown at all.. If its shutdown is invoked, it'll kill the transports etc. any further attempt to export will result in failure naturally as transports are killed.

(Sorry not really part of this PR, but this is something that I need some time to think through....)

Copy link
Member

@lalitb lalitb Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not even sure if processor/exporter should even have a variable like is_shutdown at all.. If its shutdown is invoked, it'll kill the transports etc. any further attempt to export will result in failure naturally as transports are killed.

I feel processor should have this flag. It can't assume how the exporters are implemented. Maybe exporter's shutdown methods are just no-op, and in that case the export may continue happening even after shutdown is invoked, if the processor doesn't have is_shutdown safeguard.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the need for processor to have the flag? If shutdown was already signaled, then no further shutdown signal will ever arrive at the LogProcessor, as the Provider takes care of that, and provider own Processors.

How would log processor ever get a 2nd shutdown call? Or how does it ever get an emit() call after shutdown is done?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would log processor ever get a 2nd shutdown call? Or how does it ever get an emit() call after shutdown is done?

Yes correct, is_shutdown at provider level will take care of that. I missed that. However, logger::emit() as of now doesn't check for the provider flag, which needs to be fixed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

raised a PR to discuss this further - #2462

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like it'd be cool if shutdown was idempotent - you call it, it shuts down, you call it again, it no-ops.

you call it again, it no-ops.

This maybe okay. But if a user is calling shutdown more than once, it indicates there have an bug in the way they orchestrate telemetry pipelines, so isn't it best to let them know about it...?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is logging it sufficient ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its debatable I guess....We can technically make almost every return type go away in favor of logging. So need to find a balance where do we resort to logging vs explicit-return-type.

Related: Otel .NET decided to specialy handle emit logs after shutdown, by printing these nice message only in StdOut exporter:
https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs#L39-L42

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reckon there’s a clear line there between errors that actually reflect some failure of the system, and errors that have no impact and are just hinting that the caller has done something funny.

By way of example a flush that fails become the connections gone is very different to “probably you didn’t mean to call this twice”.

That stdout error one is interesting. Is there a story there ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also and regardless - it feels like something we should have a consistent view on - when to error, when not to - that we can point at apply uniformly. That consistency is maybe even more important than what the policy itself is 🤷‍♂️

#[error("Shutdown already performed")]
AlreadyShutdown,

/// Shutdown timed out before completing.
#[error("Shutdown timed out after {0:?}")]
Timeout(Duration),

/// An unexpected error occurred during shutdown.
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
}

/// Custom error wrapper for string messages.
#[derive(Error, Debug)]
#[error("{0}")]
struct CustomError(String);

impl<T> From<PoisonError<T>> for ShutdownError {
fn from(err: PoisonError<T>) -> Self {
ShutdownError::Other(Box::new(CustomError(err.to_string())))
}

Check warning on line 134 in opentelemetry-sdk/src/export/trace.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/export/trace.rs#L132-L134

Added lines #L132 - L134 were not covered by tests
}
19 changes: 19 additions & 0 deletions opentelemetry-sdk/src/logs/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,22 @@
#[derive(Error, Debug)]
#[error("{0}")]
struct Custom(String);

/// Errors returned during shutdown
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ShutdownError {
/// Mutex lock poisoning
#[error("mutex lock poisioning for {0}")]
MutexPoisoned(String),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unsure if we should make these public.. There are strictly internal details, and a mutex poison is not user actionable at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were public before in the old type; but I agree with you!
I can hide it behind the GenericError or something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry if I am missing some discussion - why do we need to have new error enum for shutdown. Can't we reuse the LogError.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we keep one uber-error and the caller wants to handle it, they are forced to handle variants that have nothing to do with the operation they are calling


/// Other errors propagated from log SDK that weren't covered above.
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
}

impl<T> From<PoisonError<T>> for ShutdownError {
fn from(err: PoisonError<T>) -> Self {
ShutdownError::Other(err.to_string().into())
}

Check warning on line 81 in opentelemetry-sdk/src/logs/error.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/logs/error.rs#L79-L81

Added lines #L79 - L81 were not covered by tests
}
14 changes: 10 additions & 4 deletions opentelemetry-sdk/src/logs/log_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@
self.is_shutdown
.store(true, std::sync::atomic::Ordering::Relaxed);
if let Ok(mut exporter) = self.exporter.lock() {
exporter.shutdown();
exporter
.shutdown()
.map_err(|e| LogError::Other(Box::new(e)))?;
Ok(())
} else {
Err(LogError::MutexPoisoned("SimpleLogProcessor".into()))
Expand Down Expand Up @@ -650,7 +652,13 @@
)
.await;

exporter.shutdown();
if let Err(e) = exporter.shutdown() {
otel_warn!(

Check warning on line 656 in opentelemetry-sdk/src/logs/log_processor.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/logs/log_processor.rs#L655-L656

Added lines #L655 - L656 were not covered by tests
name: "BatchLogProcessor.Shutdown.Failed",
message = "failed shutting down exporter cleanly",
error = format!("{:?}", e)

Check warning on line 659 in opentelemetry-sdk/src/logs/log_processor.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/logs/log_processor.rs#L659

Added line #L659 was not covered by tests
);
};

Check warning on line 661 in opentelemetry-sdk/src/logs/log_processor.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/logs/log_processor.rs#L661

Added line #L661 was not covered by tests

if let Err(send_error) = ch.send(result) {
otel_debug!(
Expand Down Expand Up @@ -934,8 +942,6 @@
Ok(())
}

fn shutdown(&mut self) {}

fn set_resource(&mut self, resource: &Resource) {
self.resource
.lock()
Expand Down
2 changes: 1 addition & 1 deletion opentelemetry-sdk/src/logs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod log_emitter;
mod log_processor;
pub(crate) mod record;

pub use error::{LogError, LogResult};
pub use error::{LogError, LogResult, ShutdownError};
pub use log_emitter::{Builder, Logger, LoggerProvider};
pub use log_processor::{
BatchConfig, BatchConfigBuilder, BatchLogProcessor, BatchLogProcessorBuilder, LogProcessor,
Expand Down
5 changes: 3 additions & 2 deletions opentelemetry-sdk/src/testing/logs/in_memory_exporter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::export::logs::{LogBatch, LogExporter};
use crate::logs::LogRecord;
use crate::logs::{LogError, LogResult};
use crate::logs::{LogRecord, ShutdownError};
use crate::Resource;
use async_trait::async_trait;
use opentelemetry::InstrumentationScope;
Expand Down Expand Up @@ -195,10 +195,11 @@ impl LogExporter for InMemoryLogExporter {
Ok(())
}

fn shutdown(&mut self) {
fn shutdown(&mut self) -> Result<(), ShutdownError> {
if self.should_reset_on_shutdown {
self.reset();
}
Ok(())
}

fn set_resource(&mut self, resource: &Resource) {
Expand Down
7 changes: 4 additions & 3 deletions opentelemetry-sdk/src/testing/trace/in_memory_exporter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::export::trace::{ExportResult, SpanData, SpanExporter};
use crate::export::trace::{ExportResult, ShutdownResult, SpanData, SpanExporter};
use crate::resource::Resource;
use futures_util::future::BoxFuture;
use opentelemetry::trace::{TraceError, TraceResult};
Expand Down Expand Up @@ -142,8 +142,9 @@ impl SpanExporter for InMemorySpanExporter {
Box::pin(std::future::ready(Ok(())))
}

fn shutdown(&mut self) {
self.reset()
fn shutdown(&mut self) -> ShutdownResult {
self.reset();
Ok(())
}

fn set_resource(&mut self, resource: &Resource) {
Expand Down
8 changes: 6 additions & 2 deletions opentelemetry-sdk/src/testing/trace/span_exporters.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::export::trace::{ShutdownError, ShutdownResult};
use crate::{
export::trace::{ExportResult, SpanData, SpanExporter},
trace::{SpanEvents, SpanLinks},
Expand Down Expand Up @@ -53,8 +54,11 @@ impl SpanExporter for TokioSpanExporter {
Box::pin(std::future::ready(Ok(())))
}

fn shutdown(&mut self) {
self.tx_shutdown.send(()).unwrap();
fn shutdown(&mut self) -> ShutdownResult {
self.tx_shutdown
.send(())
.map_err::<ShutdownError, _>(|err| ShutdownError::Other(Box::new(err)))?;
Ok(())
}
}

Expand Down
19 changes: 10 additions & 9 deletions opentelemetry-sdk/src/trace/span_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,10 @@
}

fn shutdown(&self) -> TraceResult<()> {
Copy link
Contributor Author

@scottgerring scottgerring Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should (in another issue!) chase this distinction between TraceError and ShutdownError further down the rabbit hole. For the same reasons I don't think it makes sense to use an über-error in the exporter trait

if let Ok(mut exporter) = self.exporter.lock() {
exporter.shutdown();
Ok(())
} else {
Err(TraceError::Other(
"SimpleSpanProcessor mutex poison at shutdown".into(),
))
}
self.exporter
.lock()?
.shutdown()
.map_err(|e| TraceError::Other(Box::new(e)))
}

fn set_resource(&mut self, resource: &Resource) {
Expand Down Expand Up @@ -432,7 +428,12 @@
// Stream has terminated or processor is shutdown, return to finish execution.
BatchMessage::Shutdown(ch) => {
self.flush(Some(ch)).await;
self.exporter.shutdown();
if let Err(e) = self.exporter.shutdown() {
otel_warn!(

Check warning on line 432 in opentelemetry-sdk/src/trace/span_processor.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/trace/span_processor.rs#L432

Added line #L432 was not covered by tests
name: "SpanProcessor.Shutdown.Failed",
message = "failed shutting down exporter cleanly",
error = format!("{:?}", e));

Check warning on line 435 in opentelemetry-sdk/src/trace/span_processor.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/trace/span_processor.rs#L435

Added line #L435 was not covered by tests
}
return false;
}
// propagate the resource
Expand Down
3 changes: 3 additions & 0 deletions opentelemetry-stdout/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
- Bump msrv to 1.75.0.
- *Breaking* time fields, `StartTime` and `EndTime` is printed on aggregation (Sum, Gauge, Histogram, ExpoHistogram) with 2 tabs, previously it was on aggregation data point, with 3 tabs, see [#2377](https://github.com/open-telemetry/opentelemetry-rust/pull/2377) and [#2411](https://github.com/open-telemetry/opentelemetry-rust/pull/2411).

- `LogExporter.shutdown` and `SpanExporter.shutdown` now explicitly return a result


## 0.27.0

Released 2024-Nov-11
Expand Down
Loading
Loading