@@ -13,12 +13,25 @@ use opentelemetry::{
13
13
#[ cfg( feature = "logs_level_enabled" ) ]
14
14
use opentelemetry:: logs:: Severity ;
15
15
16
+ use std:: sync:: atomic:: AtomicBool ;
16
17
use std:: { borrow:: Cow , sync:: Arc } ;
17
18
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
+
18
30
#[ derive( Debug , Clone ) ]
19
31
/// Creator for `Logger` instances.
20
32
pub struct LoggerProvider {
21
33
inner : Arc < LoggerProviderInner > ,
34
+ is_shutdown : Arc < AtomicBool > ,
22
35
}
23
36
24
37
/// Default logger name if empty string is provided.
@@ -59,6 +72,10 @@ impl opentelemetry::logs::LoggerProvider for LoggerProvider {
59
72
}
60
73
61
74
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
+ }
62
79
Logger :: new ( library, self . clone ( ) )
63
80
}
64
81
}
@@ -87,22 +104,18 @@ impl LoggerProvider {
87
104
. collect ( )
88
105
}
89
106
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 ( )
106
119
}
107
120
}
108
121
@@ -168,6 +181,7 @@ impl Builder {
168
181
processors : self . processors ,
169
182
config : self . config ,
170
183
} ) ,
184
+ is_shutdown : Arc :: new ( AtomicBool :: new ( false ) ) ,
171
185
}
172
186
}
173
187
}
@@ -253,11 +267,63 @@ mod tests {
253
267
254
268
use super :: * ;
255
269
use opentelemetry:: global:: { logger, set_logger_provider, shutdown_logger_provider} ;
256
- use opentelemetry:: logs:: Logger ;
270
+ use opentelemetry:: logs:: { Logger , LoggerProvider as _ } ;
257
271
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 } ;
259
275
use std:: thread;
260
276
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
+ }
261
327
#[ test]
262
328
fn test_logger_provider_default_resource ( ) {
263
329
let assert_resource = |provider : & super :: LoggerProvider ,
@@ -386,6 +452,30 @@ mod tests {
386
452
387
453
#[ test]
388
454
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 ( ) {
389
479
// cargo test shutdown_test --features=logs
390
480
391
481
// Arrange
@@ -493,7 +583,7 @@ mod tests {
493
583
Ok ( ( ) )
494
584
}
495
585
496
- fn shutdown ( & mut self ) -> LogResult < ( ) > {
586
+ fn shutdown ( & self ) -> LogResult < ( ) > {
497
587
* self . shutdown_called . lock ( ) . unwrap ( ) = true ;
498
588
Ok ( ( ) )
499
589
}
0 commit comments