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
4 changes: 2 additions & 2 deletions opentelemetry-otlp/tests/integration_test/tests/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ mod logtests {

tokio::time::sleep(Duration::from_secs(10)).await;

assert_logs_results(test_utils::LOGS_FILE, "expected/logs.json");
let _ = assert_logs_results(test_utils::LOGS_FILE, "expected/logs.json");

Ok(())
}
Expand Down Expand Up @@ -122,7 +122,7 @@ mod logtests {
}
let _ = logger_provider.shutdown();
// tokio::time::sleep(Duration::from_secs(10)).await;
assert_logs_results(test_utils::LOGS_FILE, "expected/logs.json");
let _ = assert_logs_results(test_utils::LOGS_FILE, "expected/logs.json");

Ok(())
}
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
16 changes: 12 additions & 4 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, ShutdownError};
use crate::Resource;
use async_trait::async_trait;
#[cfg(feature = "spec_unstable_logs_enabled")]
Expand Down Expand Up @@ -81,9 +81,14 @@ pub trait LogExporter: Send + Sync + Debug {
/// A `LogResult<()>`, which is a result type indicating either a successful export (with
/// `Ok(())`) or an error (`Err(LogError)`) if the export operation failed.
///
async fn export(&self, batch: LogBatch<'_>) -> LogResult<()>;
/// Shuts down the exporter.
fn shutdown(&mut self) {}
async fn export(&self, batch: LogBatch<'_>) -> ExportResult;

/// Shuts down the exporter. This function is idempotent; calling it
/// more than once has no additional effect.
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 +101,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>;
44 changes: 40 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,32 @@
/// 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),

/// The export client failed while holding the client lock. It is not
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cijothomas I reckon this is a reasonable "API user summary" of what's happened with the mutex poisoning, and advice on dealing with it

/// possible to complete the shutdown and a retry will not help.
/// This is something that should not happen and should likely emit some diagnostic.
#[error("export client failed while holding lock; cannot retry.")]
ClientFailed(String),

/// An unexpected error occurred during shutdown.
#[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::ClientFailed(format!("Mutex poisoned during shutdown: {}", err))
}

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

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/export/trace.rs#L133-L135

Added lines #L133 - L135 were not covered by tests
}
34 changes: 29 additions & 5 deletions opentelemetry-sdk/src/logs/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@
#[error("Exporter timed out after {} seconds", .0.as_secs())]
ExportTimedOut(Duration),

/// The export client failed while holding the client lock. It is not
/// possible to complete the shutdown and a retry will not help.
/// This is something that should not happen and should likely emit some diagnostic.
#[error("export client failed while holding lock; cannot retry.")]
ClientFailed(String),

/// Processor is already shutdown
#[error("{0} already shutdown")]
AlreadyShutdown(String),

/// Mutex lock poisoning
#[error("mutex lock poisioning for {0}")]
MutexPoisoned(String),

/// Other errors propagated from log SDK that weren't covered above.
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
Expand Down Expand Up @@ -54,10 +56,32 @@

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

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

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/logs/error.rs#L59

Added line #L59 was not covered by tests
}
}

/// Wrap type for string
#[derive(Error, Debug)]
#[error("{0}")]
struct Custom(String);

/// Errors returned during shutdown
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ShutdownError {
/// The export client failed while holding the client lock. It is not
/// possible to complete the shutdown and a retry will not help.
/// This is something that should not happen and should likely emit some diagnostic.
#[error("export client failed while holding lock; cannot retry.")]
ClientFailed(String),

/// 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::ClientFailed(format!("Mutex poisoned during shutdown: {}", err))
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 think wrapping up the formatted inner error is plenty of context here given the narrow failure mode. I also considered wrapping up Box<Err> , but I think this is 1/ confusing in the interface and 2/ not at all actionable.

There's some good stuff on canonical's rust best practices doc on this stuff

}

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

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/logs/error.rs#L84-L86

Added lines #L84 - L86 were not covered by tests
}
4 changes: 2 additions & 2 deletions opentelemetry-sdk/src/logs/log_emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@
// which is non-actionable by the user
match err {
// specific handling for mutex poisioning
LogError::MutexPoisoned(_) => {
LogError::ClientFailed(_) => {
otel_debug!(
name: "LoggerProvider.Drop.ShutdownMutexPoisoned",
name: "LoggerProvider.Drop.ShutdownClientFailed",

Check warning on line 146 in opentelemetry-sdk/src/logs/log_emitter.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/logs/log_emitter.rs#L146

Added line #L146 was not covered by tests
);
}
_ => {
Expand Down
21 changes: 14 additions & 7 deletions opentelemetry-sdk/src/logs/log_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@
let result = self
.exporter
.lock()
.map_err(|_| LogError::MutexPoisoned("SimpleLogProcessor".into()))
.map_err(|_| LogError::ClientFailed("SimpleLogProcessor".into()))
.and_then(|exporter| {
let log_tuple = &[(record as &LogRecord, instrumentation)];
futures_executor::block_on(exporter.export(LogBatch::new(log_tuple)))
});
// Handle errors with specific static names
match result {
Err(LogError::MutexPoisoned(_)) => {
Err(LogError::ClientFailed(_)) => {
// logging as debug as this is not a user error
otel_debug!(
name: "SimpleLogProcessor.Emit.MutexPoisoning",
Expand All @@ -144,10 +144,13 @@
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()))
// Failing to get the mutex means the export client failed whilst holding it
Err(LogError::ClientFailed("SimpleLogProcessor".into()))

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

View check run for this annotation

Codecov / codecov/patch

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

Added line #L153 was not covered by tests
}
}

Expand Down Expand Up @@ -650,7 +653,13 @@
)
.await;

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

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

View check run for this annotation

Codecov / codecov/patch

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

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

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

View check run for this annotation

Codecov / codecov/patch

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

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

if let Err(send_error) = ch.send(result) {
otel_debug!(
Expand Down Expand Up @@ -934,8 +943,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
Loading
Loading