@@ -68,7 +68,7 @@ use std::{io, thread};
68
68
69
69
use std:: sync:: atomic:: AtomicUsize ;
70
70
use std:: sync:: atomic:: Ordering ;
71
- use std:: sync:: Mutex ;
71
+ use std:: sync:: { Arc , Condvar , Mutex } ;
72
72
use take_mut:: take;
73
73
74
74
use std:: panic:: { catch_unwind, AssertUnwindSafe } ;
@@ -245,6 +245,12 @@ where
245
245
thread_name : Option < String > ,
246
246
}
247
247
248
+ struct SpawnedThreadInfo {
249
+ sender : Sender < AsyncMsg > ,
250
+ flush_lock : Arc < Mutex < FlushStatus > > ,
251
+ flush_cond : Arc < Condvar > ,
252
+ }
253
+
248
254
impl < D > AsyncCoreBuilder < D >
249
255
where
250
256
D : slog:: Drain < Err = slog:: Never , Ok = ( ) > + Send + ' static ,
@@ -287,25 +293,71 @@ where
287
293
self
288
294
}
289
295
290
- fn spawn_thread ( self ) -> ( thread:: JoinHandle < ( ) > , Sender < AsyncMsg > ) {
296
+ fn spawn_thread ( self ) -> ( thread:: JoinHandle < ( ) > , SpawnedThreadInfo ) {
291
297
let ( tx, rx) = crossbeam_channel:: bounded ( self . chan_size ) ;
292
298
let mut builder = thread:: Builder :: new ( ) ;
293
299
if let Some ( thread_name) = self . thread_name {
294
300
builder = builder. name ( thread_name) ;
295
301
}
302
+ let flush_lock = Arc :: new ( Mutex :: new ( FlushStatus :: NotRequested ) ) ;
303
+ let flush_cond = Arc :: new ( Condvar :: new ( ) ) ;
304
+ let state = SpawnedThreadInfo {
305
+ sender : tx,
306
+ flush_lock : Arc :: clone ( & flush_lock) ,
307
+ flush_cond : Arc :: clone ( & flush_cond) ,
308
+ } ;
296
309
let drain = self . drain ;
297
310
let join = builder
298
311
. spawn ( move || {
299
312
let drain = AssertUnwindSafe ( & drain) ;
313
+ let mut gave_flush_warning = false ;
300
314
// catching possible unwinding panics which can occur in used inner Drain implementation
301
315
if let Err ( panic_cause) = catch_unwind ( move || loop {
316
+ let mut give_flush_warning = |x : & str | {
317
+ if !gave_flush_warning {
318
+ eprintln ! ( "slog-async: {}" , x) ;
319
+ }
320
+ gave_flush_warning = true ;
321
+ } ;
302
322
match rx. recv ( ) {
303
323
Ok ( AsyncMsg :: Record ( r) ) => {
304
324
if r. log_to ( & * drain) . is_err ( ) {
305
325
eprintln ! ( "slog-async failed while writing" ) ;
306
326
return ;
307
327
}
308
- }
328
+ } ,
329
+ Ok ( AsyncMsg :: Flush ) => {
330
+ let status_lock = match flush_lock. lock ( ) {
331
+ Err ( _e) => {
332
+ give_flush_warning ( "fush lock poisoned" ) ;
333
+ continue ;
334
+ } ,
335
+ Ok ( s) => s,
336
+ } ;
337
+ if !matches ! ( * status_lock, FlushStatus :: Pending ) {
338
+ flush_cond. notify_all ( ) ;
339
+ drop ( status_lock) ;
340
+ continue ;
341
+ }
342
+ drop ( status_lock) ;
343
+ let res_status = match drain. flush ( ) {
344
+ Ok ( ( ) ) => FlushStatus :: Success ,
345
+ Err ( e) => FlushStatus :: Failure ( e) ,
346
+ } ;
347
+ let mut status_lock = match flush_lock. lock ( ) {
348
+ Err ( _e) => {
349
+ give_flush_warning ( "fush lock poisoned" ) ;
350
+ continue ;
351
+ } ,
352
+ Ok ( s) => s,
353
+ } ;
354
+ if !matches ! ( * status_lock, FlushStatus :: Pending ) {
355
+ give_flush_warning ( "fush status corrupted" ) ;
356
+ }
357
+ * status_lock = res_status;
358
+ flush_cond. notify_all ( ) ;
359
+ drop ( status_lock) ;
360
+ } ,
309
361
Ok ( AsyncMsg :: Finish ) => return ,
310
362
Err ( recv_error) => {
311
363
eprintln ! ( "slog-async failed while receiving: {recv_error}" ) ;
@@ -318,7 +370,7 @@ where
318
370
} )
319
371
. unwrap ( ) ;
320
372
321
- ( join, tx )
373
+ ( join, state )
322
374
}
323
375
324
376
/// Build `AsyncCore`
@@ -329,12 +381,14 @@ where
329
381
/// Build `AsyncCore`
330
382
pub fn build_no_guard ( self ) -> AsyncCore {
331
383
let blocking = self . blocking ;
332
- let ( join, tx ) = self . spawn_thread ( ) ;
384
+ let ( join, info ) = self . spawn_thread ( ) ;
333
385
334
386
AsyncCore {
335
- ref_sender : tx ,
387
+ ref_sender : info . sender ,
336
388
tl_sender : thread_local:: ThreadLocal :: new ( ) ,
337
389
join : Mutex :: new ( Some ( join) ) ,
390
+ flush_lock : info. flush_lock ,
391
+ flush_cond : info. flush_cond ,
338
392
blocking,
339
393
}
340
394
}
@@ -344,18 +398,20 @@ where
344
398
/// See `AsyncGuard` for more information.
345
399
pub fn build_with_guard ( self ) -> ( AsyncCore , AsyncGuard ) {
346
400
let blocking = self . blocking ;
347
- let ( join, tx ) = self . spawn_thread ( ) ;
401
+ let ( join, info ) = self . spawn_thread ( ) ;
348
402
349
403
(
350
404
AsyncCore {
351
- ref_sender : tx . clone ( ) ,
405
+ ref_sender : info . sender . clone ( ) ,
352
406
tl_sender : thread_local:: ThreadLocal :: new ( ) ,
353
407
join : Mutex :: new ( None ) ,
408
+ flush_lock : info. flush_lock ,
409
+ flush_cond : info. flush_cond ,
354
410
blocking,
355
411
} ,
356
412
AsyncGuard {
357
413
join : Some ( join) ,
358
- tx,
414
+ tx : info . sender ,
359
415
} ,
360
416
)
361
417
}
@@ -403,6 +459,14 @@ impl Drop for AsyncGuard {
403
459
}
404
460
}
405
461
462
+ #[ derive( Debug ) ]
463
+ enum FlushStatus {
464
+ NotRequested ,
465
+ Pending ,
466
+ Failure ( slog:: FlushError ) ,
467
+ Success ,
468
+ }
469
+
406
470
/// Core of `Async` drain
407
471
///
408
472
/// See `Async` for documentation.
@@ -418,6 +482,8 @@ pub struct AsyncCore {
418
482
tl_sender : thread_local:: ThreadLocal < Sender < AsyncMsg > > ,
419
483
join : Mutex < Option < thread:: JoinHandle < ( ) > > > ,
420
484
blocking : bool ,
485
+ flush_lock : Arc < Mutex < FlushStatus > > ,
486
+ flush_cond : Arc < Condvar > ,
421
487
}
422
488
423
489
impl AsyncCore {
@@ -474,8 +540,52 @@ impl Drain for AsyncCore {
474
540
) -> AsyncResult < ( ) > {
475
541
self . send ( AsyncRecord :: from ( record, logger_values) )
476
542
}
477
- }
478
543
544
+ fn flush ( & self ) -> Result < ( ) , slog:: FlushError > {
545
+ fn handle_poison (
546
+ mut e : std:: sync:: PoisonError <
547
+ std:: sync:: MutexGuard < ' _ , FlushStatus > ,
548
+ > ,
549
+ ) -> std:: io:: Error {
550
+ * * e. get_mut ( ) = FlushStatus :: NotRequested ; // cancel request, allowing retry
551
+ std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , "mutex poisoned" )
552
+ }
553
+ let sender = self . get_sender ( ) . map_err ( |_e| {
554
+ std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , "mutex poisoned" )
555
+ } ) ?;
556
+ let mut status_lock = self . flush_lock . lock ( ) . map_err ( handle_poison) ?;
557
+ while !matches ! ( * status_lock, FlushStatus :: NotRequested ) {
558
+ // another flush is in progress, block until that one succeeds
559
+ status_lock =
560
+ self . flush_cond . wait ( status_lock) . map_err ( handle_poison) ?;
561
+ }
562
+ assert ! (
563
+ matches!( * status_lock, FlushStatus :: NotRequested ) ,
564
+ "{:?}" ,
565
+ * status_lock
566
+ ) ;
567
+ match sender. send ( AsyncMsg :: Flush ) {
568
+ Ok ( ( ) ) => { }
569
+ Err ( _) => {
570
+ return Err ( std:: io:: Error :: new (
571
+ std:: io:: ErrorKind :: Other ,
572
+ "channel disconnected" ,
573
+ )
574
+ . into ( ) ) ;
575
+ }
576
+ }
577
+ * status_lock = FlushStatus :: Pending ;
578
+ while matches ! ( * status_lock, FlushStatus :: Pending ) {
579
+ status_lock =
580
+ self . flush_cond . wait ( status_lock) . map_err ( handle_poison) ?;
581
+ }
582
+ match std:: mem:: replace ( & mut * status_lock, FlushStatus :: NotRequested ) {
583
+ FlushStatus :: NotRequested | FlushStatus :: Pending => unreachable ! ( ) ,
584
+ FlushStatus :: Failure ( cause) => Err ( cause) ,
585
+ FlushStatus :: Success => Ok ( ( ) ) ,
586
+ }
587
+ }
588
+ }
479
589
/// Serialized record.
480
590
pub struct AsyncRecord {
481
591
msg : String ,
@@ -545,6 +655,7 @@ impl AsyncRecord {
545
655
enum AsyncMsg {
546
656
Record ( AsyncRecord ) ,
547
657
Finish ,
658
+ Flush ,
548
659
}
549
660
550
661
impl Drop for AsyncCore {
@@ -796,6 +907,10 @@ impl Drain for Async {
796
907
797
908
Ok ( ( ) )
798
909
}
910
+
911
+ fn flush ( & self ) -> Result < ( ) , slog:: FlushError > {
912
+ self . core . flush ( )
913
+ }
799
914
}
800
915
801
916
impl Drop for Async {
@@ -806,7 +921,6 @@ impl Drop for Async {
806
921
807
922
// }}}
808
923
809
-
810
924
#[ cfg( test) ]
811
925
mod test {
812
926
use super :: * ;
@@ -815,25 +929,45 @@ mod test {
815
929
#[ test]
816
930
fn integration_test ( ) {
817
931
let ( mock_drain, mock_drain_rx) = MockDrain :: new ( ) ;
818
- let async_drain = AsyncBuilder :: new ( mock_drain)
819
- . build ( ) ;
820
- let slog = slog:: Logger :: root ( async_drain. fuse ( ) , o ! ( "field1" => "value1" ) ) ;
932
+ let async_drain = AsyncBuilder :: new ( mock_drain) . build ( ) ;
933
+ let slog =
934
+ slog:: Logger :: root ( async_drain. fuse ( ) , o ! ( "field1" => "value1" ) ) ;
821
935
822
936
info ! ( slog, "Message 1" ; "field2" => "value2" ) ;
823
937
warn ! ( slog, "Message 2" ; "field3" => "value3" ) ;
824
- assert_eq ! ( mock_drain_rx. recv( ) . unwrap( ) , r#"INFO Message 1: [("field1", "value1"), ("field2", "value2")]"# ) ;
825
- assert_eq ! ( mock_drain_rx. recv( ) . unwrap( ) , r#"WARN Message 2: [("field1", "value1"), ("field3", "value3")]"# ) ;
938
+ assert_eq ! (
939
+ mock_drain_rx. recv( ) . unwrap( ) ,
940
+ * r#"INFO Message 1: [("field1", "value1"), ("field2", "value2")]"#
941
+ ) ;
942
+ assert_eq ! (
943
+ mock_drain_rx. recv( ) . unwrap( ) ,
944
+ * r#"WARN Message 2: [("field1", "value1"), ("field3", "value3")]"#
945
+ ) ;
946
+ slog. flush ( ) . unwrap ( ) ;
947
+ assert_eq ! ( mock_drain_rx. recv( ) . unwrap( ) , MockMsg :: Flush ) ;
948
+ }
949
+
950
+ #[ derive( Debug , PartialEq ) ]
951
+ enum MockMsg {
952
+ Log ( String ) ,
953
+ Flush ,
954
+ }
955
+ impl PartialEq < str > for MockMsg {
956
+ fn eq ( & self , other : & str ) -> bool {
957
+ match self {
958
+ MockMsg :: Log ( ref msg) => msg == other,
959
+ _ => false ,
960
+ }
961
+ }
826
962
}
827
-
828
-
829
963
/// Test-helper drain
830
964
#[ derive( Debug ) ]
831
965
struct MockDrain {
832
- tx : mpsc:: Sender < String > ,
966
+ tx : mpsc:: Sender < MockMsg > ,
833
967
}
834
968
835
969
impl MockDrain {
836
- fn new ( ) -> ( Self , mpsc:: Receiver < String > ) {
970
+ fn new ( ) -> ( Self , mpsc:: Receiver < MockMsg > ) {
837
971
let ( tx, rx) = mpsc:: channel ( ) ;
838
972
( Self { tx } , rx)
839
973
}
@@ -843,14 +977,23 @@ mod test {
843
977
type Ok = ( ) ;
844
978
type Err = slog:: Never ;
845
979
846
- fn log ( & self , record : & Record , logger_kv : & OwnedKVList ) -> Result < Self :: Ok , Self :: Err > {
980
+ fn log (
981
+ & self ,
982
+ record : & Record ,
983
+ logger_kv : & OwnedKVList ,
984
+ ) -> Result < Self :: Ok , Self :: Err > {
847
985
let mut serializer = MockSerializer :: default ( ) ;
848
986
logger_kv. serialize ( record, & mut serializer) . unwrap ( ) ;
849
987
record. kv ( ) . serialize ( record, & mut serializer) . unwrap ( ) ;
850
988
let level = record. level ( ) . as_short_str ( ) ;
851
989
let msg = record. msg ( ) . to_string ( ) ;
852
990
let entry = format ! ( "{} {}: {:?}" , level, msg, serializer. kvs) ;
853
- self . tx . send ( entry) . unwrap ( ) ;
991
+ self . tx . send ( MockMsg :: Log ( entry) ) . unwrap ( ) ;
992
+ Ok ( ( ) )
993
+ }
994
+
995
+ fn flush ( & self ) -> Result < ( ) , slog:: FlushError > {
996
+ self . tx . send ( MockMsg :: Flush ) . unwrap ( ) ;
854
997
Ok ( ( ) )
855
998
}
856
999
}
@@ -861,7 +1004,11 @@ mod test {
861
1004
}
862
1005
863
1006
impl slog:: Serializer for MockSerializer {
864
- fn emit_arguments ( & mut self , key : Key , val : & fmt:: Arguments ) -> Result < ( ) , slog:: Error > {
1007
+ fn emit_arguments (
1008
+ & mut self ,
1009
+ key : Key ,
1010
+ val : & fmt:: Arguments ,
1011
+ ) -> Result < ( ) , slog:: Error > {
865
1012
self . kvs . push ( ( key. to_string ( ) , val. to_string ( ) ) ) ;
866
1013
Ok ( ( ) )
867
1014
}
0 commit comments