Skip to content

Commit 0d92869

Browse files
committed
Add TLS logger
1 parent de384ff commit 0d92869

File tree

4 files changed

+189
-6
lines changed

4 files changed

+189
-6
lines changed

lightning-invoice/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ impl From<Network> for Currency {
460460
Network::Testnet4 => Currency::BitcoinTestnet,
461461
Network::Regtest => Currency::Regtest,
462462
Network::Signet => Currency::Signet,
463+
_ => todo!(),
463464
}
464465
}
465466
}

lightning-macros/src/lib.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@
2020

2121
extern crate alloc;
2222

23+
use alloc::string::String;
2324
use alloc::string::ToString;
2425
use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
2526
use proc_macro2::TokenStream as TokenStream2;
2627
use quote::quote;
2728
use syn::spanned::Spanned;
28-
use syn::{parse, ImplItemFn, Token};
29+
use syn::{parse, parse2, Expr, ExprLit, ImplItemFn, Lit, Token};
2930
use syn::{parse_macro_input, Item};
3031

3132
fn add_async_method(mut parsed: ImplItemFn) -> TokenStream {
@@ -400,3 +401,46 @@ pub fn xtest_inventory(_input: TokenStream) -> TokenStream {
400401

401402
TokenStream::from(expanded)
402403
}
404+
405+
/// Adds a logging scope at the top of a method.
406+
#[proc_macro_attribute]
407+
pub fn log_scope(attrs: TokenStream, meth: TokenStream) -> TokenStream {
408+
let attrs: TokenStream2 = parse_macro_input!(attrs as TokenStream2);
409+
let mut name_attr: Option<String> = None;
410+
if !attrs.is_empty() {
411+
// Expect something like `name = "foo"`
412+
let expr: Expr = parse2(attrs.clone()).expect("invalid attribute syntax");
413+
414+
if let Expr::Assign(assign) = expr {
415+
// check left-hand side is `name`
416+
if let Expr::Path(path) = *assign.left {
417+
if path.path.is_ident("name") {
418+
if let Expr::Lit(ExprLit { lit: Lit::Str(s), .. }) = *assign.right {
419+
name_attr = Some(s.value());
420+
}
421+
}
422+
}
423+
}
424+
}
425+
let name = name_attr.unwrap();
426+
427+
let mut meth = if let Ok(parsed) = parse::<syn::ItemFn>(meth) {
428+
parsed
429+
} else {
430+
return (quote! {
431+
compile_error!("log_scope can only be set on methods")
432+
})
433+
.into();
434+
};
435+
436+
let init_stmt1 = quote! {
437+
let _logger_wrapper = crate::util::logger::LoggerWrapper(&self.logger);
438+
};
439+
let init_stmt2 = quote! {
440+
let _logging_context = crate::util::logger::LoggerScope::new(&_logger_wrapper, #name);
441+
};
442+
443+
meth.block.stmts.insert(0, parse(init_stmt2.into()).unwrap());
444+
meth.block.stmts.insert(0, parse(init_stmt1.into()).unwrap());
445+
quote! { #meth }.into()
446+
}

lightning/src/util/logger.rs

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
1616
use bitcoin::secp256k1::PublicKey;
1717

18+
use core::cell::RefCell;
1819
use core::cmp;
1920
use core::fmt;
2021
use 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+
135+
/// The span name of the message.
136+
pub span: Option<&'static str>,
133137
}
134138

135139
impl<$($args)?> Record<$($args)?> {
@@ -138,7 +142,7 @@ 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, span: Option<&'static str>, peer_id: Option<PublicKey>, channel_id: Option<ChannelId>,
142146
args: fmt::Arguments<'a>, module_path: &'static str, file: &'static str, line: u32,
143147
payment_hash: Option<PaymentHash>
144148
) -> Record<$($args)?> {
@@ -154,6 +158,7 @@ impl<$($args)?> Record<$($args)?> {
154158
file,
155159
line,
156160
payment_hash,
161+
span,
157162
}
158163
}
159164
}
@@ -189,9 +194,14 @@ impl<$($args)?> Display for Record<$($args)?> {
189194

190195
#[cfg(test)]
191196
{
192-
write!(f, " {}", self.args)?;
197+
write!(f, " ")?;
198+
if let Some(span) = self.span {
199+
write!(f, "[{}] ", span)?;
200+
}
201+
write!(f, "{}", self.args)?;
193202

194203
let mut open_bracket_written = false;
204+
195205
if let Some(peer_id) = self.peer_id {
196206
write!(f, " [")?;
197207
open_bracket_written = true;
@@ -384,15 +394,75 @@ impl<T: fmt::Display, I: core::iter::Iterator<Item = T> + Clone> fmt::Display fo
384394
}
385395
}
386396

397+
/// A wrapper to allow getting a dyn Logger from a deref type.
398+
pub struct LoggerWrapper<'a, L: Deref>(pub &'a L)
399+
where
400+
L::Target: Logger;
401+
402+
impl<'a, L: Deref> Logger for LoggerWrapper<'a, L>
403+
where
404+
L::Target: Logger,
405+
{
406+
fn log(&self, record: Record) {
407+
self.0.log(record)
408+
}
409+
}
410+
411+
pub struct Span {
412+
pub logger: &'static dyn Logger,
413+
pub name: &'static str,
414+
}
415+
416+
thread_local! {
417+
pub(crate) static TLS_LOGGER: RefCell<Vec<Span>> = RefCell::new(Vec::new());
418+
}
419+
420+
/// A scope which pushes a logger on a thread-local stack for the duration of the scope.
421+
pub struct LoggerScope<'a> {
422+
_marker: std::marker::PhantomData<&'a ()>,
423+
}
424+
425+
impl<'a> LoggerScope<'a> {
426+
/// Pushes a logger onto the thread-local logger stack.
427+
pub fn new(logger: &'a dyn Logger, span: &'static str) -> Self {
428+
TLS_LOGGER.with(|cell| {
429+
let mut stack = cell.borrow_mut();
430+
431+
let logger_ref_static: &'static dyn Logger =
432+
unsafe { std::mem::transmute::<&'a dyn Logger, &'static dyn Logger>(logger) };
433+
434+
stack.push(Span { logger: logger_ref_static, name: span });
435+
});
436+
437+
LoggerScope { _marker: std::marker::PhantomData }
438+
}
439+
}
440+
441+
impl<'a> Drop for LoggerScope<'a> {
442+
fn drop(&mut self) {
443+
TLS_LOGGER.with(|cell| {
444+
let mut stack = cell.borrow_mut();
445+
stack.pop();
446+
});
447+
}
448+
}
449+
387450
#[cfg(test)]
388451
mod tests {
389452
use crate::ln::types::ChannelId;
390453
use crate::sync::Arc;
391454
use crate::types::payment::PaymentHash;
392-
use crate::util::logger::{Level, Logger, WithContext};
455+
use crate::util::logger::{Level, Logger, LoggerScope, WithContext};
393456
use crate::util::test_utils::TestLogger;
394457
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
395458

459+
#[test]
460+
fn logger_scope() {
461+
let logger = TestLogger::new();
462+
let _scope = LoggerScope::new(&logger, "test_logger_scope");
463+
log_info_ctx!("Info");
464+
}
465+
396466
#[test]
397467
fn test_level_show() {
398468
assert_eq!("INFO", Level::Info.to_string());

lightning/src/util/macro_logger.rs

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,28 @@ macro_rules! log_spendable {
174174
#[doc(hidden)]
175175
#[macro_export]
176176
macro_rules! log_given_level {
177-
($logger: expr, $lvl:expr, $($arg:tt)+) => (
178-
$logger.log($crate::util::logger::Record::new($lvl, None, None, format_args!($($arg)+), module_path!(), file!(), line!(), None))
177+
($logger: expr, $lvl:expr, $($arg:tt)+) => {{
178+
let mut span_name = None;
179+
$crate::util::logger::TLS_LOGGER.with(|cell| {
180+
if let Some(span) = cell.borrow().last() {
181+
span_name = Some(span.name);
182+
}
183+
});
184+
$logger.log($crate::util::logger::Record::new($lvl, span_name, None, None, format_args!($($arg)+), module_path!(), file!(), line!(), None));
185+
}};
186+
}
187+
188+
/// Create a new Record and log it. You probably don't want to use this macro directly,
189+
/// but it needs to be exported so `log_trace` etc can use it in external crates.
190+
#[doc(hidden)]
191+
#[macro_export]
192+
macro_rules! log_given_level_ctx {
193+
($lvl:expr, $($arg:tt)+) => (
194+
$crate::util::logger::TLS_LOGGER.with(|cell| {
195+
if let Some(span) = cell.borrow().last() {
196+
span.logger.log($crate::util::logger::Record::new($lvl, Some(span.name), None, None, format_args!($($arg)+), module_path!(), file!(), line!(), None))
197+
}
198+
})
179199
);
180200
}
181201

@@ -187,6 +207,14 @@ macro_rules! log_error {
187207
)
188208
}
189209

210+
// Log at the `ERROR` level using the thread-local logger.
211+
#[macro_export]
212+
macro_rules! log_error_ctx {
213+
($($arg:tt)+) => {
214+
$crate::log_given_level_ctx!($crate::util::logger::Level::Error, $($arg)*);
215+
};
216+
}
217+
190218
/// Log at the `WARN` level.
191219
#[macro_export]
192220
macro_rules! log_warn {
@@ -195,6 +223,14 @@ macro_rules! log_warn {
195223
)
196224
}
197225

226+
// Log at the `WARN` level using the thread-local logger.
227+
#[macro_export]
228+
macro_rules! log_warn_ctx {
229+
($($arg:tt)+) => {
230+
$crate::log_given_level_ctx!($crate::util::logger::Level::Warn, $($arg)*);
231+
};
232+
}
233+
198234
/// Log at the `INFO` level.
199235
#[macro_export]
200236
macro_rules! log_info {
@@ -203,6 +239,14 @@ macro_rules! log_info {
203239
)
204240
}
205241

242+
/// Log at the `INFO` level using the thread-local logger.
243+
#[macro_export]
244+
macro_rules! log_info_ctx {
245+
($($arg:tt)+) => {
246+
$crate::log_given_level_ctx!($crate::util::logger::Level::Info, $($arg)*);
247+
};
248+
}
249+
206250
/// Log at the `DEBUG` level.
207251
#[macro_export]
208252
macro_rules! log_debug {
@@ -211,6 +255,14 @@ macro_rules! log_debug {
211255
)
212256
}
213257

258+
// Log at the `DEBUG` level using the thread-local logger.
259+
#[macro_export]
260+
macro_rules! log_debug_ctx {
261+
($($arg:tt)+) => {
262+
$crate::log_given_level_ctx!($crate::util::logger::Level::Debug, $($arg)*);
263+
};
264+
}
265+
214266
/// Log at the `TRACE` level.
215267
#[macro_export]
216268
macro_rules! log_trace {
@@ -219,10 +271,26 @@ macro_rules! log_trace {
219271
)
220272
}
221273

274+
// Log at the `TRACE` level using the thread-local logger.
275+
#[macro_export]
276+
macro_rules! log_trace_ctx {
277+
($($arg:tt)+) => {
278+
$crate::log_given_level_ctx!($crate::util::logger::Level::Trace, $($arg)*);
279+
};
280+
}
281+
222282
/// Log at the `GOSSIP` level.
223283
#[macro_export]
224284
macro_rules! log_gossip {
225285
($logger: expr, $($arg:tt)*) => (
226286
$crate::log_given_level!($logger, $crate::util::logger::Level::Gossip, $($arg)*);
227287
)
228288
}
289+
290+
// Log at the `GOSSIP` level using the thread-local logger.
291+
#[macro_export]
292+
macro_rules! log_gossip_ctx {
293+
($($arg:tt)+) => {
294+
$crate::log_given_level_ctx!($crate::util::logger::Level::Gossip, $($arg)*);
295+
};
296+
}

0 commit comments

Comments
 (0)