@@ -13,12 +13,25 @@ use opentelemetry::{
1313#[ cfg( feature = "logs_level_enabled" ) ]
1414use opentelemetry:: logs:: Severity ;
1515
16+ use std:: sync:: atomic:: AtomicBool ;
1617use std:: { borrow:: Cow , sync:: Arc } ;
1718
19+ use once_cell:: sync:: Lazy ;
20+
21+ // a no nop logger provider used as placeholder when the provider is shutdown
22+ static NOOP_LOGGER_PROVIDER : Lazy < LoggerProvider > = Lazy :: new ( || LoggerProvider {
23+ inner : Arc :: new ( LoggerProviderInner {
24+ processors : Vec :: new ( ) ,
25+ config : Config :: default ( ) ,
26+ } ) ,
27+ is_shutdown : Arc :: new ( AtomicBool :: new ( true ) ) ,
28+ } ) ;
29+
1830#[ derive( Debug , Clone ) ]
1931/// Creator for `Logger` instances.
2032pub struct LoggerProvider {
2133 inner : Arc < LoggerProviderInner > ,
34+ is_shutdown : Arc < AtomicBool > ,
2235}
2336
2437/// Default logger name if empty string is provided.
@@ -59,6 +72,10 @@ impl opentelemetry::logs::LoggerProvider for LoggerProvider {
5972 }
6073
6174 fn library_logger ( & self , library : Arc < InstrumentationLibrary > ) -> Self :: Logger {
75+ // If the provider is shutdown, new logger will refer a no-op logger provider.
76+ if self . is_shutdown . load ( std:: sync:: atomic:: Ordering :: Relaxed ) {
77+ return Logger :: new ( library, NOOP_LOGGER_PROVIDER . clone ( ) ) ;
78+ }
6279 Logger :: new ( library, self . clone ( ) )
6380 }
6481}
@@ -87,22 +104,18 @@ impl LoggerProvider {
87104 . collect ( )
88105 }
89106
90- /// Shuts down this `LoggerProvider`, panicking on failure.
91- pub fn shutdown ( & mut self ) -> Vec < LogResult < ( ) > > {
92- self . try_shutdown ( )
93- . expect ( "cannot shutdown LoggerProvider when child Loggers are still active" )
94- }
95-
96- /// Attempts to shutdown this `LoggerProvider`, succeeding only when
97- /// all cloned `LoggerProvider` values have been dropped.
98- pub fn try_shutdown ( & mut self ) -> Option < Vec < LogResult < ( ) > > > {
99- Arc :: get_mut ( & mut self . inner ) . map ( |inner| {
100- inner
101- . processors
102- . iter_mut ( )
103- . map ( |processor| processor. shutdown ( ) )
104- . collect ( )
105- } )
107+ /// Shuts down this `LoggerProvider`
108+ pub fn shutdown ( & self ) -> Vec < LogResult < ( ) > > {
109+ // mark itself as already shutdown
110+ self . is_shutdown
111+ . store ( true , std:: sync:: atomic:: Ordering :: Relaxed ) ;
112+ // propagate the shutdown signal to processors
113+ // it's up to the processor to properly block new logs after shutdown
114+ self . inner
115+ . processors
116+ . iter ( )
117+ . map ( |processor| processor. shutdown ( ) )
118+ . collect ( )
106119 }
107120}
108121
@@ -168,6 +181,7 @@ impl Builder {
168181 processors : self . processors ,
169182 config : self . config ,
170183 } ) ,
184+ is_shutdown : Arc :: new ( AtomicBool :: new ( false ) ) ,
171185 }
172186 }
173187}
@@ -253,11 +267,63 @@ mod tests {
253267
254268 use super :: * ;
255269 use opentelemetry:: global:: { logger, set_logger_provider, shutdown_logger_provider} ;
256- use opentelemetry:: logs:: Logger ;
270+ use opentelemetry:: logs:: { Logger , LoggerProvider as _ } ;
257271 use opentelemetry:: { Key , KeyValue , Value } ;
258- use std:: sync:: Mutex ;
272+ use std:: fmt:: { Debug , Formatter } ;
273+ use std:: sync:: atomic:: AtomicU64 ;
274+ use std:: sync:: { Arc , Mutex } ;
259275 use std:: thread;
260276
277+ struct ShutdownTestLogProcessor {
278+ is_shutdown : Arc < Mutex < bool > > ,
279+ counter : Arc < AtomicU64 > ,
280+ }
281+
282+ impl Debug for ShutdownTestLogProcessor {
283+ fn fmt ( & self , _f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
284+ todo ! ( )
285+ }
286+ }
287+
288+ impl ShutdownTestLogProcessor {
289+ pub ( crate ) fn new ( counter : Arc < AtomicU64 > ) -> Self {
290+ ShutdownTestLogProcessor {
291+ is_shutdown : Arc :: new ( Mutex :: new ( false ) ) ,
292+ counter,
293+ }
294+ }
295+ }
296+
297+ impl LogProcessor for ShutdownTestLogProcessor {
298+ fn emit ( & self , _data : LogData ) {
299+ self . is_shutdown
300+ . lock ( )
301+ . map ( |is_shutdown| {
302+ if !* is_shutdown {
303+ self . counter
304+ . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
305+ }
306+ } )
307+ . expect ( "lock poisoned" ) ;
308+ }
309+
310+ fn force_flush ( & self ) -> LogResult < ( ) > {
311+ Ok ( ( ) )
312+ }
313+
314+ fn shutdown ( & self ) -> LogResult < ( ) > {
315+ self . is_shutdown
316+ . lock ( )
317+ . map ( |mut is_shutdown| * is_shutdown = true )
318+ . expect ( "lock poisoned" ) ;
319+ Ok ( ( ) )
320+ }
321+
322+ #[ cfg( feature = "logs_level_enabled" ) ]
323+ fn event_enabled ( & self , _level : Severity , _target : & str , _name : & str ) -> bool {
324+ true
325+ }
326+ }
261327 #[ test]
262328 fn test_logger_provider_default_resource ( ) {
263329 let assert_resource = |provider : & super :: LoggerProvider ,
@@ -386,6 +452,30 @@ mod tests {
386452
387453 #[ test]
388454 fn shutdown_test ( ) {
455+ let counter = Arc :: new ( AtomicU64 :: new ( 0 ) ) ;
456+ let logger_provider = LoggerProvider :: builder ( )
457+ . with_log_processor ( ShutdownTestLogProcessor :: new ( counter. clone ( ) ) )
458+ . build ( ) ;
459+
460+ let logger1 = logger_provider. logger ( "test-logger1" ) ;
461+ let logger2 = logger_provider. logger ( "test-logger2" ) ;
462+ logger1. emit ( LogRecord :: default ( ) ) ;
463+ logger2. emit ( LogRecord :: default ( ) ) ;
464+
465+ let logger3 = logger_provider. logger ( "test-logger3" ) ;
466+ let handle = thread:: spawn ( move || {
467+ logger3. emit ( LogRecord :: default ( ) ) ;
468+ } ) ;
469+ handle. join ( ) . expect ( "thread panicked" ) ;
470+
471+ let _ = logger_provider. shutdown ( ) ;
472+ logger1. emit ( LogRecord :: default ( ) ) ;
473+
474+ assert_eq ! ( counter. load( std:: sync:: atomic:: Ordering :: SeqCst ) , 3 ) ;
475+ }
476+
477+ #[ test]
478+ fn global_shutdown_test ( ) {
389479 // cargo test shutdown_test --features=logs
390480
391481 // Arrange
@@ -493,7 +583,7 @@ mod tests {
493583 Ok ( ( ) )
494584 }
495585
496- fn shutdown ( & mut self ) -> LogResult < ( ) > {
586+ fn shutdown ( & self ) -> LogResult < ( ) > {
497587 * self . shutdown_called . lock ( ) . unwrap ( ) = true ;
498588 Ok ( ( ) )
499589 }
0 commit comments