1use bitcoin::secp256k1::PublicKey;
17
18use core::cmp;
19use core::fmt;
20use core::ops::Deref;
21
22use crate::ln::types::ChannelId;
23#[cfg(c_bindings)]
24use crate::prelude::*; use crate::types::payment::PaymentHash;
26
27static LOG_LEVEL_NAMES: [&'static str; 6] = ["GOSSIP", "TRACE", "DEBUG", "INFO", "WARN", "ERROR"];
28
29#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
31pub enum Level {
32 Gossip,
34 Trace,
36 Debug,
38 Info,
40 Warn,
42 Error,
44}
45
46impl PartialOrd for Level {
47 #[inline]
48 fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
49 Some(self.cmp(other))
50 }
51
52 #[inline]
53 fn lt(&self, other: &Level) -> bool {
54 (*self as usize) < *other as usize
55 }
56
57 #[inline]
58 fn le(&self, other: &Level) -> bool {
59 *self as usize <= *other as usize
60 }
61
62 #[inline]
63 fn gt(&self, other: &Level) -> bool {
64 *self as usize > *other as usize
65 }
66
67 #[inline]
68 fn ge(&self, other: &Level) -> bool {
69 *self as usize >= *other as usize
70 }
71}
72
73impl Ord for Level {
74 #[inline]
75 fn cmp(&self, other: &Level) -> cmp::Ordering {
76 (*self as usize).cmp(&(*other as usize))
77 }
78}
79
80impl fmt::Display for Level {
81 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
82 fmt.pad(LOG_LEVEL_NAMES[*self as usize])
83 }
84}
85
86impl Level {
87 #[inline]
89 pub fn max() -> Level {
90 Level::Gossip
91 }
92}
93
94macro_rules! impl_record {
95 ($($args: lifetime)?, $($nonstruct_args: lifetime)?) => {
96#[derive(Clone, Debug)]
99pub struct Record<$($args)?> {
100 pub level: Level,
102 pub peer_id: Option<PublicKey>,
108 pub channel_id: Option<ChannelId>,
111 #[cfg(not(c_bindings))]
112 pub args: fmt::Arguments<'a>,
114 #[cfg(c_bindings)]
115 pub args: String,
117 pub module_path: &'static str,
119 pub file: &'static str,
121 pub line: u32,
123 pub payment_hash: Option<PaymentHash>,
128}
129
130impl<$($args)?> Record<$($args)?> {
131 #[inline]
135 pub fn new<$($nonstruct_args)?>(
136 level: Level, peer_id: Option<PublicKey>, channel_id: Option<ChannelId>,
137 args: fmt::Arguments<'a>, module_path: &'static str, file: &'static str, line: u32,
138 payment_hash: Option<PaymentHash>
139 ) -> Record<$($args)?> {
140 Record {
141 level,
142 peer_id,
143 channel_id,
144 #[cfg(not(c_bindings))]
145 args,
146 #[cfg(c_bindings)]
147 args: format!("{}", args),
148 module_path,
149 file,
150 line,
151 payment_hash,
152 }
153 }
154}
155} }
156#[cfg(not(c_bindings))]
157impl_record!('a, );
158#[cfg(c_bindings)]
159impl_record!(, 'a);
160
161pub trait Logger {
163 fn log(&self, record: Record);
165}
166
167pub struct WithContext<'a, L: Deref>
172where
173 L::Target: Logger,
174{
175 logger: &'a L,
177 peer_id: Option<PublicKey>,
179 channel_id: Option<ChannelId>,
181 payment_hash: Option<PaymentHash>,
183}
184
185impl<'a, L: Deref> Logger for WithContext<'a, L>
186where
187 L::Target: Logger,
188{
189 fn log(&self, mut record: Record) {
190 if self.peer_id.is_some() {
191 record.peer_id = self.peer_id
192 };
193 if self.channel_id.is_some() {
194 record.channel_id = self.channel_id;
195 }
196 if self.payment_hash.is_some() {
197 record.payment_hash = self.payment_hash;
198 }
199 self.logger.log(record)
200 }
201}
202
203impl<'a, L: Deref> WithContext<'a, L>
204where
205 L::Target: Logger,
206{
207 pub fn from(
209 logger: &'a L, peer_id: Option<PublicKey>, channel_id: Option<ChannelId>,
210 payment_hash: Option<PaymentHash>,
211 ) -> Self {
212 WithContext { logger, peer_id, channel_id, payment_hash }
213 }
214}
215
216#[doc(hidden)]
220pub struct DebugPubKey<'a>(pub &'a PublicKey);
221impl<'a> core::fmt::Display for DebugPubKey<'a> {
222 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
223 for i in self.0.serialize().iter() {
224 write!(f, "{:02x}", i)?;
225 }
226 Ok(())
227 }
228}
229
230#[doc(hidden)]
234pub struct DebugBytes<'a>(pub &'a [u8]);
235impl<'a> core::fmt::Display for DebugBytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
237 for i in self.0 {
238 write!(f, "{:02x}", i)?;
239 }
240 Ok(())
241 }
242}
243
244#[doc(hidden)]
248pub struct DebugIter<T: fmt::Display, I: core::iter::Iterator<Item = T> + Clone>(pub I);
249impl<T: fmt::Display, I: core::iter::Iterator<Item = T> + Clone> fmt::Display for DebugIter<T, I> {
250 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
251 write!(f, "[")?;
252 let mut iter = self.0.clone();
253 if let Some(item) = iter.next() {
254 write!(f, "{}", item)?;
255 }
256 for item in iter {
257 write!(f, ", {}", item)?;
258 }
259 write!(f, "]")?;
260 Ok(())
261 }
262}
263
264#[cfg(test)]
265mod tests {
266 use crate::ln::types::ChannelId;
267 use crate::sync::Arc;
268 use crate::types::payment::PaymentHash;
269 use crate::util::logger::{Level, Logger, WithContext};
270 use crate::util::test_utils::TestLogger;
271 use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
272
273 #[test]
274 fn test_level_show() {
275 assert_eq!("INFO", Level::Info.to_string());
276 assert_eq!("ERROR", Level::Error.to_string());
277 assert_ne!("WARN", Level::Error.to_string());
278 }
279
280 struct WrapperLog {
281 logger: Arc<dyn Logger>,
282 }
283
284 impl WrapperLog {
285 fn new(logger: Arc<dyn Logger>) -> WrapperLog {
286 WrapperLog { logger }
287 }
288
289 fn call_macros(&self) {
290 log_error!(self.logger, "This is an error");
291 log_warn!(self.logger, "This is a warning");
292 log_info!(self.logger, "This is an info");
293 log_debug!(self.logger, "This is a debug");
294 log_trace!(self.logger, "This is a trace");
295 log_gossip!(self.logger, "This is a gossip");
296 }
297 }
298
299 #[test]
300 fn test_logging_macros() {
301 let logger = TestLogger::new();
302 let logger: Arc<dyn Logger> = Arc::new(logger);
303 let wrapper = WrapperLog::new(Arc::clone(&logger));
304 wrapper.call_macros();
305 }
306
307 #[test]
308 fn test_logging_with_context() {
309 let logger = &TestLogger::new();
310 let secp_ctx = Secp256k1::new();
311 let pk = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
312 let payment_hash = PaymentHash([0; 32]);
313 let context_logger =
314 WithContext::from(&logger, Some(pk), Some(ChannelId([0; 32])), Some(payment_hash));
315 log_error!(context_logger, "This is an error");
316 log_warn!(context_logger, "This is an error");
317 log_debug!(context_logger, "This is an error");
318 log_trace!(context_logger, "This is an error");
319 log_gossip!(context_logger, "This is an error");
320 log_info!(context_logger, "This is an error");
321 logger.assert_log_context_contains(
322 "lightning::util::logger::tests",
323 Some(pk),
324 Some(ChannelId([0; 32])),
325 6,
326 );
327 }
328
329 #[test]
330 fn test_logging_with_multiple_wrapped_context() {
331 let logger = &TestLogger::new();
332 let secp_ctx = Secp256k1::new();
333 let pk = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
334 let payment_hash = PaymentHash([0; 32]);
335 let context_logger =
336 &WithContext::from(&logger, None, Some(ChannelId([0; 32])), Some(payment_hash));
337 let full_context_logger = WithContext::from(&context_logger, Some(pk), None, None);
338 log_error!(full_context_logger, "This is an error");
339 log_warn!(full_context_logger, "This is an error");
340 log_debug!(full_context_logger, "This is an error");
341 log_trace!(full_context_logger, "This is an error");
342 log_gossip!(full_context_logger, "This is an error");
343 log_info!(full_context_logger, "This is an error");
344 logger.assert_log_context_contains(
345 "lightning::util::logger::tests",
346 Some(pk),
347 Some(ChannelId([0; 32])),
348 6,
349 );
350 }
351
352 #[test]
353 fn test_log_ordering() {
354 assert!(Level::Error > Level::Warn);
355 assert!(Level::Error >= Level::Warn);
356 assert!(Level::Error >= Level::Error);
357 assert!(Level::Warn > Level::Info);
358 assert!(Level::Warn >= Level::Info);
359 assert!(Level::Warn >= Level::Warn);
360 assert!(Level::Info > Level::Debug);
361 assert!(Level::Info >= Level::Debug);
362 assert!(Level::Info >= Level::Info);
363 assert!(Level::Debug > Level::Trace);
364 assert!(Level::Debug >= Level::Trace);
365 assert!(Level::Debug >= Level::Debug);
366 assert!(Level::Trace > Level::Gossip);
367 assert!(Level::Trace >= Level::Gossip);
368 assert!(Level::Trace >= Level::Trace);
369 assert!(Level::Gossip >= Level::Gossip);
370
371 assert!(Level::Error <= Level::Error);
372 assert!(Level::Warn < Level::Error);
373 assert!(Level::Warn <= Level::Error);
374 assert!(Level::Warn <= Level::Warn);
375 assert!(Level::Info < Level::Warn);
376 assert!(Level::Info <= Level::Warn);
377 assert!(Level::Info <= Level::Info);
378 assert!(Level::Debug < Level::Info);
379 assert!(Level::Debug <= Level::Info);
380 assert!(Level::Debug <= Level::Debug);
381 assert!(Level::Trace < Level::Debug);
382 assert!(Level::Trace <= Level::Debug);
383 assert!(Level::Trace <= Level::Trace);
384 assert!(Level::Gossip < Level::Trace);
385 assert!(Level::Gossip <= Level::Trace);
386 assert!(Level::Gossip <= Level::Gossip);
387 }
388}