breez_sdk_liquid/
logger.rs

1use std::fs::OpenOptions;
2use std::io::Write;
3
4use anyhow::{anyhow, Result};
5use chrono::Local;
6use log::{LevelFilter, Metadata, Record};
7
8use crate::model::LogEntry;
9
10pub(crate) struct GlobalSdkLogger {
11    /// SDK internal logger, which logs to file
12    pub(crate) logger: env_logger::Logger,
13    /// Optional external log listener, that can receive a stream of log statements
14    pub(crate) log_listener: Option<Box<dyn log::Log>>,
15}
16impl log::Log for GlobalSdkLogger {
17    fn enabled(&self, metadata: &Metadata) -> bool {
18        metadata.level() <= log::Level::Trace
19    }
20
21    fn log(&self, record: &Record) {
22        if self.enabled(record.metadata()) {
23            self.logger.log(record);
24
25            if let Some(s) = &self.log_listener.as_ref() {
26                if s.enabled(record.metadata()) {
27                    s.log(record);
28                }
29            }
30        }
31    }
32
33    fn flush(&self) {}
34}
35
36pub(super) fn init_logging(log_dir: &str, app_logger: Option<Box<dyn log::Log>>) -> Result<()> {
37    let target_log_file = Box::new(
38        OpenOptions::new()
39            .create(true)
40            .append(true)
41            .open(format!("{log_dir}/sdk.log"))
42            .map_err(|e| anyhow!("Can't create log file: {e}"))?,
43    );
44    let logger = env_logger::Builder::new()
45        .target(env_logger::Target::Pipe(target_log_file))
46        .parse_filters(
47            r#"
48                debug,
49                breez_sdk_liquid=debug,
50                breez_sdk_liquid::swapper::boltz_status_stream=info,
51                electrum_client::raw_client=warn,
52                lwk_wollet=info,
53                rustls=warn,
54                rustyline=warn,
55                ureq=info,
56                tungstenite=warn
57            "#,
58        )
59        .format(|buf, record| {
60            writeln!(
61                buf,
62                "[{} {} {}:{}] {}",
63                Local::now().format("%Y-%m-%d %H:%M:%S%.3f"),
64                record.level(),
65                record.module_path().unwrap_or("unknown"),
66                record.line().unwrap_or(0),
67                record.args()
68            )
69        })
70        .build();
71
72    let global_logger = GlobalSdkLogger {
73        logger,
74        log_listener: app_logger,
75    };
76
77    log::set_boxed_logger(Box::new(global_logger))
78        .map_err(|e| anyhow!("Failed to set global logger: {e}"))?;
79    log::set_max_level(LevelFilter::Trace);
80
81    Ok(())
82}
83
84pub trait Logger: Send + Sync {
85    fn log(&self, l: LogEntry);
86}