opentelemetry_api/global/
logs.rs

1use std::{
2    borrow::Cow,
3    fmt, mem,
4    sync::{Arc, RwLock},
5};
6
7use once_cell::sync::Lazy;
8
9use crate::{
10    logs::{Logger, LoggerProvider, NoopLoggerProvider},
11    InstrumentationLibrary,
12};
13
14/// Allows a specific [`LoggerProvider`] to be used generically, by mirroring
15/// the interface, and boxing the returned types.
16///
17/// [`LoggerProvider`]: crate::logs::LoggerProvider.
18pub trait ObjectSafeLoggerProvider {
19    /// Creates a versioned named [`Logger`] instance that is a trait object
20    /// through the underlying [`LoggerProvider`].
21    ///
22    /// [`Logger`]: crate::logs::Logger
23    /// [`LoggerProvider`]: crate::logs::LoggerProvider
24    fn boxed_logger(
25        &self,
26        library: Arc<InstrumentationLibrary>,
27    ) -> Box<dyn Logger + Send + Sync + 'static>;
28}
29
30impl<L, P> ObjectSafeLoggerProvider for P
31where
32    L: Logger + Send + Sync + 'static,
33    P: LoggerProvider<Logger = L>,
34{
35    fn boxed_logger(
36        &self,
37        library: Arc<InstrumentationLibrary>,
38    ) -> Box<dyn Logger + Send + Sync + 'static> {
39        Box::new(self.library_logger(library))
40    }
41}
42
43pub struct BoxedLogger(Box<dyn Logger + Send + Sync + 'static>);
44
45impl fmt::Debug for BoxedLogger {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        f.write_str("BoxedLogger")
48    }
49}
50
51impl Logger for BoxedLogger {
52    fn emit(&self, record: crate::logs::LogRecord) {
53        self.0.emit(record)
54    }
55
56    #[cfg(feature = "logs_level_enabled")]
57    fn event_enabled(&self, level: crate::logs::Severity, target: &str) -> bool {
58        self.0.event_enabled(level, target)
59    }
60}
61
62#[derive(Clone)]
63/// Represents the globally configured [`LoggerProvider`] instance.
64pub struct GlobalLoggerProvider {
65    provider: Arc<dyn ObjectSafeLoggerProvider + Send + Sync>,
66}
67
68impl fmt::Debug for GlobalLoggerProvider {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        f.write_str("GlobalLoggerProvider")
71    }
72}
73
74impl GlobalLoggerProvider {
75    fn new<
76        L: Logger + Send + Sync + 'static,
77        P: LoggerProvider<Logger = L> + Send + Sync + 'static,
78    >(
79        provider: P,
80    ) -> Self {
81        GlobalLoggerProvider {
82            provider: Arc::new(provider),
83        }
84    }
85}
86
87impl LoggerProvider for GlobalLoggerProvider {
88    type Logger = BoxedLogger;
89
90    fn library_logger(&self, library: Arc<InstrumentationLibrary>) -> Self::Logger {
91        BoxedLogger(self.provider.boxed_logger(library))
92    }
93}
94
95static GLOBAL_LOGGER_PROVIDER: Lazy<RwLock<GlobalLoggerProvider>> =
96    Lazy::new(|| RwLock::new(GlobalLoggerProvider::new(NoopLoggerProvider::new())));
97
98/// Returns an instance of the currently configured global [`LoggerProvider`]
99/// through [`GlobalLoggerProvider`].
100///
101/// [`LoggerProvider`]: crate::logs::LoggerProvider
102pub fn logger_provider() -> GlobalLoggerProvider {
103    GLOBAL_LOGGER_PROVIDER
104        .read()
105        .expect("GLOBAL_LOGGER_PROVIDER RwLock poisoned")
106        .clone()
107}
108
109/// Creates a named instance of [`Logger`] via the configured
110/// [`GlobalLoggerProvider`].
111///
112/// If `name` is an empty string, the provider will use a default name.
113///
114/// [`Logger`]: crate::logs::Logger
115pub fn logger(name: Cow<'static, str>) -> BoxedLogger {
116    logger_provider().logger(name)
117}
118
119/// Sets the given [`LoggerProvider`] instance as the current global provider,
120/// returning the [`LoggerProvider`] instance that was previously set as global
121/// provider.
122pub fn set_logger_provider<L, P>(new_provider: P) -> GlobalLoggerProvider
123where
124    L: Logger + Send + Sync + 'static,
125    P: LoggerProvider<Logger = L> + Send + Sync + 'static,
126{
127    let mut provider = GLOBAL_LOGGER_PROVIDER
128        .write()
129        .expect("GLOBAL_LOGGER_PROVIDER RwLock poisoned");
130    mem::replace(&mut *provider, GlobalLoggerProvider::new(new_provider))
131}
132
133/// Shut down the current global [`LoggerProvider`].
134pub fn shutdown_logger_provider() {
135    let _ = set_logger_provider(NoopLoggerProvider::new());
136}