diff --git a/opentelemetry-otlp/CHANGELOG.md b/opentelemetry-otlp/CHANGELOG.md index dfbd03926c..347a759004 100644 --- a/opentelemetry-otlp/CHANGELOG.md +++ b/opentelemetry-otlp/CHANGELOG.md @@ -17,6 +17,11 @@ [#1568]: https://github.com/open-telemetry/opentelemetry-rust/pull/1568 +### Changed + - **Breaking** Remove global provider for Logs [#1691](https://github.com/open-telemetry/opentelemetry-rust/pull/1691/) + - The method OtlpLogPipeline::install_simple() and OtlpLogPipeline::install_batch() now return `LoggerProvider` instead of + `Logger`. Refer to the [basic-otlp](https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry-otlp/examples/basic-otlp/src/main.rs) and [basic-otlp-http](https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry-otlp/examples/basic-otlp-http/src/main.rs) examples for how to initialize OTLP Log Exporter to use with OpenTelemetryLogBridge and OpenTelemetryTracingBridge respectively. + ## v0.15.0 ### Added diff --git a/opentelemetry-otlp/examples/basic-otlp-http/src/main.rs b/opentelemetry-otlp/examples/basic-otlp-http/src/main.rs index f06ba1d9de..91af4715fa 100644 --- a/opentelemetry-otlp/examples/basic-otlp-http/src/main.rs +++ b/opentelemetry-otlp/examples/basic-otlp-http/src/main.rs @@ -15,7 +15,7 @@ use std::error::Error; use tracing::info; use tracing_subscriber::prelude::*; -fn init_logs() -> Result { +fn init_logs() -> Result { let service_name = env!("CARGO_BIN_NAME"); opentelemetry_otlp::new_pipeline() .logging() @@ -76,13 +76,12 @@ static COMMON_ATTRIBUTES: Lazy<[KeyValue; 4]> = Lazy::new(|| { async fn main() -> Result<(), Box> { let _ = init_tracer()?; let _ = init_metrics()?; - let _ = init_logs(); + // Opentelemetry will not provide a global API to manage the logger provider. Application users must manage the lifecycle of the logger provider on their own. Dropping logger providers will disable log emitting. + let logger_provider = init_logs().unwrap(); let tracer = global::tracer("ex.com/basic"); let meter = global::meter("ex.com/basic"); - // configure the global logger to use our opentelemetry logger - let logger_provider = opentelemetry::global::logger_provider(); let layer = OpenTelemetryTracingBridge::new(&logger_provider); tracing_subscriber::registry().with(layer).init(); @@ -108,7 +107,7 @@ async fn main() -> Result<(), Box> { histogram.record(5.5, COMMON_ATTRIBUTES.as_ref()); global::shutdown_tracer_provider(); - global::shutdown_logger_provider(); + logger_provider.shutdown(); global::shutdown_meter_provider(); Ok(()) diff --git a/opentelemetry-otlp/examples/basic-otlp/src/main.rs b/opentelemetry-otlp/examples/basic-otlp/src/main.rs index 4f4320cab9..02e1cb3449 100644 --- a/opentelemetry-otlp/examples/basic-otlp/src/main.rs +++ b/opentelemetry-otlp/examples/basic-otlp/src/main.rs @@ -54,7 +54,7 @@ fn init_metrics() -> Result<(), MetricsError> { } } -fn init_logs() -> Result { +fn init_logs() -> Result { let service_name = env!("CARGO_BIN_NAME"); opentelemetry_otlp::new_pipeline() .logging() @@ -93,10 +93,7 @@ async fn main() -> Result<(), Box> { let _ = init_metrics()?; // Initialize logs, which sets the global loggerprovider. - let _ = init_logs(); - - // Retrieve the global LoggerProvider. - let logger_provider = global::logger_provider(); + let logger_provider = init_logs().unwrap(); // Create a new OpenTelemetryLogBridge using the above LoggerProvider. let otel_log_appender = OpenTelemetryLogBridge::new(&logger_provider); @@ -141,7 +138,7 @@ async fn main() -> Result<(), Box> { info!(target: "my-target", "hello from {}. My price is {}", "apple", 1.99); global::shutdown_tracer_provider(); - global::shutdown_logger_provider(); + logger_provider.shutdown(); global::shutdown_meter_provider(); Ok(()) diff --git a/opentelemetry-otlp/src/logs.rs b/opentelemetry-otlp/src/logs.rs index d6e346bf61..43045a7742 100644 --- a/opentelemetry-otlp/src/logs.rs +++ b/opentelemetry-otlp/src/logs.rs @@ -10,12 +10,10 @@ use crate::exporter::http::HttpExporterBuilder; use crate::{NoExporterConfig, OtlpPipeline}; use async_trait::async_trait; -use std::{borrow::Cow, fmt::Debug}; +use std::fmt::Debug; + +use opentelemetry::logs::LogError; -use opentelemetry::{ - global, - logs::{LogError, LoggerProvider}, -}; use opentelemetry_sdk::{export::logs::LogData, runtime::RuntimeChannel}; /// Compression algorithm to use, defaults to none. @@ -147,7 +145,7 @@ impl OtlpLogPipeline { /// Returns a [`Logger`] with the name `opentelemetry-otlp` and the current crate version. /// /// [`Logger`]: opentelemetry_sdk::logs::Logger - pub fn install_simple(self) -> Result { + pub fn install_simple(self) -> Result { Ok(build_simple_with_exporter( self.exporter_builder.build_log_exporter()?, self.log_config, @@ -163,7 +161,7 @@ impl OtlpLogPipeline { pub fn install_batch( self, runtime: R, - ) -> Result { + ) -> Result { Ok(build_batch_with_exporter( self.exporter_builder.build_log_exporter()?, self.log_config, @@ -176,19 +174,14 @@ impl OtlpLogPipeline { fn build_simple_with_exporter( exporter: LogExporter, log_config: Option, -) -> opentelemetry_sdk::logs::Logger { +) -> opentelemetry_sdk::logs::LoggerProvider { let mut provider_builder = opentelemetry_sdk::logs::LoggerProvider::builder().with_simple_exporter(exporter); if let Some(config) = log_config { provider_builder = provider_builder.with_config(config); } - let provider = provider_builder.build(); - let logger = provider - .logger_builder(Cow::Borrowed("opentelemetry-otlp")) - .with_version(Cow::Borrowed(env!("CARGO_PKG_VERSION"))) - .build(); - let _ = global::set_logger_provider(provider); - logger + // logger would be created in the tracing appender + provider_builder.build() } fn build_batch_with_exporter( @@ -196,7 +189,7 @@ fn build_batch_with_exporter( log_config: Option, runtime: R, batch_config: Option, -) -> opentelemetry_sdk::logs::Logger { +) -> opentelemetry_sdk::logs::LoggerProvider { let mut provider_builder = opentelemetry_sdk::logs::LoggerProvider::builder(); let batch_processor = opentelemetry_sdk::logs::BatchLogProcessor::builder(exporter, runtime) .with_batch_config(batch_config.unwrap_or_default()) @@ -206,11 +199,6 @@ fn build_batch_with_exporter( if let Some(config) = log_config { provider_builder = provider_builder.with_config(config); } - let provider = provider_builder.build(); - let logger = provider - .logger_builder(Cow::Borrowed("opentelemetry-otlp")) - .with_version(Cow::Borrowed(env!("CARGO_PKG_VERSION"))) - .build(); - let _ = global::set_logger_provider(provider); - logger + // logger would be created in the tracing appender + provider_builder.build() } diff --git a/opentelemetry-sdk/src/logs/log_emitter.rs b/opentelemetry-sdk/src/logs/log_emitter.rs index 503fcca367..1fb650b965 100644 --- a/opentelemetry-sdk/src/logs/log_emitter.rs +++ b/opentelemetry-sdk/src/logs/log_emitter.rs @@ -266,8 +266,8 @@ mod tests { use crate::Resource; use super::*; - use opentelemetry::global::{logger, set_logger_provider, shutdown_logger_provider}; - use opentelemetry::logs::{Logger, LoggerProvider as _}; + use opentelemetry::logs::Logger; + use opentelemetry::logs::LoggerProvider as _; use opentelemetry::{Key, KeyValue, Value}; use std::fmt::{Debug, Formatter}; use std::sync::atomic::AtomicU64; @@ -481,74 +481,27 @@ mod tests { // Arrange let shutdown_called = Arc::new(Mutex::new(false)); let flush_called = Arc::new(Mutex::new(false)); - let signal_to_end = Arc::new(Mutex::new(false)); - let signal_to_thread_started = Arc::new(Mutex::new(false)); let logger_provider = LoggerProvider::builder() .with_log_processor(LazyLogProcessor::new( shutdown_called.clone(), flush_called.clone(), )) .build(); - set_logger_provider(logger_provider); + //set_logger_provider(logger_provider); + let logger1 = logger_provider.logger("test-logger1"); + let logger2 = logger_provider.logger("test-logger2"); - // Act - let logger1 = logger("test-logger1"); - let logger2 = logger("test-logger2"); + // Acts logger1.emit(LogRecord::default()); logger2.emit(LogRecord::default()); - let signal_to_end_clone = signal_to_end.clone(); - let signal_to_thread_started_clone = signal_to_thread_started.clone(); - - let handle = thread::spawn(move || { - let logger3 = logger("test-logger3"); - loop { - // signal the main thread that this thread has started. - *signal_to_thread_started_clone.lock().unwrap() = true; - logger3.emit(LogRecord::default()); - if *signal_to_end_clone.lock().unwrap() { - break; - } - } - }); - - // wait for the spawned thread to start before calling shutdown This is - // very important - if shutdown is called before the spawned thread - // obtains its logger, then the logger will be no-op one, and the test - // will pass, but it will not be testing the intended scenario. - while !*signal_to_thread_started.lock().unwrap() { - thread::sleep(std::time::Duration::from_millis(10)); - } - - // Intentionally *not* calling shutdown/flush on the provider, but - // instead relying on shutdown_logger_provider which causes the global - // provider to be dropped, leading to the sdk logger provider's drop to - // be called, which is expected to call shutdown on processors. - shutdown_logger_provider(); + // explicitly calling shutdown on logger_provider. This will + // indeed do the shutdown, even if there are loggers still alive. + logger_provider.shutdown(); // Assert - // shutdown_logger_provider is necessary but not sufficient, as loggers - // hold on to the the provider (via inner provider clones). - assert!(!*shutdown_called.lock().unwrap()); - - // flush is never called by the sdk. - assert!(!*flush_called.lock().unwrap()); - - // Drop one of the logger. Not enough! - drop(logger1); - assert!(!*shutdown_called.lock().unwrap()); - - // drop logger2, which is the only remaining logger in this thread. - // Still not enough! - drop(logger2); - assert!(!*shutdown_called.lock().unwrap()); - - // now signal the spawned thread to end, which causes it to drop its - // logger. Since that is the last logger, the provider (inner provider) - // is finally dropped, triggering shutdown - *signal_to_end.lock().unwrap() = true; - handle.join().unwrap(); + // shutdown is called. assert!(*shutdown_called.lock().unwrap()); // flush is never called by the sdk. diff --git a/opentelemetry/CHANGELOG.md b/opentelemetry/CHANGELOG.md index e593fcbfa8..380daa3671 100644 --- a/opentelemetry/CHANGELOG.md +++ b/opentelemetry/CHANGELOG.md @@ -10,6 +10,16 @@ ### Removed - Remove `urlencoding` crate dependency. [#1613](https://github.com/open-telemetry/opentelemetry-rust/pull/1613) +- Remove global providers for Logs [$1691](https://github.com/open-telemetry/opentelemetry-rust/pull/1691) + LoggerProviders are not meant for end users to get loggers from. It is only required for the log bridges. + Below global constructs for the logs are removed from API: + - opentelemetry::global::logger + - opentelemetry::global::set_logger_provider + - opentelemetry::global::shutdown_logger_provider + - opentelemetry::global::logger_provider + - opentelemetry::global::GlobalLoggerProvider + - opentelemetry::global::ObjectSafeLoggerProvider + For creating appenders using Logging bridge API, refer to the opentelemetry-tracing-appender [example](https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry-appender-tracing/examples/basic.rs) ### Changed diff --git a/opentelemetry/Cargo.toml b/opentelemetry/Cargo.toml index 7c5de3b6bc..f531dbb81e 100644 --- a/opentelemetry/Cargo.toml +++ b/opentelemetry/Cargo.toml @@ -40,7 +40,7 @@ logs_level_enabled = ["logs"] otel_unstable = [] [dev-dependencies] -opentelemetry_sdk = { path = "../opentelemetry-sdk" } # for documentation tests +opentelemetry_sdk = { path = "../opentelemetry-sdk", features = ["logs_level_enabled"]} # for documentation tests criterion = { version = "0.3" } [[bench]] diff --git a/opentelemetry/src/global/logs.rs b/opentelemetry/src/global/logs.rs deleted file mode 100644 index e2b53f43ee..0000000000 --- a/opentelemetry/src/global/logs.rs +++ /dev/null @@ -1,136 +0,0 @@ -use std::{ - borrow::Cow, - fmt, mem, - sync::{Arc, RwLock}, -}; - -use once_cell::sync::Lazy; - -use crate::{ - logs::{Logger, LoggerProvider, NoopLoggerProvider}, - InstrumentationLibrary, -}; - -/// Allows a specific [`LoggerProvider`] to be used generically, by mirroring -/// the interface, and boxing the returned types. -/// -/// [`LoggerProvider`]: crate::logs::LoggerProvider. -pub trait ObjectSafeLoggerProvider { - /// Creates a versioned named [`Logger`] instance that is a trait object - /// through the underlying [`LoggerProvider`]. - /// - /// [`Logger`]: crate::logs::Logger - /// [`LoggerProvider`]: crate::logs::LoggerProvider - fn boxed_logger( - &self, - library: Arc, - ) -> Box; -} - -impl ObjectSafeLoggerProvider for P -where - L: Logger + Send + Sync + 'static, - P: LoggerProvider, -{ - fn boxed_logger( - &self, - library: Arc, - ) -> Box { - Box::new(self.library_logger(library)) - } -} - -pub struct BoxedLogger(Box); - -impl fmt::Debug for BoxedLogger { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("BoxedLogger") - } -} - -impl Logger for BoxedLogger { - fn emit(&self, record: crate::logs::LogRecord) { - self.0.emit(record) - } - - #[cfg(feature = "logs_level_enabled")] - fn event_enabled(&self, level: crate::logs::Severity, target: &str) -> bool { - self.0.event_enabled(level, target) - } -} - -#[derive(Clone)] -/// Represents the globally configured [`LoggerProvider`] instance. -pub struct GlobalLoggerProvider { - provider: Arc, -} - -impl fmt::Debug for GlobalLoggerProvider { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("GlobalLoggerProvider") - } -} - -impl GlobalLoggerProvider { - fn new< - L: Logger + Send + Sync + 'static, - P: LoggerProvider + Send + Sync + 'static, - >( - provider: P, - ) -> Self { - GlobalLoggerProvider { - provider: Arc::new(provider), - } - } -} - -impl LoggerProvider for GlobalLoggerProvider { - type Logger = BoxedLogger; - - fn library_logger(&self, library: Arc) -> Self::Logger { - BoxedLogger(self.provider.boxed_logger(library)) - } -} - -static GLOBAL_LOGGER_PROVIDER: Lazy> = - Lazy::new(|| RwLock::new(GlobalLoggerProvider::new(NoopLoggerProvider::new()))); - -/// Returns an instance of the currently configured global [`LoggerProvider`] -/// through [`GlobalLoggerProvider`]. -/// -/// [`LoggerProvider`]: crate::logs::LoggerProvider -pub fn logger_provider() -> GlobalLoggerProvider { - GLOBAL_LOGGER_PROVIDER - .read() - .expect("GLOBAL_LOGGER_PROVIDER RwLock poisoned") - .clone() -} - -/// Creates a named instance of [`Logger`] via the configured -/// [`GlobalLoggerProvider`]. -/// -/// If `name` is an empty string, the provider will use a default name. -/// -/// [`Logger`]: crate::logs::Logger -pub fn logger(name: impl Into>) -> BoxedLogger { - logger_provider().logger(name) -} - -/// Sets the given [`LoggerProvider`] instance as the current global provider, -/// returning the [`LoggerProvider`] instance that was previously set as global -/// provider. -pub fn set_logger_provider(new_provider: P) -> GlobalLoggerProvider -where - L: Logger + Send + Sync + 'static, - P: LoggerProvider + Send + Sync + 'static, -{ - let mut provider = GLOBAL_LOGGER_PROVIDER - .write() - .expect("GLOBAL_LOGGER_PROVIDER RwLock poisoned"); - mem::replace(&mut *provider, GlobalLoggerProvider::new(new_provider)) -} - -/// Shut down the current global [`LoggerProvider`]. -pub fn shutdown_logger_provider() { - let _ = set_logger_provider(NoopLoggerProvider::new()); -} diff --git a/opentelemetry/src/global/mod.rs b/opentelemetry/src/global/mod.rs index a19da68e2f..25910c77d3 100644 --- a/opentelemetry/src/global/mod.rs +++ b/opentelemetry/src/global/mod.rs @@ -138,8 +138,6 @@ //! [`set_meter_provider`]: crate::global::set_meter_provider mod error_handler; -#[cfg(feature = "logs")] -mod logs; #[cfg(feature = "metrics")] mod metrics; #[cfg(feature = "trace")] @@ -148,12 +146,6 @@ mod propagation; mod trace; pub use error_handler::{handle_error, set_error_handler, Error}; -#[cfg(feature = "logs")] -#[cfg_attr(docsrs, doc(cfg(feature = "logs")))] -pub use logs::{ - logger, logger_provider, set_logger_provider, shutdown_logger_provider, GlobalLoggerProvider, - ObjectSafeLoggerProvider, -}; #[cfg(feature = "metrics")] #[cfg_attr(docsrs, doc(cfg(feature = "metrics")))] pub use metrics::*; diff --git a/opentelemetry/src/logs/logger.rs b/opentelemetry/src/logs/logger.rs index 6d4d48f973..11b7fb9d60 100644 --- a/opentelemetry/src/logs/logger.rs +++ b/opentelemetry/src/logs/logger.rs @@ -63,9 +63,11 @@ pub trait LoggerProvider { /// # Examples /// /// ``` - /// use opentelemetry::{global, logs::LoggerProvider}; + /// use opentelemetry::InstrumentationLibrary; + /// use crate::opentelemetry::logs::LoggerProvider; + /// use opentelemetry_sdk::logs::LoggerProvider as SdkLoggerProvider; /// - /// let provider = global::logger_provider(); + /// let provider = SdkLoggerProvider::builder().build(); /// /// // logger used in applications/binaries /// let logger = provider.logger_builder("my_app").build(); @@ -88,9 +90,11 @@ pub trait LoggerProvider { /// # Examples /// /// ``` - /// use opentelemetry::{global, InstrumentationLibrary, logs::LoggerProvider}; + /// use opentelemetry::InstrumentationLibrary; + /// use crate::opentelemetry::logs::LoggerProvider; + /// use opentelemetry_sdk::logs::LoggerProvider as SdkLoggerProvider; /// - /// let provider = global::logger_provider(); + /// let provider = SdkLoggerProvider::builder().build(); /// /// // logger used in applications/binaries /// let logger = provider.logger("my_app");