1515
1616use bitcoin:: secp256k1:: PublicKey ;
1717
18+ use core:: cell:: RefCell ;
1819use core:: cmp;
1920use core:: fmt;
2021use core:: fmt:: Display ;
@@ -130,6 +131,9 @@ pub struct Record<$($args)?> {
130131 /// Note that this is only filled in for logs pertaining to a specific payment, and will be
131132 /// `None` for logs which are not directly related to a payment.
132133 pub payment_hash: Option <PaymentHash >,
134+ /// The names of the surrounding spans, if any.
135+ #[ cfg( feature = "std" ) ]
136+ pub spans: Vec <& ' static str >,
133137}
134138
135139impl <$( $args) ?> Record <$( $args) ?> {
@@ -138,7 +142,10 @@ impl<$($args)?> Record<$($args)?> {
138142 /// This is not exported to bindings users as fmt can't be used in C
139143 #[ inline]
140144 pub fn new<$( $nonstruct_args) ?>(
141- level: Level , peer_id: Option <PublicKey >, channel_id: Option <ChannelId >,
145+ level: Level ,
146+ #[ cfg( feature = "std" ) ]
147+ spans: Vec <& ' static str >,
148+ peer_id: Option <PublicKey >, channel_id: Option <ChannelId >,
142149 args: fmt:: Arguments <' a>, module_path: & ' static str , file: & ' static str , line: u32 ,
143150 payment_hash: Option <PaymentHash >
144151 ) -> Record <$( $args) ?> {
@@ -154,6 +161,8 @@ impl<$($args)?> Record<$($args)?> {
154161 file,
155162 line,
156163 payment_hash,
164+ #[ cfg( feature = "std" ) ]
165+ spans,
157166 }
158167 }
159168}
@@ -189,7 +198,20 @@ impl<$($args)?> Display for Record<$($args)?> {
189198
190199 #[ cfg( test) ]
191200 {
192- write!( f, " {}" , self . args) ?;
201+ write!( f, " " ) ?;
202+ #[ cfg( feature = "std" ) ]
203+ if !self . spans. is_empty( ) {
204+ write!( f, "[" ) ?;
205+ for ( i, span) in self . spans. iter( ) . enumerate( ) {
206+ if i > 0 {
207+ write!( f, "->" ) ?;
208+ }
209+ write!( f, "{}" , span) ?;
210+ }
211+ write!( f, "] " ) ?;
212+ }
213+
214+ write!( f, "{}" , self . args) ?;
193215
194216 let mut open_bracket_written = false ;
195217 if let Some ( peer_id) = self . peer_id {
@@ -384,14 +406,70 @@ impl<T: fmt::Display, I: core::iter::Iterator<Item = T> + Clone> fmt::Display fo
384406 }
385407}
386408
409+ #[ cfg( feature = "std" ) ]
410+ thread_local ! {
411+ /// The thread-local stack of loggers.
412+ pub static TLS_LOGGER : RefCell <Vec <& ' static str >> = RefCell :: new( Vec :: new( ) ) ;
413+ }
414+
415+ /// A scope which pushes a logger on a thread-local stack for the duration of the scope.
416+ pub struct LoggerScope < ' a > {
417+ _marker : core:: marker:: PhantomData < & ' a ( ) > ,
418+ }
419+
420+ impl < ' a > LoggerScope < ' a > {
421+ /// Pushes a logger onto the thread-local logger stack.
422+ pub fn new ( span : & ' static str ) -> Self {
423+ #[ cfg( feature = "std" ) ]
424+ TLS_LOGGER . with ( |cell| {
425+ let mut stack = cell. borrow_mut ( ) ;
426+ stack. push ( span) ;
427+ } ) ;
428+
429+ LoggerScope { _marker : core:: marker:: PhantomData }
430+ }
431+ }
432+
433+ impl < ' a > Drop for LoggerScope < ' a > {
434+ fn drop ( & mut self ) {
435+ #[ cfg( feature = "std" ) ]
436+ TLS_LOGGER . with ( |cell| {
437+ let mut stack = cell. borrow_mut ( ) ;
438+ stack. pop ( ) ;
439+ } ) ;
440+ }
441+ }
442+
387443#[ cfg( test) ]
388444mod tests {
389445 use crate :: ln:: types:: ChannelId ;
390446 use crate :: sync:: Arc ;
391447 use crate :: types:: payment:: PaymentHash ;
392- use crate :: util:: logger:: { Level , Logger , WithContext } ;
448+ use crate :: util:: logger:: { Level , Logger , LoggerScope , WithContext } ;
393449 use crate :: util:: test_utils:: TestLogger ;
394450 use bitcoin:: secp256k1:: { PublicKey , Secp256k1 , SecretKey } ;
451+ use lightning_macros:: log_scope;
452+
453+ #[ test]
454+ fn logger_scope ( ) {
455+ let logger = TestLogger :: new ( ) ;
456+ let _scope = LoggerScope :: new ( "test_logger_scope" ) ;
457+ log_info ! ( logger, "Info" ) ;
458+ }
459+
460+ #[ test]
461+ #[ log_scope( name = "test_logger_scope_proc_macro" ) ]
462+ fn logger_scope_proc_macro ( ) {
463+ let logger = TestLogger :: new ( ) ;
464+ log_info ! ( logger, "Info" ) ;
465+ }
466+
467+ #[ test]
468+ #[ log_scope]
469+ fn logger_scope_proc_macro_no_name ( ) {
470+ let logger = TestLogger :: new ( ) ;
471+ log_info ! ( logger, "Info" ) ;
472+ }
395473
396474 #[ test]
397475 fn test_level_show ( ) {
0 commit comments