From 7257696ee634f6a3c87841dca19f433f24148542 Mon Sep 17 00:00:00 2001 From: Enigbe Ochekliye Date: Mon, 18 Nov 2024 21:59:53 +0100 Subject: [PATCH 01/13] feat(logger): implement configurable log writer with filesystem support * Add flexible log writer interface for multiple destinations * Implement filesystem writing capability via FilesystemLogger * Prefix LDK-based objects with 'Ldk' for consistency * Add configuration options for log file path and log level --- bindings/ldk_node.udl | 26 ++++++---- src/builder.rs | 90 +++++++++++++++++++-------------- src/chain/mod.rs | 14 ++--- src/config.rs | 37 +++++++++----- src/connection.rs | 6 +-- src/event.rs | 12 ++--- src/gossip.rs | 8 +-- src/io/utils.rs | 29 +++++------ src/lib.rs | 19 +++---- src/liquidity.rs | 6 +-- src/logger.rs | 58 ++++++++++++++------- src/payment/bolt11.rs | 22 ++++---- src/payment/bolt12.rs | 10 ++-- src/payment/onchain.rs | 6 +-- src/payment/spontaneous.rs | 9 ++-- src/payment/store.rs | 6 +-- src/payment/unified_qr.rs | 6 +-- src/peer_store.rs | 8 +-- src/tx_broadcaster.rs | 8 +-- src/types.rs | 43 ++++++++-------- src/wallet/mod.rs | 24 ++++----- src/wallet/persist.rs | 8 ++- tests/common/mod.rs | 5 +- tests/integration_tests_rust.rs | 7 ++- 24 files changed, 255 insertions(+), 212 deletions(-) diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index bc99c1783..331ced3f0 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -5,13 +5,11 @@ namespace ldk_node { dictionary Config { string storage_dir_path; - string? log_file_path; Network network; sequence? listening_addresses; NodeAlias? node_alias; sequence trusted_peers_0conf; u64 probing_liquidity_limit_multiplier; - LogLevel log_level; AnchorChannelsConfig? anchor_channels_config; SendingParameters? sending_parameters; }; @@ -27,6 +25,20 @@ dictionary EsploraSyncConfig { u64 fee_rate_cache_update_interval_secs; }; +enum LdkLevel { + "Gossip", + "Trace", + "Debug", + "Info", + "Warn", + "Error", +}; + +dictionary FilesystemLoggerConfig { + string log_file_path; + LdkLevel level; +}; + interface Builder { constructor(); [Name=from_config] @@ -41,6 +53,7 @@ interface Builder { void set_gossip_source_rgs(string rgs_server_url); void set_liquidity_source_lsps2(SocketAddress address, PublicKey node_id, string? token); void set_storage_dir_path(string storage_dir_path); + void set_filesystem_logger(FilesystemLoggerConfig fs_config); void set_network(Network network); [Throws=BuildError] void set_listening_addresses(sequence listening_addresses); @@ -514,15 +527,6 @@ interface MaxDustHTLCExposure { FeeRateMultiplier ( u64 multiplier ); }; -enum LogLevel { - "Gossip", - "Trace", - "Debug", - "Info", - "Warn", - "Error", -}; - interface NetworkGraph { sequence list_channels(); ChannelInfo? channel(u64 short_channel_id); diff --git a/src/builder.rs b/src/builder.rs index fac2ae0c5..b61db9694 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -6,7 +6,9 @@ // accordance with one or both of these licenses. use crate::chain::{ChainSource, DEFAULT_ESPLORA_SERVER_URL}; -use crate::config::{default_user_config, Config, EsploraSyncConfig, WALLET_KEYS_SEED_LEN}; +use crate::config::{ + default_user_config, Config, EsploraSyncConfig, FilesystemLoggerConfig, WALLET_KEYS_SEED_LEN, +}; use crate::connection::ConnectionManager; use crate::event::EventQueue; @@ -16,7 +18,7 @@ use crate::io::sqlite_store::SqliteStore; use crate::io::utils::{read_node_metrics, write_node_metrics}; use crate::io::vss_store::VssStore; use crate::liquidity::LiquiditySource; -use crate::logger::{log_error, log_info, FilesystemLogger, Logger}; +use crate::logger::{log_error, log_info, LdkLogger, Logger}; use crate::message_handler::NodeCustomMessageHandler; use crate::payment::store::PaymentStore; use crate::peer_store::PeerStore; @@ -27,8 +29,8 @@ use crate::types::{ }; use crate::wallet::persist::KVStoreWalletPersister; use crate::wallet::Wallet; +use crate::Node; use crate::{io, NodeMetrics}; -use crate::{LogLevel, Node}; use lightning::chain::{chainmonitor, BestBlock, Watch}; use lightning::io::Cursor; @@ -106,6 +108,17 @@ impl Default for LiquiditySourceConfig { } } +#[derive(Debug)] +enum LogWriterConfig { + File(FilesystemLoggerConfig), +} + +impl Default for LogWriterConfig { + fn default() -> Self { + Self::File(FilesystemLoggerConfig::default()) + } +} + /// An error encountered during building a [`Node`]. /// /// [`Node`]: crate::Node @@ -182,6 +195,7 @@ pub struct NodeBuilder { chain_data_source_config: Option, gossip_source_config: Option, liquidity_source_config: Option, + log_writer_config: Option, } impl NodeBuilder { @@ -197,12 +211,14 @@ impl NodeBuilder { let chain_data_source_config = None; let gossip_source_config = None; let liquidity_source_config = None; + let log_writer_config = None; Self { config, entropy_source_config, chain_data_source_config, gossip_source_config, liquidity_source_config, + log_writer_config, } } @@ -298,9 +314,9 @@ impl NodeBuilder { self } - /// Sets the log file path if the log file needs to live separate from the storage directory path. - pub fn set_log_file_path(&mut self, log_dir_path: String) -> &mut Self { - self.config.log_file_path = Some(log_dir_path); + /// Configures the [`Node`] instance to write logs to the filesystem. + pub fn set_filesystem_logger(&mut self, fs_config: FilesystemLoggerConfig) -> &mut Self { + self.log_writer_config = Some(LogWriterConfig::File(fs_config)); self } @@ -333,12 +349,6 @@ impl NodeBuilder { Ok(self) } - /// Sets the level at which [`Node`] will log messages. - pub fn set_log_level(&mut self, level: LogLevel) -> &mut Self { - self.config.log_level = level; - self - } - /// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options /// previously configured. pub fn build(&self) -> Result { @@ -391,7 +401,10 @@ impl NodeBuilder { ) -> Result { use bitcoin::key::Secp256k1; - let logger = setup_logger(&self.config)?; + let writer = LogWriterConfig::default(); + let log_writer_config = + if let Some(config) = &self.log_writer_config { config } else { &writer }; + let logger = setup_logger(&log_writer_config)?; let seed_bytes = seed_bytes_from_config( &self.config, @@ -456,7 +469,10 @@ impl NodeBuilder { pub fn build_with_vss_store_and_header_provider( &self, vss_url: String, store_id: String, header_provider: Arc, ) -> Result { - let logger = setup_logger(&self.config)?; + let writer = LogWriterConfig::default(); + let log_writer_config = + if let Some(config) = &self.log_writer_config { config } else { &writer }; + let logger = setup_logger(&log_writer_config)?; let seed_bytes = seed_bytes_from_config( &self.config, @@ -488,7 +504,11 @@ impl NodeBuilder { /// Builds a [`Node`] instance according to the options previously configured. pub fn build_with_store(&self, kv_store: Arc) -> Result { - let logger = setup_logger(&self.config)?; + let writer = LogWriterConfig::default(); + let log_writer_config = + if let Some(config) = &self.log_writer_config { config } else { &writer }; + let logger = setup_logger(&log_writer_config)?; + let seed_bytes = seed_bytes_from_config( &self.config, self.entropy_source_config.as_ref(), @@ -610,9 +630,9 @@ impl ArcedNodeBuilder { self.inner.write().unwrap().set_storage_dir_path(storage_dir_path); } - /// Sets the log file path if logs need to live separate from the storage directory path. - pub fn set_log_file_path(&self, log_file_path: String) { - self.inner.write().unwrap().set_log_file_path(log_file_path); + /// Configures the [`Node`] instance to write logs to the filesystem. + pub fn set_filesystem_logger(&self, fs_config: FilesystemLoggerConfig) { + self.inner.write().unwrap().set_filesystem_logger(fs_config); } /// Sets the Bitcoin network used. @@ -635,11 +655,6 @@ impl ArcedNodeBuilder { self.inner.write().unwrap().set_node_alias(node_alias).map(|_| ()) } - /// Sets the level at which [`Node`] will log messages. - pub fn set_log_level(&self, level: LogLevel) { - self.inner.write().unwrap().set_log_level(level); - } - /// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options /// previously configured. pub fn build(&self) -> Result, BuildError> { @@ -734,7 +749,7 @@ fn build_with_store_internal( config: Arc, chain_data_source_config: Option<&ChainDataSourceConfig>, gossip_source_config: Option<&GossipSourceConfig>, liquidity_source_config: Option<&LiquiditySourceConfig>, seed_bytes: [u8; 64], - logger: Arc, kv_store: Arc, + logger: Arc, kv_store: Arc, ) -> Result { // Initialize the status fields. let is_listening = Arc::new(AtomicBool::new(false)); @@ -1231,23 +1246,22 @@ fn build_with_store_internal( }) } -/// Sets up the node logger, creating a new log file if it does not exist, or utilizing -/// the existing log file. -fn setup_logger(config: &Config) -> Result, BuildError> { - let log_file_path = match &config.log_file_path { - Some(log_dir) => String::from(log_dir), - None => format!("{}/{}", config.storage_dir_path.clone(), "ldk_node.log"), - }; +/// Sets up the node logger. +fn setup_logger(config: &LogWriterConfig) -> Result, BuildError> { + match config { + LogWriterConfig::File(fs_logger_config) => { + let log_file_path = &fs_logger_config.log_file_path; - Ok(Arc::new( - FilesystemLogger::new(log_file_path, config.log_level) - .map_err(|_| BuildError::LoggerSetupFailed)?, - )) + Ok(Arc::new( + Logger::new_fs_writer(log_file_path.to_string(), fs_logger_config.level) + .map_err(|_| BuildError::LoggerSetupFailed)?, + )) + }, + } } fn seed_bytes_from_config( - config: &Config, entropy_source_config: Option<&EntropySourceConfig>, - logger: Arc, + config: &Config, entropy_source_config: Option<&EntropySourceConfig>, logger: Arc, ) -> Result<[u8; 64], BuildError> { match entropy_source_config { Some(EntropySourceConfig::SeedBytes(bytes)) => Ok(bytes.clone()), @@ -1269,7 +1283,7 @@ fn seed_bytes_from_config( } fn derive_vss_xprv( - config: Arc, seed_bytes: &[u8; 64], logger: Arc, + config: Arc, seed_bytes: &[u8; 64], logger: Arc, ) -> Result { use bitcoin::key::Secp256k1; diff --git a/src/chain/mod.rs b/src/chain/mod.rs index 6c89476d2..f8bc3a6db 100644 --- a/src/chain/mod.rs +++ b/src/chain/mod.rs @@ -21,7 +21,7 @@ use crate::fee_estimator::{ ConfirmationTarget, OnchainFeeEstimator, }; use crate::io::utils::write_node_metrics; -use crate::logger::{log_bytes, log_error, log_info, log_trace, FilesystemLogger, Logger}; +use crate::logger::{log_bytes, log_error, log_info, log_trace, LdkLogger, Logger}; use crate::types::{Broadcaster, ChainMonitor, ChannelManager, DynStore, Sweeper, Wallet}; use crate::{Error, NodeMetrics}; @@ -112,13 +112,13 @@ pub(crate) enum ChainSource { esplora_client: EsploraAsyncClient, onchain_wallet: Arc, onchain_wallet_sync_status: Mutex, - tx_sync: Arc>>, + tx_sync: Arc>>, lightning_wallet_sync_status: Mutex, fee_estimator: Arc, tx_broadcaster: Arc, kv_store: Arc, config: Arc, - logger: Arc, + logger: Arc, node_metrics: Arc>, }, BitcoindRpc { @@ -131,7 +131,7 @@ pub(crate) enum ChainSource { tx_broadcaster: Arc, kv_store: Arc, config: Arc, - logger: Arc, + logger: Arc, node_metrics: Arc>, }, } @@ -140,7 +140,7 @@ impl ChainSource { pub(crate) fn new_esplora( server_url: String, sync_config: EsploraSyncConfig, onchain_wallet: Arc, fee_estimator: Arc, tx_broadcaster: Arc, - kv_store: Arc, config: Arc, logger: Arc, + kv_store: Arc, config: Arc, logger: Arc, node_metrics: Arc>, ) -> Self { let mut client_builder = esplora_client::Builder::new(&server_url); @@ -170,7 +170,7 @@ impl ChainSource { host: String, port: u16, rpc_user: String, rpc_password: String, onchain_wallet: Arc, fee_estimator: Arc, tx_broadcaster: Arc, kv_store: Arc, config: Arc, - logger: Arc, node_metrics: Arc>, + logger: Arc, node_metrics: Arc>, ) -> Self { let bitcoind_rpc_client = Arc::new(BitcoindRpcClient::new(host, port, rpc_user, rpc_password)); @@ -1123,7 +1123,7 @@ impl Filter for ChainSource { fn periodically_archive_fully_resolved_monitors( channel_manager: Arc, chain_monitor: Arc, - kv_store: Arc, logger: Arc, node_metrics: Arc>, + kv_store: Arc, logger: Arc, node_metrics: Arc>, ) -> Result<(), Error> { let mut locked_node_metrics = node_metrics.write().unwrap(); let cur_height = channel_manager.current_best_block().height; diff --git a/src/config.rs b/src/config.rs index 00b147e21..1820a577a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,6 +7,7 @@ //! Objects for configuring the node. +use crate::logger::LdkLevel; use crate::payment::SendingParameters; use lightning::ln::msgs::SocketAddress; @@ -14,7 +15,6 @@ use lightning::routing::gossip::NodeAlias; use lightning::util::config::ChannelConfig as LdkChannelConfig; use lightning::util::config::MaxDustHTLCExposure as LdkMaxDustHTLCExposure; use lightning::util::config::UserConfig; -use lightning::util::logger::Level as LogLevel; use bitcoin::secp256k1::PublicKey; use bitcoin::Network; @@ -22,14 +22,15 @@ use bitcoin::Network; use std::time::Duration; // Config defaults -const DEFAULT_STORAGE_DIR_PATH: &str = "/tmp/ldk_node/"; +const DEFAULT_STORAGE_DIR_PATH: &str = "/tmp/ldk_node"; const DEFAULT_NETWORK: Network = Network::Bitcoin; const DEFAULT_BDK_WALLET_SYNC_INTERVAL_SECS: u64 = 80; const DEFAULT_LDK_WALLET_SYNC_INTERVAL_SECS: u64 = 30; const DEFAULT_FEE_RATE_CACHE_UPDATE_INTERVAL_SECS: u64 = 60 * 10; const DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER: u64 = 3; -const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Debug; const DEFAULT_ANCHOR_PER_CHANNEL_RESERVE_SATS: u64 = 25_000; +const DEFAULT_LOG_FILE_PATH: &'static str = "ldk_node.log"; +const DEFAULT_LOG_LEVEL: LdkLevel = LdkLevel::Debug; // The 'stop gap' parameter used by BDK's wallet sync. This seems to configure the threshold // number of derivation indexes after which BDK stops looking for new scripts belonging to the wallet. @@ -103,11 +104,6 @@ pub(crate) const WALLET_KEYS_SEED_LEN: usize = 64; pub struct Config { /// The path where the underlying LDK and BDK persist their data. pub storage_dir_path: String, - /// The path where logs are stored. - /// - /// If set to `None`, logs can be found in `ldk_node.log` in the [`Config::storage_dir_path`] - /// directory. - pub log_file_path: Option, /// The used Bitcoin network. pub network: Network, /// The addresses on which the node will listen for incoming connections. @@ -133,10 +129,6 @@ pub struct Config { /// Channels with available liquidity less than the required amount times this value won't be /// used to send pre-flight probes. pub probing_liquidity_limit_multiplier: u64, - /// The level at which we log messages. - /// - /// Any messages below this level will be excluded from the logs. - pub log_level: LogLevel, /// Configuration options pertaining to Anchor channels, i.e., channels for which the /// `option_anchors_zero_fee_htlc_tx` channel type is negotiated. /// @@ -168,12 +160,10 @@ impl Default for Config { fn default() -> Self { Self { storage_dir_path: DEFAULT_STORAGE_DIR_PATH.to_string(), - log_file_path: None, network: DEFAULT_NETWORK, listening_addresses: None, trusted_peers_0conf: Vec::new(), probing_liquidity_limit_multiplier: DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER, - log_level: DEFAULT_LOG_LEVEL, anchor_channels_config: Some(AnchorChannelsConfig::default()), sending_parameters: None, node_alias: None, @@ -439,6 +429,25 @@ impl From for LdkMaxDustHTLCExposure { } } +/// Configuration options for logging to the filesystem. +#[derive(Debug)] +pub struct FilesystemLoggerConfig { + /// The log file path. + /// + /// This specifies the log file path if a destination other than the storage + /// directory, i.e. [`Config::storage_dir_path`], is preferred. + pub log_file_path: String, + /// This specifies the log level. + pub level: LdkLevel, +} + +impl Default for FilesystemLoggerConfig { + fn default() -> Self { + let log_file_path = format!("{}/{}", DEFAULT_STORAGE_DIR_PATH, DEFAULT_LOG_FILE_PATH); + Self { log_file_path, level: DEFAULT_LOG_LEVEL } + } +} + #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/src/connection.rs b/src/connection.rs index 5f665f77e..c4cde717a 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -5,7 +5,7 @@ // http://opensource.org/licenses/MIT>, at your option. You may not use this file except in // accordance with one or both of these licenses. -use crate::logger::{log_error, log_info, Logger}; +use crate::logger::{log_error, log_info, LdkLogger}; use crate::types::PeerManager; use crate::Error; @@ -21,7 +21,7 @@ use std::time::Duration; pub(crate) struct ConnectionManager where - L::Target: Logger, + L::Target: LdkLogger, { pending_connections: Mutex>>>>, @@ -31,7 +31,7 @@ where impl ConnectionManager where - L::Target: Logger, + L::Target: LdkLogger, { pub(crate) fn new(peer_manager: Arc, logger: L) -> Self { let pending_connections = Mutex::new(HashMap::new()); diff --git a/src/event.rs b/src/event.rs index 5f5812cdb..42a421df4 100644 --- a/src/event.rs +++ b/src/event.rs @@ -24,7 +24,7 @@ use crate::io::{ EVENT_QUEUE_PERSISTENCE_KEY, EVENT_QUEUE_PERSISTENCE_PRIMARY_NAMESPACE, EVENT_QUEUE_PERSISTENCE_SECONDARY_NAMESPACE, }; -use crate::logger::{log_debug, log_error, log_info, Logger}; +use crate::logger::{log_debug, log_error, log_info, LdkLogger}; use lightning::events::bump_transaction::BumpTransactionEvent; use lightning::events::{ClosureReason, PaymentPurpose, ReplayEvent}; @@ -269,7 +269,7 @@ impl_writeable_tlv_based_enum!(Event, pub struct EventQueue where - L::Target: Logger, + L::Target: LdkLogger, { queue: Arc>>, waker: Arc>>, @@ -280,7 +280,7 @@ where impl EventQueue where - L::Target: Logger, + L::Target: LdkLogger, { pub(crate) fn new(kv_store: Arc, logger: L) -> Self { let queue = Arc::new(Mutex::new(VecDeque::new())); @@ -359,7 +359,7 @@ where impl ReadableArgs<(Arc, L)> for EventQueue where - L::Target: Logger, + L::Target: LdkLogger, { #[inline] fn read( @@ -423,7 +423,7 @@ impl Future for EventFuture { pub(crate) struct EventHandler where - L::Target: Logger, + L::Target: LdkLogger, { event_queue: Arc>, wallet: Arc, @@ -441,7 +441,7 @@ where impl EventHandler where - L::Target: Logger, + L::Target: LdkLogger, { pub fn new( event_queue: Arc>, wallet: Arc, diff --git a/src/gossip.rs b/src/gossip.rs index 450b5b5ee..f49a9a6d1 100644 --- a/src/gossip.rs +++ b/src/gossip.rs @@ -6,7 +6,7 @@ // accordance with one or both of these licenses. use crate::config::RGS_SYNC_TIMEOUT_SECS; -use crate::logger::{log_trace, FilesystemLogger, Logger}; +use crate::logger::{log_trace, LdkLogger, Logger}; use crate::types::{GossipSync, Graph, P2PGossipSync, RapidGossipSync}; use crate::Error; @@ -24,12 +24,12 @@ pub(crate) enum GossipSource { gossip_sync: Arc, server_url: String, latest_sync_timestamp: AtomicU32, - logger: Arc, + logger: Arc, }, } impl GossipSource { - pub fn new_p2p(network_graph: Arc, logger: Arc) -> Self { + pub fn new_p2p(network_graph: Arc, logger: Arc) -> Self { let gossip_sync = Arc::new(P2PGossipSync::new( network_graph, None::>, @@ -40,7 +40,7 @@ impl GossipSource { pub fn new_rgs( server_url: String, latest_sync_timestamp: u32, network_graph: Arc, - logger: Arc, + logger: Arc, ) -> Self { let gossip_sync = Arc::new(RapidGossipSync::new(network_graph, Arc::clone(&logger))); let latest_sync_timestamp = AtomicU32::new(latest_sync_timestamp); diff --git a/src/io/utils.rs b/src/io/utils.rs index 218fec473..8b2d3b77a 100644 --- a/src/io/utils.rs +++ b/src/io/utils.rs @@ -13,7 +13,7 @@ use crate::fee_estimator::OnchainFeeEstimator; use crate::io::{ NODE_METRICS_KEY, NODE_METRICS_PRIMARY_NAMESPACE, NODE_METRICS_SECONDARY_NAMESPACE, }; -use crate::logger::{log_error, FilesystemLogger}; +use crate::logger::{log_error, LdkLogger, Logger}; use crate::peer_store::PeerStore; use crate::sweep::DeprecatedSpendableOutputInfo; use crate::types::{Broadcaster, DynStore, KeysManager, Sweeper}; @@ -24,7 +24,6 @@ use lightning::io::Cursor; use lightning::ln::msgs::DecodeError; use lightning::routing::gossip::NetworkGraph; use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringDecayParameters}; -use lightning::util::logger::Logger; use lightning::util::persist::{ KVSTORE_NAMESPACE_KEY_ALPHABET, KVSTORE_NAMESPACE_KEY_MAX_LEN, NETWORK_GRAPH_PERSISTENCE_KEY, NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE, NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE, @@ -72,7 +71,7 @@ pub(crate) fn read_or_generate_seed_file( keys_seed_path: &str, logger: L, ) -> std::io::Result<[u8; WALLET_KEYS_SEED_LEN]> where - L::Target: Logger, + L::Target: LdkLogger, { if Path::new(&keys_seed_path).exists() { let seed = fs::read(keys_seed_path).map_err(|e| { @@ -123,7 +122,7 @@ pub(crate) fn read_network_graph( kv_store: Arc, logger: L, ) -> Result, std::io::Error> where - L::Target: Logger, + L::Target: LdkLogger, { let mut reader = Cursor::new(kv_store.read( NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE, @@ -141,7 +140,7 @@ pub(crate) fn read_scorer>, L: Deref + Clone>( kv_store: Arc, network_graph: G, logger: L, ) -> Result, std::io::Error> where - L::Target: Logger, + L::Target: LdkLogger, { let params = ProbabilisticScoringDecayParameters::default(); let mut reader = Cursor::new(kv_store.read( @@ -161,7 +160,7 @@ pub(crate) fn read_event_queue( kv_store: Arc, logger: L, ) -> Result, std::io::Error> where - L::Target: Logger, + L::Target: LdkLogger, { let mut reader = Cursor::new(kv_store.read( EVENT_QUEUE_PERSISTENCE_PRIMARY_NAMESPACE, @@ -179,7 +178,7 @@ pub(crate) fn read_peer_info( kv_store: Arc, logger: L, ) -> Result, std::io::Error> where - L::Target: Logger, + L::Target: LdkLogger, { let mut reader = Cursor::new(kv_store.read( PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, @@ -197,7 +196,7 @@ pub(crate) fn read_payments( kv_store: Arc, logger: L, ) -> Result, std::io::Error> where - L::Target: Logger, + L::Target: LdkLogger, { let mut res = Vec::new(); @@ -226,7 +225,7 @@ where pub(crate) fn read_output_sweeper( broadcaster: Arc, fee_estimator: Arc, chain_data_source: Arc, keys_manager: Arc, kv_store: Arc, - logger: Arc, + logger: Arc, ) -> Result { let mut reader = Cursor::new(kv_store.read( OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE, @@ -264,7 +263,7 @@ pub(crate) fn migrate_deprecated_spendable_outputs( sweeper: Arc, kv_store: Arc, logger: L, ) -> Result<(), std::io::Error> where - L::Target: Logger, + L::Target: LdkLogger, { let best_block = sweeper.current_best_block(); @@ -349,7 +348,7 @@ pub(crate) fn read_node_metrics( kv_store: Arc, logger: L, ) -> Result where - L::Target: Logger, + L::Target: LdkLogger, { let mut reader = Cursor::new(kv_store.read( NODE_METRICS_PRIMARY_NAMESPACE, @@ -366,7 +365,7 @@ pub(crate) fn write_node_metrics( node_metrics: &NodeMetrics, kv_store: Arc, logger: L, ) -> Result<(), Error> where - L::Target: Logger, + L::Target: LdkLogger, { let data = node_metrics.encode(); kv_store @@ -486,7 +485,7 @@ macro_rules! impl_read_write_change_set_type { kv_store: Arc, logger: L, ) -> Result, std::io::Error> where - L::Target: Logger, + L::Target: LdkLogger, { let bytes = match kv_store.read($primary_namespace, $secondary_namespace, $key) { Ok(bytes) => bytes, @@ -526,7 +525,7 @@ macro_rules! impl_read_write_change_set_type { value: &$change_set_type, kv_store: Arc, logger: L, ) -> Result<(), std::io::Error> where - L::Target: Logger, + L::Target: LdkLogger, { let data = ChangeSetSerWrapper(value).encode(); kv_store.write($primary_namespace, $secondary_namespace, $key, &data).map_err(|e| { @@ -600,7 +599,7 @@ impl_read_write_change_set_type!( // Reads the full BdkWalletChangeSet or returns default fields pub(crate) fn read_bdk_wallet_change_set( - kv_store: Arc, logger: Arc, + kv_store: Arc, logger: Arc, ) -> Result, std::io::Error> { let mut change_set = BdkWalletChangeSet::default(); diff --git a/src/lib.rs b/src/lib.rs index 363812292..e7b44b3d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,6 +110,9 @@ pub use event::Event; pub use io::utils::generate_entropy_mnemonic; +pub use config::FilesystemLoggerConfig; +pub use logger::LdkLevel; + #[cfg(feature = "uniffi")] use uniffi_types::*; @@ -142,7 +145,7 @@ use types::{ }; pub use types::{ChannelDetails, CustomTlvRecord, PeerDetails, UserChannelId}; -use logger::{log_error, log_info, log_trace, FilesystemLogger, Logger}; +use logger::{log_error, log_info, log_trace, LdkLogger, Logger}; use lightning::chain::BestBlock; use lightning::events::bump_transaction::Wallet as LdkWallet; @@ -152,8 +155,6 @@ use lightning::ln::channelmanager::PaymentId; use lightning::ln::msgs::SocketAddress; use lightning::routing::gossip::NodeAlias; -pub use lightning::util::logger::Level as LogLevel; - use lightning_background_processor::process_events_async; use bitcoin::secp256k1::PublicKey; @@ -180,23 +181,23 @@ pub struct Node { wallet: Arc, chain_source: Arc, tx_broadcaster: Arc, - event_queue: Arc>>, + event_queue: Arc>>, channel_manager: Arc, chain_monitor: Arc, output_sweeper: Arc, peer_manager: Arc, onion_messenger: Arc, - connection_manager: Arc>>, + connection_manager: Arc>>, keys_manager: Arc, network_graph: Arc, gossip_source: Arc, - liquidity_source: Option>>>, + liquidity_source: Option>>>, kv_store: Arc, - logger: Arc, + logger: Arc, _router: Arc, scorer: Arc>, - peer_store: Arc>>, - payment_store: Arc>>, + peer_store: Arc>>, + payment_store: Arc>>, is_listening: Arc, node_metrics: Arc>, } diff --git a/src/liquidity.rs b/src/liquidity.rs index 1dfb5453a..557bfddb0 100644 --- a/src/liquidity.rs +++ b/src/liquidity.rs @@ -5,7 +5,7 @@ // http://opensource.org/licenses/MIT>, at your option. You may not use this file except in // accordance with one or both of these licenses. -use crate::logger::{log_debug, log_error, log_info, Logger}; +use crate::logger::{log_debug, log_error, log_info, LdkLogger}; use crate::types::{ChannelManager, KeysManager, LiquidityManager, PeerManager}; use crate::{Config, Error}; @@ -41,7 +41,7 @@ struct LSPS2Service { pub(crate) struct LiquiditySource where - L::Target: Logger, + L::Target: LdkLogger, { lsps2_service: Option, channel_manager: Arc, @@ -53,7 +53,7 @@ where impl LiquiditySource where - L::Target: Logger, + L::Target: LdkLogger, { pub(crate) fn new_lsps2( address: SocketAddress, node_id: PublicKey, token: Option, diff --git a/src/logger.rs b/src/logger.rs index bde4faff0..904aeee98 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -5,10 +5,11 @@ // http://opensource.org/licenses/MIT>, at your option. You may not use this file except in // accordance with one or both of these licenses. -pub(crate) use lightning::util::logger::Logger; +pub(crate) use lightning::util::logger::Logger as LdkLogger; pub(crate) use lightning::{log_bytes, log_debug, log_error, log_info, log_trace}; -use lightning::util::logger::{Level, Record}; +pub use lightning::util::logger::Level as LdkLevel; +use lightning::util::logger::Record; use chrono::Utc; @@ -18,12 +19,24 @@ use std::path::Path; pub(crate) struct FilesystemLogger { file_path: String, - level: Level, + level: LdkLevel, } -impl FilesystemLogger { - /// Creates a new filesystem logger given the path to the log file and the log level. - pub(crate) fn new(log_file_path: String, level: Level) -> Result { +/// Defines a writer for [`Logger`]. +pub(crate) enum Writer { + /// Writes logs to the file system. + FileWriter(FilesystemLogger), +} + +pub(crate) struct Logger { + /// Specifies the logger's writer. + writer: Writer, +} + +impl Logger { + /// Creates a new logger with a filesystem writer. The parameters to this function + /// are the path to the log file, and the log level. + pub fn new_fs_writer(log_file_path: String, level: LdkLevel) -> Result { if let Some(parent_dir) = Path::new(&log_file_path).parent() { fs::create_dir_all(parent_dir) .map_err(|e| eprintln!("ERROR: Failed to create log parent directory: {}", e))?; @@ -36,14 +49,14 @@ impl FilesystemLogger { .map_err(|e| eprintln!("ERROR: Failed to open log file: {}", e))?; } - Ok(Self { file_path: log_file_path, level }) + let fs_writer = FilesystemLogger { file_path: log_file_path, level }; + + Ok(Self { writer: Writer::FileWriter(fs_writer) }) } } -impl Logger for FilesystemLogger { + +impl LdkLogger for Logger { fn log(&self, record: Record) { - if record.level < self.level { - return; - } let raw_log = record.args.to_string(); let log = format!( "{} {:<5} [{}:{}] {}\n", @@ -53,12 +66,21 @@ impl Logger for FilesystemLogger { record.line, raw_log ); - fs::OpenOptions::new() - .create(true) - .append(true) - .open(self.file_path.clone()) - .expect("Failed to open log file") - .write_all(log.as_bytes()) - .expect("Failed to write to log file") + + match &self.writer { + Writer::FileWriter(fs_logger) => { + if record.level < fs_logger.level { + return; + } + + fs::OpenOptions::new() + .create(true) + .append(true) + .open(fs_logger.file_path.clone()) + .expect("Failed to open log file") + .write_all(log.as_bytes()) + .expect("Failed to write to log file") + }, + } } } diff --git a/src/payment/bolt11.rs b/src/payment/bolt11.rs index 708c127bd..7c2f7804b 100644 --- a/src/payment/bolt11.rs +++ b/src/payment/bolt11.rs @@ -13,7 +13,7 @@ use crate::config::{Config, LDK_PAYMENT_RETRY_TIMEOUT}; use crate::connection::ConnectionManager; use crate::error::Error; use crate::liquidity::LiquiditySource; -use crate::logger::{log_error, log_info, FilesystemLogger, Logger}; +use crate::logger::{log_error, log_info, LdkLogger, Logger}; use crate::payment::store::{ LSPFeeLimits, PaymentDetails, PaymentDetailsUpdate, PaymentDirection, PaymentKind, PaymentStatus, PaymentStore, @@ -48,25 +48,23 @@ use std::time::SystemTime; pub struct Bolt11Payment { runtime: Arc>>>, channel_manager: Arc, - connection_manager: Arc>>, + connection_manager: Arc>>, keys_manager: Arc, - liquidity_source: Option>>>, - payment_store: Arc>>, - peer_store: Arc>>, + liquidity_source: Option>>>, + payment_store: Arc>>, + peer_store: Arc>>, config: Arc, - logger: Arc, + logger: Arc, } impl Bolt11Payment { pub(crate) fn new( runtime: Arc>>>, channel_manager: Arc, - connection_manager: Arc>>, - keys_manager: Arc, - liquidity_source: Option>>>, - payment_store: Arc>>, - peer_store: Arc>>, config: Arc, - logger: Arc, + connection_manager: Arc>>, keys_manager: Arc, + liquidity_source: Option>>>, + payment_store: Arc>>, peer_store: Arc>>, + config: Arc, logger: Arc, ) -> Self { Self { runtime, diff --git a/src/payment/bolt12.rs b/src/payment/bolt12.rs index 90024b7d3..9f6ac0339 100644 --- a/src/payment/bolt12.rs +++ b/src/payment/bolt12.rs @@ -11,7 +11,7 @@ use crate::config::LDK_PAYMENT_RETRY_TIMEOUT; use crate::error::Error; -use crate::logger::{log_error, log_info, FilesystemLogger, Logger}; +use crate::logger::{log_error, log_info, LdkLogger, Logger}; use crate::payment::store::{ PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, PaymentStore, }; @@ -39,15 +39,15 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; pub struct Bolt12Payment { runtime: Arc>>>, channel_manager: Arc, - payment_store: Arc>>, - logger: Arc, + payment_store: Arc>>, + logger: Arc, } impl Bolt12Payment { pub(crate) fn new( runtime: Arc>>>, - channel_manager: Arc, - payment_store: Arc>>, logger: Arc, + channel_manager: Arc, payment_store: Arc>>, + logger: Arc, ) -> Self { Self { runtime, channel_manager, payment_store, logger } } diff --git a/src/payment/onchain.rs b/src/payment/onchain.rs index d46eba2b5..123f38a84 100644 --- a/src/payment/onchain.rs +++ b/src/payment/onchain.rs @@ -9,7 +9,7 @@ use crate::config::Config; use crate::error::Error; -use crate::logger::{log_info, FilesystemLogger, Logger}; +use crate::logger::{log_info, LdkLogger, Logger}; use crate::types::{ChannelManager, Wallet}; use crate::wallet::OnchainSendAmount; @@ -27,13 +27,13 @@ pub struct OnchainPayment { wallet: Arc, channel_manager: Arc, config: Arc, - logger: Arc, + logger: Arc, } impl OnchainPayment { pub(crate) fn new( runtime: Arc>>>, wallet: Arc, - channel_manager: Arc, config: Arc, logger: Arc, + channel_manager: Arc, config: Arc, logger: Arc, ) -> Self { Self { runtime, wallet, channel_manager, config, logger } } diff --git a/src/payment/spontaneous.rs b/src/payment/spontaneous.rs index a0f91134c..28ae6813b 100644 --- a/src/payment/spontaneous.rs +++ b/src/payment/spontaneous.rs @@ -9,7 +9,7 @@ use crate::config::{Config, LDK_PAYMENT_RETRY_TIMEOUT}; use crate::error::Error; -use crate::logger::{log_error, log_info, FilesystemLogger, Logger}; +use crate::logger::{log_error, log_info, LdkLogger, Logger}; use crate::payment::store::{ PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, PaymentStore, }; @@ -37,17 +37,16 @@ pub struct SpontaneousPayment { runtime: Arc>>>, channel_manager: Arc, keys_manager: Arc, - payment_store: Arc>>, + payment_store: Arc>>, config: Arc, - logger: Arc, + logger: Arc, } impl SpontaneousPayment { pub(crate) fn new( runtime: Arc>>>, channel_manager: Arc, keys_manager: Arc, - payment_store: Arc>>, config: Arc, - logger: Arc, + payment_store: Arc>>, config: Arc, logger: Arc, ) -> Self { Self { runtime, channel_manager, keys_manager, payment_store, config, logger } } diff --git a/src/payment/store.rs b/src/payment/store.rs index ee82544dc..5b868d454 100644 --- a/src/payment/store.rs +++ b/src/payment/store.rs @@ -9,7 +9,7 @@ use crate::hex_utils; use crate::io::{ PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE, }; -use crate::logger::{log_error, Logger}; +use crate::logger::{log_error, LdkLogger}; use crate::types::DynStore; use crate::Error; @@ -343,7 +343,7 @@ impl PaymentDetailsUpdate { pub(crate) struct PaymentStore where - L::Target: Logger, + L::Target: LdkLogger, { payments: Mutex>, kv_store: Arc, @@ -352,7 +352,7 @@ where impl PaymentStore where - L::Target: Logger, + L::Target: LdkLogger, { pub(crate) fn new(payments: Vec, kv_store: Arc, logger: L) -> Self { let payments = Mutex::new(HashMap::from_iter( diff --git a/src/payment/unified_qr.rs b/src/payment/unified_qr.rs index 88d372456..7a14ae3c3 100644 --- a/src/payment/unified_qr.rs +++ b/src/payment/unified_qr.rs @@ -12,7 +12,7 @@ //! [BOLT 11]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md //! [BOLT 12]: https://github.com/lightning/bolts/blob/master/12-offer-encoding.md use crate::error::Error; -use crate::logger::{log_error, FilesystemLogger, Logger}; +use crate::logger::{log_error, LdkLogger, Logger}; use crate::payment::{Bolt11Payment, Bolt12Payment, OnchainPayment}; use crate::Config; @@ -50,13 +50,13 @@ pub struct UnifiedQrPayment { bolt11_invoice: Arc, bolt12_payment: Arc, config: Arc, - logger: Arc, + logger: Arc, } impl UnifiedQrPayment { pub(crate) fn new( onchain_payment: Arc, bolt11_invoice: Arc, - bolt12_payment: Arc, config: Arc, logger: Arc, + bolt12_payment: Arc, config: Arc, logger: Arc, ) -> Self { Self { onchain_payment, bolt11_invoice, bolt12_payment, config, logger } } diff --git a/src/peer_store.rs b/src/peer_store.rs index d4d6bbb97..4d1c65157 100644 --- a/src/peer_store.rs +++ b/src/peer_store.rs @@ -9,7 +9,7 @@ use crate::io::{ PEER_INFO_PERSISTENCE_KEY, PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, }; -use crate::logger::{log_error, Logger}; +use crate::logger::{log_error, LdkLogger}; use crate::types::DynStore; use crate::{Error, SocketAddress}; @@ -24,7 +24,7 @@ use std::sync::{Arc, RwLock}; pub struct PeerStore where - L::Target: Logger, + L::Target: LdkLogger, { peers: RwLock>, kv_store: Arc, @@ -33,7 +33,7 @@ where impl PeerStore where - L::Target: Logger, + L::Target: LdkLogger, { pub(crate) fn new(kv_store: Arc, logger: L) -> Self { let peers = RwLock::new(HashMap::new()); @@ -92,7 +92,7 @@ where impl ReadableArgs<(Arc, L)> for PeerStore where - L::Target: Logger, + L::Target: LdkLogger, { #[inline] fn read( diff --git a/src/tx_broadcaster.rs b/src/tx_broadcaster.rs index 5aded03c6..09189b137 100644 --- a/src/tx_broadcaster.rs +++ b/src/tx_broadcaster.rs @@ -5,7 +5,7 @@ // http://opensource.org/licenses/MIT>, at your option. You may not use this file except in // accordance with one or both of these licenses. -use crate::logger::{log_error, Logger}; +use crate::logger::{log_error, LdkLogger}; use lightning::chain::chaininterface::BroadcasterInterface; @@ -20,7 +20,7 @@ const BCAST_PACKAGE_QUEUE_SIZE: usize = 50; pub(crate) struct TransactionBroadcaster where - L::Target: Logger, + L::Target: LdkLogger, { queue_sender: mpsc::Sender>, queue_receiver: Mutex>>, @@ -29,7 +29,7 @@ where impl TransactionBroadcaster where - L::Target: Logger, + L::Target: LdkLogger, { pub(crate) fn new(logger: L) -> Self { let (queue_sender, queue_receiver) = mpsc::channel(BCAST_PACKAGE_QUEUE_SIZE); @@ -43,7 +43,7 @@ where impl BroadcasterInterface for TransactionBroadcaster where - L::Target: Logger, + L::Target: LdkLogger, { fn broadcast_transactions(&self, txs: &[&Transaction]) { let package = txs.iter().map(|&t| t.clone()).collect::>(); diff --git a/src/types.rs b/src/types.rs index 4ec8e9fe8..0c84313d0 100644 --- a/src/types.rs +++ b/src/types.rs @@ -8,7 +8,7 @@ use crate::chain::ChainSource; use crate::config::ChannelConfig; use crate::fee_estimator::OnchainFeeEstimator; -use crate::logger::FilesystemLogger; +use crate::logger::Logger; use crate::message_handler::NodeCustomMessageHandler; use lightning::chain::chainmonitor; @@ -39,7 +39,7 @@ pub(crate) type ChainMonitor = chainmonitor::ChainMonitor< Arc, Arc, Arc, - Arc, + Arc, Arc, >; @@ -48,8 +48,8 @@ pub(crate) type PeerManager = lightning::ln::peer_handler::PeerManager< Arc, Arc, Arc, - Arc, - Arc>>, + Arc, + Arc>>, Arc, >; @@ -64,51 +64,48 @@ pub(crate) type ChannelManager = lightning::ln::channelmanager::ChannelManager< Arc, Arc, Arc, - Arc, + Arc, >; -pub(crate) type Broadcaster = crate::tx_broadcaster::TransactionBroadcaster>; +pub(crate) type Broadcaster = crate::tx_broadcaster::TransactionBroadcaster>; pub(crate) type Wallet = - crate::wallet::Wallet, Arc, Arc>; + crate::wallet::Wallet, Arc, Arc>; -pub(crate) type KeysManager = crate::wallet::WalletKeysManager< - Arc, - Arc, - Arc, ->; +pub(crate) type KeysManager = + crate::wallet::WalletKeysManager, Arc, Arc>; pub(crate) type Router = DefaultRouter< Arc, - Arc, + Arc, Arc, Arc>, ProbabilisticScoringFeeParameters, Scorer, >; -pub(crate) type Scorer = ProbabilisticScorer, Arc>; +pub(crate) type Scorer = ProbabilisticScorer, Arc>; -pub(crate) type Graph = gossip::NetworkGraph>; +pub(crate) type Graph = gossip::NetworkGraph>; pub(crate) type UtxoLookup = dyn lightning::routing::utxo::UtxoLookup + Send + Sync; pub(crate) type P2PGossipSync = - lightning::routing::gossip::P2PGossipSync, Arc, Arc>; + lightning::routing::gossip::P2PGossipSync, Arc, Arc>; pub(crate) type RapidGossipSync = - lightning_rapid_gossip_sync::RapidGossipSync, Arc>; + lightning_rapid_gossip_sync::RapidGossipSync, Arc>; pub(crate) type GossipSync = lightning_background_processor::GossipSync< Arc, Arc, Arc, Arc, - Arc, + Arc, >; pub(crate) type OnionMessenger = lightning::onion_message::messenger::OnionMessenger< Arc, Arc, - Arc, + Arc, Arc, Arc, Arc, @@ -118,7 +115,7 @@ pub(crate) type OnionMessenger = lightning::onion_message::messenger::OnionMesse pub(crate) type MessageRouter = lightning::onion_message::messenger::DefaultMessageRouter< Arc, - Arc, + Arc, Arc, >; @@ -128,16 +125,16 @@ pub(crate) type Sweeper = OutputSweeper< Arc, Arc, Arc, - Arc, + Arc, Arc, >; pub(crate) type BumpTransactionEventHandler = lightning::events::bump_transaction::BumpTransactionEventHandler< Arc, - Arc, Arc>>, + Arc, Arc>>, Arc, - Arc, + Arc, >; /// A local, potentially user-provided, identifier of a channel. diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index a4d4b066e..99efc68c8 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -7,7 +7,7 @@ use persist::KVStoreWalletPersister; -use crate::logger::{log_debug, log_error, log_info, log_trace, Logger}; +use crate::logger::{log_debug, log_error, log_info, log_trace, LdkLogger}; use crate::fee_estimator::{ConfirmationTarget, FeeEstimator}; use crate::Error; @@ -58,7 +58,7 @@ pub(crate) struct Wallet where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { // A BDK on-chain wallet. inner: Mutex>, @@ -72,7 +72,7 @@ impl Wallet where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { pub(crate) fn new( wallet: bdk_wallet::PersistedWallet, @@ -459,7 +459,7 @@ impl Listen for Wallet where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { fn filtered_block_connected( &self, _header: &bitcoin::block::Header, @@ -519,7 +519,7 @@ impl WalletSource for Wallet where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { fn list_confirmed_utxos(&self) -> Result, ()> { let locked_wallet = self.inner.lock().unwrap(); @@ -661,7 +661,7 @@ pub(crate) struct WalletKeysManager where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { inner: KeysManager, wallet: Arc>, @@ -672,7 +672,7 @@ impl WalletKeysManager where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { /// Constructs a `WalletKeysManager` that overrides the destination and shutdown scripts. /// @@ -703,7 +703,7 @@ impl NodeSigner for WalletKeysManager where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { fn get_node_id(&self, recipient: Recipient) -> Result { self.inner.get_node_id(recipient) @@ -746,7 +746,7 @@ impl OutputSpender for WalletKeysManager where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { /// See [`KeysManager::spend_spendable_outputs`] for documentation on this method. fn spend_spendable_outputs( @@ -769,7 +769,7 @@ impl EntropySource for WalletKeysManager where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { fn get_secure_random_bytes(&self) -> [u8; 32] { self.inner.get_secure_random_bytes() @@ -780,7 +780,7 @@ impl SignerProvider for WalletKeysManager where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { type EcdsaSigner = InMemorySigner; @@ -831,7 +831,7 @@ impl ChangeDestinationSource for WalletKeysManager where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { fn get_change_destination_script(&self) -> Result { let address = self.wallet.get_new_internal_address().map_err(|e| { diff --git a/src/wallet/persist.rs b/src/wallet/persist.rs index 06af541a2..d9e4e7135 100644 --- a/src/wallet/persist.rs +++ b/src/wallet/persist.rs @@ -10,11 +10,9 @@ use crate::io::utils::{ write_bdk_wallet_indexer, write_bdk_wallet_local_chain, write_bdk_wallet_network, write_bdk_wallet_tx_graph, }; -use crate::logger::{log_error, FilesystemLogger}; +use crate::logger::{log_error, LdkLogger, Logger}; use crate::types::DynStore; -use lightning::util::logger::Logger; - use bdk_chain::Merge; use bdk_wallet::{ChangeSet, WalletPersister}; @@ -22,11 +20,11 @@ use std::sync::Arc; pub(crate) struct KVStoreWalletPersister { latest_change_set: Option, kv_store: Arc, - logger: Arc, + logger: Arc, } impl KVStoreWalletPersister { - pub(crate) fn new(kv_store: Arc, logger: Arc) -> Self { + pub(crate) fn new(kv_store: Arc, logger: Arc) -> Self { Self { latest_change_set: None, kv_store, logger } } } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 65567cb64..ad0e8bbeb 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -12,8 +12,7 @@ use ldk_node::config::{Config, EsploraSyncConfig}; use ldk_node::io::sqlite_store::SqliteStore; use ldk_node::payment::{PaymentDirection, PaymentKind, PaymentStatus}; use ldk_node::{ - Builder, CustomTlvRecord, Event, LightningBalance, LogLevel, Node, NodeError, - PendingSweepBalance, + Builder, CustomTlvRecord, Event, LightningBalance, Node, NodeError, PendingSweepBalance, }; use lightning::ln::msgs::SocketAddress; @@ -234,8 +233,6 @@ pub(crate) fn random_config(anchor_channels: bool) -> Config { println!("Setting random LDK node alias: {:?}", alias); config.node_alias = alias; - config.log_level = LogLevel::Gossip; - config } diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index 937af241b..0e12beaa1 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -14,11 +14,12 @@ use common::{ setup_node, setup_two_nodes, wait_for_tx, TestChainSource, TestSyncStore, }; -use ldk_node::config::EsploraSyncConfig; +use ldk_node::config::{EsploraSyncConfig, FilesystemLoggerConfig}; use ldk_node::payment::{PaymentKind, QrPaymentResult, SendingParameters}; use ldk_node::{Builder, Event, NodeError}; use lightning::ln::channelmanager::PaymentId; +use lightning::util::logger::Level; use lightning::util::persist::KVStore; use bitcoincore_rpc::RpcApi; @@ -215,6 +216,10 @@ fn start_stop_reinit() { sync_config.lightning_wallet_sync_interval_secs = 100000; setup_builder!(builder, config); builder.set_chain_source_esplora(esplora_url.clone(), Some(sync_config)); + builder.set_filesystem_logger(FilesystemLoggerConfig { + log_file_path: format!("{}/{}", config.storage_dir_path, "ldk_node.log"), + level: Level::Debug, + }); let node = builder.build_with_store(Arc::clone(&test_sync_store)).unwrap(); node.start().unwrap(); From abb3b4461fbe8953141d16f712b6705f291fae38 Mon Sep 17 00:00:00 2001 From: Enigbe Ochekliye Date: Tue, 19 Nov 2024 00:01:37 +0100 Subject: [PATCH 02/13] feat(logger): add & impl LogWriter for Writer --- bindings/ldk_node.udl | 12 ++++++ src/lib.rs | 2 +- src/logger.rs | 90 ++++++++++++++++++++++++++++++------------- 3 files changed, 76 insertions(+), 28 deletions(-) diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 331ced3f0..c55761a9d 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -567,6 +567,18 @@ dictionary NodeAnnouncementInfo { sequence addresses; }; +dictionary LogRecord { + LdkLevel level; + string args; + string module_path; + u32 line; +}; + +[Trait] +interface LogWriter { + void log(LogRecord record); +}; + [Custom] typedef string Txid; diff --git a/src/lib.rs b/src/lib.rs index e7b44b3d7..a3113a071 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,7 +111,7 @@ pub use event::Event; pub use io::utils::generate_entropy_mnemonic; pub use config::FilesystemLoggerConfig; -pub use logger::LdkLevel; +pub use logger::{LdkLevel, LogRecord, LogWriter}; #[cfg(feature = "uniffi")] use uniffi_types::*; diff --git a/src/logger.rs b/src/logger.rs index 904aeee98..69a71a5b7 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -5,11 +5,10 @@ // http://opensource.org/licenses/MIT>, at your option. You may not use this file except in // accordance with one or both of these licenses. -pub(crate) use lightning::util::logger::Logger as LdkLogger; +pub(crate) use lightning::util::logger::{Logger as LdkLogger, Record}; pub(crate) use lightning::{log_bytes, log_debug, log_error, log_info, log_trace}; pub use lightning::util::logger::Level as LdkLevel; -use lightning::util::logger::Record; use chrono::Utc; @@ -17,6 +16,37 @@ use std::fs; use std::io::Write; use std::path::Path; +/// A unit of logging output with Metadata to enable filtering Module_path, +/// file, line to inform on log's source. +pub struct LogRecord { + /// The verbosity level of the message. + pub level: LdkLevel, + /// The message body. + pub args: String, + /// The module path of the message. + pub module_path: String, + /// The line containing the message. + pub line: u32, +} + +impl<'a> From> for LogRecord { + fn from(record: Record) -> Self { + Self { + level: record.level, + args: record.args.to_string(), + module_path: record.module_path.to_string(), + line: record.line, + } + } +} + +/// LogWriter trait encapsulating the operations required of a +/// logger's writer. +pub trait LogWriter: Send + Sync { + /// Log the record. + fn log(&self, record: LogRecord); +} + pub(crate) struct FilesystemLogger { file_path: String, level: LdkLevel, @@ -28,6 +58,36 @@ pub(crate) enum Writer { FileWriter(FilesystemLogger), } +impl LogWriter for Writer { + fn log(&self, record: LogRecord) { + let raw_log = record.args.to_string(); + let log = format!( + "{} {:<5} [{}:{}] {}\n", + Utc::now().format("%Y-%m-%d %H:%M:%S"), + record.level.to_string(), + record.module_path, + record.line, + raw_log + ); + + match self { + Writer::FileWriter(fs_logger) => { + if record.level < fs_logger.level { + return; + } + + fs::OpenOptions::new() + .create(true) + .append(true) + .open(fs_logger.file_path.clone()) + .expect("Failed to open log file") + .write_all(log.as_bytes()) + .expect("Failed to write to log file") + }, + } + } +} + pub(crate) struct Logger { /// Specifies the logger's writer. writer: Writer, @@ -57,30 +117,6 @@ impl Logger { impl LdkLogger for Logger { fn log(&self, record: Record) { - let raw_log = record.args.to_string(); - let log = format!( - "{} {:<5} [{}:{}] {}\n", - Utc::now().format("%Y-%m-%d %H:%M:%S"), - record.level.to_string(), - record.module_path, - record.line, - raw_log - ); - - match &self.writer { - Writer::FileWriter(fs_logger) => { - if record.level < fs_logger.level { - return; - } - - fs::OpenOptions::new() - .create(true) - .append(true) - .open(fs_logger.file_path.clone()) - .expect("Failed to open log file") - .write_all(log.as_bytes()) - .expect("Failed to write to log file") - }, - } + self.writer.log(record.into()); } } From 49e914ea06c6c29b0709ae7558de41344d456a87 Mon Sep 17 00:00:00 2001 From: Enigbe Ochekliye Date: Tue, 19 Nov 2024 12:03:34 +0100 Subject: [PATCH 03/13] fix(bindings): remove config log level from kotlin tests --- .../kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt | 2 -- .../src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt | 2 -- 2 files changed, 4 deletions(-) diff --git a/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt b/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt index 763862a33..03c4b88a7 100644 --- a/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt +++ b/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt @@ -28,13 +28,11 @@ class AndroidLibTest { config1.storageDirPath = tmpDir1 config1.listeningAddresses = listOf(listenAddress1) config1.network = Network.REGTEST - config1.logLevel = LogLevel.TRACE val config2 = defaultConfig() config2.storageDirPath = tmpDir2 config2.listeningAddresses = listOf(listenAddress2) config2.network = Network.REGTEST - config2.logLevel = LogLevel.TRACE val builder1 = Builder.fromConfig(config1) val builder2 = Builder.fromConfig(config2) diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt b/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt index 786534b84..84381037c 100644 --- a/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt +++ b/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt @@ -118,7 +118,6 @@ class LibraryTest { config1.storageDirPath = tmpDir1 config1.listeningAddresses = listOf(listenAddress1) config1.network = Network.REGTEST - config1.logLevel = LogLevel.TRACE println("Config 1: $config1") @@ -126,7 +125,6 @@ class LibraryTest { config2.storageDirPath = tmpDir2 config2.listeningAddresses = listOf(listenAddress2) config2.network = Network.REGTEST - config2.logLevel = LogLevel.TRACE println("Config 2: $config2") val builder1 = Builder.fromConfig(config1) From 3dbff3756edfbcc71e267f0e6203758850d43ca8 Mon Sep 17 00:00:00 2001 From: Enigbe Ochekliye Date: Tue, 19 Nov 2024 14:58:22 +0100 Subject: [PATCH 04/13] feat: forward logs to `log` facade --- Cargo.toml | 1 + bindings/ldk_node.udl | 5 +++++ src/builder.rs | 19 ++++++++++++++++++- src/config.rs | 7 +++++++ src/lib.rs | 2 +- src/logger.rs | 21 +++++++++++++++++++++ 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f22092cb5..7dcf283cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,7 @@ libc = "0.2" uniffi = { version = "0.27.3", features = ["build"], optional = true } serde = { version = "1.0.210", default-features = false, features = ["std", "derive"] } serde_json = { version = "1.0.128", default-features = false, features = ["std"] } +log = { version = "0.4.22" } vss-client = "0.3" prost = { version = "0.11.6", default-features = false} diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index c55761a9d..18d01ba77 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -39,6 +39,10 @@ dictionary FilesystemLoggerConfig { LdkLevel level; }; +dictionary LogFacadeLoggerConfig { + LdkLevel level; +}; + interface Builder { constructor(); [Name=from_config] @@ -54,6 +58,7 @@ interface Builder { void set_liquidity_source_lsps2(SocketAddress address, PublicKey node_id, string? token); void set_storage_dir_path(string storage_dir_path); void set_filesystem_logger(FilesystemLoggerConfig fs_config); + void set_log_facade_logger(LogFacadeLoggerConfig lf_config); void set_network(Network network); [Throws=BuildError] void set_listening_addresses(sequence listening_addresses); diff --git a/src/builder.rs b/src/builder.rs index b61db9694..04328ccb8 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -7,7 +7,8 @@ use crate::chain::{ChainSource, DEFAULT_ESPLORA_SERVER_URL}; use crate::config::{ - default_user_config, Config, EsploraSyncConfig, FilesystemLoggerConfig, WALLET_KEYS_SEED_LEN, + default_user_config, Config, EsploraSyncConfig, FilesystemLoggerConfig, LogFacadeLoggerConfig, + WALLET_KEYS_SEED_LEN, }; use crate::connection::ConnectionManager; @@ -111,6 +112,7 @@ impl Default for LiquiditySourceConfig { #[derive(Debug)] enum LogWriterConfig { File(FilesystemLoggerConfig), + Log(LogFacadeLoggerConfig), } impl Default for LogWriterConfig { @@ -320,6 +322,12 @@ impl NodeBuilder { self } + /// Configures the [`Node`] instance to write logs to the `log` facade. + pub fn set_log_facade_logger(&mut self, lf_config: LogFacadeLoggerConfig) -> &mut Self { + self.log_writer_config = Some(LogWriterConfig::Log(lf_config)); + self + } + /// Sets the Bitcoin network used. pub fn set_network(&mut self, network: Network) -> &mut Self { self.config.network = network; @@ -635,6 +643,11 @@ impl ArcedNodeBuilder { self.inner.write().unwrap().set_filesystem_logger(fs_config); } + /// Configures the [`Node`] instance to write logs to the `log` facade. + pub fn set_log_facade_logger(&self, lf_config: LogFacadeLoggerConfig) { + self.inner.write().unwrap().set_log_facade_logger(lf_config); + } + /// Sets the Bitcoin network used. pub fn set_network(&self, network: Network) { self.inner.write().unwrap().set_network(network); @@ -1257,6 +1270,10 @@ fn setup_logger(config: &LogWriterConfig) -> Result, BuildError> { .map_err(|_| BuildError::LoggerSetupFailed)?, )) }, + LogWriterConfig::Log(log_facade_logger_config) => Ok(Arc::new( + Logger::new_log_facade(log_facade_logger_config.level) + .map_err(|_| BuildError::LoggerSetupFailed)?, + )), } } diff --git a/src/config.rs b/src/config.rs index 1820a577a..b18db31d2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -441,6 +441,13 @@ pub struct FilesystemLoggerConfig { pub level: LdkLevel, } +/// Configuration options for logging to the `log` facade. +#[derive(Debug)] +pub struct LogFacadeLoggerConfig { + /// This specifies the log level. + pub level: LdkLevel, +} + impl Default for FilesystemLoggerConfig { fn default() -> Self { let log_file_path = format!("{}/{}", DEFAULT_STORAGE_DIR_PATH, DEFAULT_LOG_FILE_PATH); diff --git a/src/lib.rs b/src/lib.rs index a3113a071..db5c08842 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,7 +110,7 @@ pub use event::Event; pub use io::utils::generate_entropy_mnemonic; -pub use config::FilesystemLoggerConfig; +pub use config::{FilesystemLoggerConfig, LogFacadeLoggerConfig}; pub use logger::{LdkLevel, LogRecord, LogWriter}; #[cfg(feature = "uniffi")] diff --git a/src/logger.rs b/src/logger.rs index 69a71a5b7..02d09c125 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -11,6 +11,7 @@ pub(crate) use lightning::{log_bytes, log_debug, log_error, log_info, log_trace} pub use lightning::util::logger::Level as LdkLevel; use chrono::Utc; +use log::{debug, error, info, trace, warn}; use std::fs; use std::io::Write; @@ -52,10 +53,16 @@ pub(crate) struct FilesystemLogger { level: LdkLevel, } +pub(crate) struct LogFacadeLogger { + level: LdkLevel, +} + /// Defines a writer for [`Logger`]. pub(crate) enum Writer { /// Writes logs to the file system. FileWriter(FilesystemLogger), + /// Fowards logs to the `log` facade. + LogFacadeWriter(LogFacadeLogger), } impl LogWriter for Writer { @@ -84,6 +91,14 @@ impl LogWriter for Writer { .write_all(log.as_bytes()) .expect("Failed to write to log file") }, + Writer::LogFacadeWriter(log_facade_logger) => match log_facade_logger.level { + LdkLevel::Gossip => trace!("{}", log), + LdkLevel::Trace => trace!("{}", log), + LdkLevel::Debug => debug!("{}", log), + LdkLevel::Info => info!("{}", log), + LdkLevel::Warn => warn!("{}", log), + LdkLevel::Error => error!("{}", log), + }, } } } @@ -113,6 +128,12 @@ impl Logger { Ok(Self { writer: Writer::FileWriter(fs_writer) }) } + + pub fn new_log_facade(level: LdkLevel) -> Result { + let log_facade_writer = LogFacadeLogger { level }; + + Ok(Self { writer: Writer::LogFacadeWriter(log_facade_writer) }) + } } impl LdkLogger for Logger { From c1f7858ae316db7b91cd26d77bc8e40bc3d28973 Mon Sep 17 00:00:00 2001 From: Enigbe Ochekliye Date: Tue, 19 Nov 2024 22:24:07 +0100 Subject: [PATCH 05/13] test(logwriter): forward logs to mock in-memory `log` logger --- Cargo.toml | 2 +- src/config.rs | 4 +-- tests/common/mod.rs | 64 ++++++++++++++++++++++++++++++--- tests/integration_tests_rust.rs | 64 +++++++++++++++++++++++---------- 4 files changed, 107 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7dcf283cb..4e33da8d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,7 @@ libc = "0.2" uniffi = { version = "0.27.3", features = ["build"], optional = true } serde = { version = "1.0.210", default-features = false, features = ["std", "derive"] } serde_json = { version = "1.0.128", default-features = false, features = ["std"] } -log = { version = "0.4.22" } +log = { version = "0.4.22", features = ["std"]} vss-client = "0.3" prost = { version = "0.11.6", default-features = false} diff --git a/src/config.rs b/src/config.rs index b18db31d2..9708bcdf4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -430,7 +430,7 @@ impl From for LdkMaxDustHTLCExposure { } /// Configuration options for logging to the filesystem. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct FilesystemLoggerConfig { /// The log file path. /// @@ -442,7 +442,7 @@ pub struct FilesystemLoggerConfig { } /// Configuration options for logging to the `log` facade. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct LogFacadeLoggerConfig { /// This specifies the log level. pub level: LdkLevel, diff --git a/tests/common/mod.rs b/tests/common/mod.rs index ad0e8bbeb..75852acd9 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -12,7 +12,8 @@ use ldk_node::config::{Config, EsploraSyncConfig}; use ldk_node::io::sqlite_store::SqliteStore; use ldk_node::payment::{PaymentDirection, PaymentKind, PaymentStatus}; use ldk_node::{ - Builder, CustomTlvRecord, Event, LightningBalance, Node, NodeError, PendingSweepBalance, + Builder, CustomTlvRecord, Event, FilesystemLoggerConfig, LightningBalance, + LogFacadeLoggerConfig, Node, NodeError, PendingSweepBalance, }; use lightning::ln::msgs::SocketAddress; @@ -36,9 +37,11 @@ use electrum_client::ElectrumApi; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; +use log::{LevelFilter, Log}; + use std::env; use std::path::PathBuf; -use std::sync::{Arc, RwLock}; +use std::sync::{Arc, Mutex, RwLock}; use std::time::Duration; macro_rules! expect_event { @@ -247,6 +250,47 @@ pub(crate) enum TestChainSource<'a> { BitcoindRpc(&'a BitcoinD), } +#[derive(Clone)] +pub(crate) enum TestLogWriter { + File(FilesystemLoggerConfig), + LogFacade(LogFacadeLoggerConfig), +} + +/// Simple in-memory mock `log` logger for tests. +pub(crate) struct MockLogger { + logs: Arc>>, +} + +impl MockLogger { + pub fn new() -> Self { + Self { logs: Arc::new(Mutex::new(Vec::new())) } + } + + pub fn retrieve_logs(&self) -> Vec { + self.logs.lock().unwrap().clone() + } +} + +impl Log for MockLogger { + fn log(&self, record: &log::Record) { + let message = format!("[{}] {}", record.level(), record.args()); + self.logs.lock().unwrap().push(message); + } + + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn flush(&self) {} +} + +pub(crate) fn init_mock_logger(level: LevelFilter) -> Arc { + let logger = Arc::new(MockLogger::new()); + log::set_boxed_logger(Box::new(logger.clone())).unwrap(); + log::set_max_level(level); + logger +} + macro_rules! setup_builder { ($builder: ident, $config: expr) => { #[cfg(feature = "uniffi")] @@ -260,11 +304,11 @@ pub(crate) use setup_builder; pub(crate) fn setup_two_nodes( chain_source: &TestChainSource, allow_0conf: bool, anchor_channels: bool, - anchors_trusted_no_reserve: bool, + anchors_trusted_no_reserve: bool, log_writer: TestLogWriter, ) -> (TestNode, TestNode) { println!("== Node A =="); let config_a = random_config(anchor_channels); - let node_a = setup_node(chain_source, config_a, None); + let node_a = setup_node(chain_source, config_a, None, log_writer.clone()); println!("\n== Node B =="); let mut config_b = random_config(anchor_channels); @@ -279,12 +323,13 @@ pub(crate) fn setup_two_nodes( .trusted_peers_no_reserve .push(node_a.node_id()); } - let node_b = setup_node(chain_source, config_b, None); + let node_b = setup_node(chain_source, config_b, None, log_writer); (node_a, node_b) } pub(crate) fn setup_node( chain_source: &TestChainSource, config: Config, seed_bytes: Option>, + log_writer: TestLogWriter, ) -> TestNode { setup_builder!(builder, config); match chain_source { @@ -305,6 +350,15 @@ pub(crate) fn setup_node( }, } + match log_writer { + TestLogWriter::File(fs_config) => { + builder.set_filesystem_logger(fs_config); + }, + TestLogWriter::LogFacade(lf_config) => { + builder.set_log_facade_logger(lf_config); + }, + } + if let Some(seed) = seed_bytes { builder.set_entropy_seed_bytes(seed).unwrap(); } diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index 0e12beaa1..b7c059b0e 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -9,14 +9,15 @@ mod common; use common::{ do_channel_full_cycle, expect_channel_ready_event, expect_event, expect_payment_received_event, - expect_payment_successful_event, generate_blocks_and_wait, open_channel, + expect_payment_successful_event, generate_blocks_and_wait, init_mock_logger, open_channel, premine_and_distribute_funds, random_config, setup_bitcoind_and_electrsd, setup_builder, - setup_node, setup_two_nodes, wait_for_tx, TestChainSource, TestSyncStore, + setup_node, setup_two_nodes, wait_for_tx, TestChainSource, TestLogWriter, TestSyncStore, }; use ldk_node::config::{EsploraSyncConfig, FilesystemLoggerConfig}; use ldk_node::payment::{PaymentKind, QrPaymentResult, SendingParameters}; -use ldk_node::{Builder, Event, NodeError}; +use ldk_node::LdkLevel; +use ldk_node::{Builder, Event, LogFacadeLoggerConfig, NodeError}; use lightning::ln::channelmanager::PaymentId; use lightning::util::logger::Level; @@ -32,7 +33,8 @@ use std::sync::Arc; fn channel_full_cycle() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, false, true, false); } @@ -40,7 +42,8 @@ fn channel_full_cycle() { fn channel_full_cycle_bitcoind() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::BitcoindRpc(&bitcoind); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, false, true, false); } @@ -48,7 +51,8 @@ fn channel_full_cycle_bitcoind() { fn channel_full_cycle_force_close() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, false, true, true); } @@ -56,7 +60,8 @@ fn channel_full_cycle_force_close() { fn channel_full_cycle_force_close_trusted_no_reserve() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, true); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, true, log_writer); do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, false, true, true); } @@ -64,7 +69,8 @@ fn channel_full_cycle_force_close_trusted_no_reserve() { fn channel_full_cycle_0conf() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, true, true, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, true, true, false, log_writer); do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, true, true, false) } @@ -72,7 +78,8 @@ fn channel_full_cycle_0conf() { fn channel_full_cycle_legacy_staticremotekey() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, false, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, false, false, log_writer); do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, false, false, false); } @@ -80,7 +87,8 @@ fn channel_full_cycle_legacy_staticremotekey() { fn channel_open_fails_when_funds_insufficient() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); let addr_a = node_a.onchain_payment().new_address().unwrap(); let addr_b = node_b.onchain_payment().new_address().unwrap(); @@ -280,7 +288,8 @@ fn start_stop_reinit() { fn onchain_spend_receive() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); let addr_a = node_a.onchain_payment().new_address().unwrap(); let addr_b = node_b.onchain_payment().new_address().unwrap(); @@ -381,7 +390,9 @@ fn onchain_wallet_recovery() { let seed_bytes = vec![42u8; 64]; let original_config = random_config(true); - let original_node = setup_node(&chain_source, original_config, Some(seed_bytes.clone())); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let original_node = + setup_node(&chain_source, original_config, Some(seed_bytes.clone()), log_writer); let premine_amount_sat = 100_000; @@ -426,7 +437,8 @@ fn onchain_wallet_recovery() { // Now we start from scratch, only the seed remains the same. let recovered_config = random_config(true); - let recovered_node = setup_node(&chain_source, recovered_config, Some(seed_bytes)); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let recovered_node = setup_node(&chain_source, recovered_config, Some(seed_bytes), log_writer); recovered_node.sync_wallets().unwrap(); assert_eq!( @@ -469,7 +481,8 @@ fn sign_verify_msg() { let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let config = random_config(true); let chain_source = TestChainSource::Esplora(&electrsd); - let node = setup_node(&chain_source, config, None); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let node = setup_node(&chain_source, config, None, log_writer); // Tests arbitrary message signing and later verification let msg = "OK computer".as_bytes(); @@ -487,7 +500,8 @@ fn connection_restart_behavior() { fn do_connection_restart_behavior(persist: bool) { let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, false, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, false, false, log_writer); let node_id_a = node_a.node_id(); let node_id_b = node_b.node_id(); @@ -539,7 +553,8 @@ fn do_connection_restart_behavior(persist: bool) { fn concurrent_connections_succeed() { let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); let node_a = Arc::new(node_a); let node_b = Arc::new(node_b); @@ -570,7 +585,8 @@ fn concurrent_connections_succeed() { fn simple_bolt12_send_receive() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); let address_a = node_a.onchain_payment().new_address().unwrap(); let premine_amount_sat = 5_000_000; @@ -778,7 +794,8 @@ fn simple_bolt12_send_receive() { fn generate_bip21_uri() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); let address_a = node_a.onchain_payment().new_address().unwrap(); let premined_sats = 5_000_000; @@ -820,7 +837,10 @@ fn generate_bip21_uri() { fn unified_qr_send_receive() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + + let mock_logger = init_mock_logger(log::LevelFilter::Trace); + let log_writer = TestLogWriter::LogFacade(LogFacadeLoggerConfig { level: LdkLevel::Trace }); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); let address_a = node_a.onchain_payment().new_address().unwrap(); let premined_sats = 5_000_000; @@ -926,4 +946,10 @@ fn unified_qr_send_receive() { assert_eq!(node_b.list_balances().total_onchain_balance_sats, 800_000); assert_eq!(node_b.list_balances().total_lightning_balance_sats, 200_000); + + assert!(mock_logger + .retrieve_logs() + .last() + .unwrap() + .contains("Incremental sync of on-chain wallet finished"),); } From a40ccb1820134193fcc064dce18fc4030b252804 Mon Sep 17 00:00:00 2001 From: Enigbe Ochekliye Date: Tue, 19 Nov 2024 22:57:33 +0100 Subject: [PATCH 06/13] fix: correct "Forwards" spelling error --- src/logger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logger.rs b/src/logger.rs index 02d09c125..0e81b6a9e 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -61,7 +61,7 @@ pub(crate) struct LogFacadeLogger { pub(crate) enum Writer { /// Writes logs to the file system. FileWriter(FilesystemLogger), - /// Fowards logs to the `log` facade. + /// Forwards logs to the `log` facade. LogFacadeWriter(LogFacadeLogger), } From 7f4b122931a182a60c482d5f7d7a1841f7db83a8 Mon Sep 17 00:00:00 2001 From: Enigbe Ochekliye Date: Wed, 20 Nov 2024 12:17:38 +0100 Subject: [PATCH 07/13] feat(custom): forward logs to a custom logger * Add support for user-provided custom logger to write logs to, allowing users to provide any logger that implements LogWriter * Add test to cover this use case, implementing Log- Writer for the mock, in-memory MockLogger. --- src/builder.rs | 18 ++++++++++++++++- src/logger.rs | 14 ++++++++++++- tests/common/mod.rs | 35 +++++++++++++++++++++++++++++++-- tests/integration_tests_rust.rs | 8 +++++++- 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 04328ccb8..d7622c23b 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -19,7 +19,7 @@ use crate::io::sqlite_store::SqliteStore; use crate::io::utils::{read_node_metrics, write_node_metrics}; use crate::io::vss_store::VssStore; use crate::liquidity::LiquiditySource; -use crate::logger::{log_error, log_info, LdkLogger, Logger}; +use crate::logger::{log_error, log_info, LdkLogger, LogWriter, Logger}; use crate::message_handler::NodeCustomMessageHandler; use crate::payment::store::PaymentStore; use crate::peer_store::PeerStore; @@ -113,6 +113,7 @@ impl Default for LiquiditySourceConfig { enum LogWriterConfig { File(FilesystemLoggerConfig), Log(LogFacadeLoggerConfig), + Custom(Arc), } impl Default for LogWriterConfig { @@ -328,6 +329,12 @@ impl NodeBuilder { self } + /// Configures the [`Node`] instance to write logs to the provided custom log writer. + pub fn set_custom_logger(&mut self, log_writer: Arc) -> &mut Self { + self.log_writer_config = Some(LogWriterConfig::Custom(log_writer)); + self + } + /// Sets the Bitcoin network used. pub fn set_network(&mut self, network: Network) -> &mut Self { self.config.network = network; @@ -648,6 +655,11 @@ impl ArcedNodeBuilder { self.inner.write().unwrap().set_log_facade_logger(lf_config); } + /// Configures the [`Node`] instance to write logs to the provided custom log writer. + pub fn set_custom_logger(&self, log_writer: Arc) { + self.inner.write().unwrap().set_custom_logger(log_writer); + } + /// Sets the Bitcoin network used. pub fn set_network(&self, network: Network) { self.inner.write().unwrap().set_network(network); @@ -1274,6 +1286,10 @@ fn setup_logger(config: &LogWriterConfig) -> Result, BuildError> { Logger::new_log_facade(log_facade_logger_config.level) .map_err(|_| BuildError::LoggerSetupFailed)?, )), + LogWriterConfig::Custom(custom_log_writer) => Ok(Arc::new( + Logger::new_custom_writer(custom_log_writer.clone()) + .map_err(|_| BuildError::LoggerSetupFailed)?, + )), } } diff --git a/src/logger.rs b/src/logger.rs index 0e81b6a9e..9cde70f2f 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -13,9 +13,11 @@ pub use lightning::util::logger::Level as LdkLevel; use chrono::Utc; use log::{debug, error, info, trace, warn}; +use std::fmt::Debug; use std::fs; use std::io::Write; use std::path::Path; +use std::sync::Arc; /// A unit of logging output with Metadata to enable filtering Module_path, /// file, line to inform on log's source. @@ -43,26 +45,31 @@ impl<'a> From> for LogRecord { /// LogWriter trait encapsulating the operations required of a /// logger's writer. -pub trait LogWriter: Send + Sync { +pub trait LogWriter: Send + Sync + Debug { /// Log the record. fn log(&self, record: LogRecord); } +#[derive(Debug)] pub(crate) struct FilesystemLogger { file_path: String, level: LdkLevel, } +#[derive(Debug)] pub(crate) struct LogFacadeLogger { level: LdkLevel, } /// Defines a writer for [`Logger`]. +#[derive(Debug)] pub(crate) enum Writer { /// Writes logs to the file system. FileWriter(FilesystemLogger), /// Forwards logs to the `log` facade. LogFacadeWriter(LogFacadeLogger), + /// Forwards logs to custom writer. + CustomWriter(Arc), } impl LogWriter for Writer { @@ -99,6 +106,7 @@ impl LogWriter for Writer { LdkLevel::Warn => warn!("{}", log), LdkLevel::Error => error!("{}", log), }, + Writer::CustomWriter(custom_logger) => custom_logger.log(record), } } } @@ -134,6 +142,10 @@ impl Logger { Ok(Self { writer: Writer::LogFacadeWriter(log_facade_writer) }) } + + pub fn new_custom_writer(log_writer: Arc) -> Result { + Ok(Self { writer: Writer::CustomWriter(log_writer) }) + } } impl LdkLogger for Logger { diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 75852acd9..abf5d8d40 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -8,12 +8,13 @@ #![cfg(any(test, cln_test, vss_test))] #![allow(dead_code)] +use chrono::Utc; use ldk_node::config::{Config, EsploraSyncConfig}; use ldk_node::io::sqlite_store::SqliteStore; use ldk_node::payment::{PaymentDirection, PaymentKind, PaymentStatus}; use ldk_node::{ Builder, CustomTlvRecord, Event, FilesystemLoggerConfig, LightningBalance, - LogFacadeLoggerConfig, Node, NodeError, PendingSweepBalance, + LogFacadeLoggerConfig, LogRecord, LogWriter, Node, NodeError, PendingSweepBalance, }; use lightning::ln::msgs::SocketAddress; @@ -254,9 +255,11 @@ pub(crate) enum TestChainSource<'a> { pub(crate) enum TestLogWriter { File(FilesystemLoggerConfig), LogFacade(LogFacadeLoggerConfig), + Custom(Arc), } /// Simple in-memory mock `log` logger for tests. +#[derive(Debug)] pub(crate) struct MockLogger { logs: Arc>>, } @@ -271,9 +274,18 @@ impl MockLogger { } } +/// [`MockLogger`] as `log` logger - destination for [`Writer::LogFacadeWriter`] +/// to write logs to. +/// +/// [`Writer::LogFacadeWriter`]: ldk_node::logger::Writer::LogFacadeWriter impl Log for MockLogger { fn log(&self, record: &log::Record) { - let message = format!("[{}] {}", record.level(), record.args()); + let message = format!( + "{} [{}] {}", + Utc::now().format("%Y-%m-%d %H:%M:%S"), + record.level(), + record.args() + ); self.logs.lock().unwrap().push(message); } @@ -284,6 +296,22 @@ impl Log for MockLogger { fn flush(&self) {} } +/// [`MockLogger`] as custom logger - a destination for [`Writer::CustomWriter`] +/// to write logs to. +/// +/// [`Writer::CustomWriter`]: ldk_node::logger::Writer::CustomWriter +impl LogWriter for MockLogger { + fn log(&self, record: LogRecord) { + let message = format!( + "{} [{}] {}", + Utc::now().format("%Y-%m-%d %H:%M:%S"), + record.level, + record.args + ); + self.logs.lock().unwrap().push(message); + } +} + pub(crate) fn init_mock_logger(level: LevelFilter) -> Arc { let logger = Arc::new(MockLogger::new()); log::set_boxed_logger(Box::new(logger.clone())).unwrap(); @@ -357,6 +385,9 @@ pub(crate) fn setup_node( TestLogWriter::LogFacade(lf_config) => { builder.set_log_facade_logger(lf_config); }, + TestLogWriter::Custom(log_writer) => { + builder.set_custom_logger(log_writer); + }, } if let Some(seed) = seed_bytes { diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index b7c059b0e..5f7648398 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -794,7 +794,10 @@ fn simple_bolt12_send_receive() { fn generate_bip21_uri() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); - let log_writer = TestLogWriter::File(FilesystemLoggerConfig::default()); + + // Setup custom logger. + let mock_logger = init_mock_logger(log::LevelFilter::Trace); + let log_writer = TestLogWriter::Custom(mock_logger.clone()); let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); let address_a = node_a.onchain_payment().new_address().unwrap(); @@ -831,6 +834,8 @@ fn generate_bip21_uri() { }, Err(e) => panic!("Failed to generate URI: {:?}", e), } + + assert!(mock_logger.retrieve_logs().last().unwrap().contains("Invoice created: lnbcrt")); } #[test] @@ -838,6 +843,7 @@ fn unified_qr_send_receive() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); let chain_source = TestChainSource::Esplora(&electrsd); + // Setup `log` facade logger. let mock_logger = init_mock_logger(log::LevelFilter::Trace); let log_writer = TestLogWriter::LogFacade(LogFacadeLoggerConfig { level: LdkLevel::Trace }); let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); From bdeb4329751f139dbe46f82977d13532a192a577 Mon Sep 17 00:00:00 2001 From: Enigbe Ochekliye Date: Wed, 20 Nov 2024 16:35:16 +0100 Subject: [PATCH 08/13] fix(test): fix setting log's global logger twice --- tests/common/mod.rs | 7 ++++++- tests/integration_tests_rust.rs | 15 +++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/tests/common/mod.rs b/tests/common/mod.rs index abf5d8d40..714893c88 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -312,13 +312,18 @@ impl LogWriter for MockLogger { } } -pub(crate) fn init_mock_logger(level: LevelFilter) -> Arc { +pub(crate) fn init_log_logger(level: LevelFilter) -> Arc { let logger = Arc::new(MockLogger::new()); log::set_boxed_logger(Box::new(logger.clone())).unwrap(); log::set_max_level(level); logger } +pub(crate) fn init_custom_logger() -> Arc { + let logger = Arc::new(MockLogger::new()); + logger +} + macro_rules! setup_builder { ($builder: ident, $config: expr) => { #[cfg(feature = "uniffi")] diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index 5f7648398..036d81e07 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -9,9 +9,10 @@ mod common; use common::{ do_channel_full_cycle, expect_channel_ready_event, expect_event, expect_payment_received_event, - expect_payment_successful_event, generate_blocks_and_wait, init_mock_logger, open_channel, - premine_and_distribute_funds, random_config, setup_bitcoind_and_electrsd, setup_builder, - setup_node, setup_two_nodes, wait_for_tx, TestChainSource, TestLogWriter, TestSyncStore, + expect_payment_successful_event, generate_blocks_and_wait, init_custom_logger, init_log_logger, + open_channel, premine_and_distribute_funds, random_config, setup_bitcoind_and_electrsd, + setup_builder, setup_node, setup_two_nodes, wait_for_tx, TestChainSource, TestLogWriter, + TestSyncStore, }; use ldk_node::config::{EsploraSyncConfig, FilesystemLoggerConfig}; @@ -796,7 +797,7 @@ fn generate_bip21_uri() { let chain_source = TestChainSource::Esplora(&electrsd); // Setup custom logger. - let mock_logger = init_mock_logger(log::LevelFilter::Trace); + let mock_logger = init_custom_logger(); let log_writer = TestLogWriter::Custom(mock_logger.clone()); let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); @@ -835,7 +836,9 @@ fn generate_bip21_uri() { Err(e) => panic!("Failed to generate URI: {:?}", e), } - assert!(mock_logger.retrieve_logs().last().unwrap().contains("Invoice created: lnbcrt")); + let logs = mock_logger.retrieve_logs(); + let last_log_entry = logs.last().unwrap(); + assert!(last_log_entry.contains("[INFO] Invoice created:")); } #[test] @@ -844,7 +847,7 @@ fn unified_qr_send_receive() { let chain_source = TestChainSource::Esplora(&electrsd); // Setup `log` facade logger. - let mock_logger = init_mock_logger(log::LevelFilter::Trace); + let mock_logger = init_log_logger(log::LevelFilter::Trace); let log_writer = TestLogWriter::LogFacade(LogFacadeLoggerConfig { level: LdkLevel::Trace }); let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); From d8eb0e179a8b8c566dec3c51c3cb9878d0ff0782 Mon Sep 17 00:00:00 2001 From: Enigbe Date: Wed, 11 Dec 2024 13:01:35 +0100 Subject: [PATCH 09/13] chore: revert the renaming of LogLevel to LdkLevel --- bindings/ldk_node.udl | 8 ++++---- src/config.rs | 8 ++++---- src/lib.rs | 2 +- src/logger.rs | 24 ++++++++++++------------ tests/integration_tests_rust.rs | 4 ++-- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 18d01ba77..7bcec1435 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -25,7 +25,7 @@ dictionary EsploraSyncConfig { u64 fee_rate_cache_update_interval_secs; }; -enum LdkLevel { +enum LogLevel { "Gossip", "Trace", "Debug", @@ -36,11 +36,11 @@ enum LdkLevel { dictionary FilesystemLoggerConfig { string log_file_path; - LdkLevel level; + LogLevel level; }; dictionary LogFacadeLoggerConfig { - LdkLevel level; + LogLevel level; }; interface Builder { @@ -573,7 +573,7 @@ dictionary NodeAnnouncementInfo { }; dictionary LogRecord { - LdkLevel level; + LogLevel level; string args; string module_path; u32 line; diff --git a/src/config.rs b/src/config.rs index 9708bcdf4..e89644994 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,7 @@ //! Objects for configuring the node. -use crate::logger::LdkLevel; +use crate::logger::LogLevel; use crate::payment::SendingParameters; use lightning::ln::msgs::SocketAddress; @@ -30,7 +30,7 @@ const DEFAULT_FEE_RATE_CACHE_UPDATE_INTERVAL_SECS: u64 = 60 * 10; const DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER: u64 = 3; const DEFAULT_ANCHOR_PER_CHANNEL_RESERVE_SATS: u64 = 25_000; const DEFAULT_LOG_FILE_PATH: &'static str = "ldk_node.log"; -const DEFAULT_LOG_LEVEL: LdkLevel = LdkLevel::Debug; +const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Debug; // The 'stop gap' parameter used by BDK's wallet sync. This seems to configure the threshold // number of derivation indexes after which BDK stops looking for new scripts belonging to the wallet. @@ -438,14 +438,14 @@ pub struct FilesystemLoggerConfig { /// directory, i.e. [`Config::storage_dir_path`], is preferred. pub log_file_path: String, /// This specifies the log level. - pub level: LdkLevel, + pub level: LogLevel, } /// Configuration options for logging to the `log` facade. #[derive(Debug, Clone)] pub struct LogFacadeLoggerConfig { /// This specifies the log level. - pub level: LdkLevel, + pub level: LogLevel, } impl Default for FilesystemLoggerConfig { diff --git a/src/lib.rs b/src/lib.rs index db5c08842..66e11a3e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,7 +111,7 @@ pub use event::Event; pub use io::utils::generate_entropy_mnemonic; pub use config::{FilesystemLoggerConfig, LogFacadeLoggerConfig}; -pub use logger::{LdkLevel, LogRecord, LogWriter}; +pub use logger::{LogLevel, LogRecord, LogWriter}; #[cfg(feature = "uniffi")] use uniffi_types::*; diff --git a/src/logger.rs b/src/logger.rs index 9cde70f2f..9916fdd93 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -8,7 +8,7 @@ pub(crate) use lightning::util::logger::{Logger as LdkLogger, Record}; pub(crate) use lightning::{log_bytes, log_debug, log_error, log_info, log_trace}; -pub use lightning::util::logger::Level as LdkLevel; +pub use lightning::util::logger::Level as LogLevel; use chrono::Utc; use log::{debug, error, info, trace, warn}; @@ -23,7 +23,7 @@ use std::sync::Arc; /// file, line to inform on log's source. pub struct LogRecord { /// The verbosity level of the message. - pub level: LdkLevel, + pub level: LogLevel, /// The message body. pub args: String, /// The module path of the message. @@ -53,12 +53,12 @@ pub trait LogWriter: Send + Sync + Debug { #[derive(Debug)] pub(crate) struct FilesystemLogger { file_path: String, - level: LdkLevel, + level: LogLevel, } #[derive(Debug)] pub(crate) struct LogFacadeLogger { - level: LdkLevel, + level: LogLevel, } /// Defines a writer for [`Logger`]. @@ -99,12 +99,12 @@ impl LogWriter for Writer { .expect("Failed to write to log file") }, Writer::LogFacadeWriter(log_facade_logger) => match log_facade_logger.level { - LdkLevel::Gossip => trace!("{}", log), - LdkLevel::Trace => trace!("{}", log), - LdkLevel::Debug => debug!("{}", log), - LdkLevel::Info => info!("{}", log), - LdkLevel::Warn => warn!("{}", log), - LdkLevel::Error => error!("{}", log), + LogLevel::Gossip => trace!("{}", log), + LogLevel::Trace => trace!("{}", log), + LogLevel::Debug => debug!("{}", log), + LogLevel::Info => info!("{}", log), + LogLevel::Warn => warn!("{}", log), + LogLevel::Error => error!("{}", log), }, Writer::CustomWriter(custom_logger) => custom_logger.log(record), } @@ -119,7 +119,7 @@ pub(crate) struct Logger { impl Logger { /// Creates a new logger with a filesystem writer. The parameters to this function /// are the path to the log file, and the log level. - pub fn new_fs_writer(log_file_path: String, level: LdkLevel) -> Result { + pub fn new_fs_writer(log_file_path: String, level: LogLevel) -> Result { if let Some(parent_dir) = Path::new(&log_file_path).parent() { fs::create_dir_all(parent_dir) .map_err(|e| eprintln!("ERROR: Failed to create log parent directory: {}", e))?; @@ -137,7 +137,7 @@ impl Logger { Ok(Self { writer: Writer::FileWriter(fs_writer) }) } - pub fn new_log_facade(level: LdkLevel) -> Result { + pub fn new_log_facade(level: LogLevel) -> Result { let log_facade_writer = LogFacadeLogger { level }; Ok(Self { writer: Writer::LogFacadeWriter(log_facade_writer) }) diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index 036d81e07..555d4dde6 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -17,7 +17,7 @@ use common::{ use ldk_node::config::{EsploraSyncConfig, FilesystemLoggerConfig}; use ldk_node::payment::{PaymentKind, QrPaymentResult, SendingParameters}; -use ldk_node::LdkLevel; +use ldk_node::LogLevel; use ldk_node::{Builder, Event, LogFacadeLoggerConfig, NodeError}; use lightning::ln::channelmanager::PaymentId; @@ -848,7 +848,7 @@ fn unified_qr_send_receive() { // Setup `log` facade logger. let mock_logger = init_log_logger(log::LevelFilter::Trace); - let log_writer = TestLogWriter::LogFacade(LogFacadeLoggerConfig { level: LdkLevel::Trace }); + let log_writer = TestLogWriter::LogFacade(LogFacadeLoggerConfig { level: LogLevel::Trace }); let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); let address_a = node_a.onchain_payment().new_address().unwrap(); From fe6c36135a7c3c10943644efa842254b803f1cbf Mon Sep 17 00:00:00 2001 From: Enigbe Date: Thu, 12 Dec 2024 22:34:07 +0100 Subject: [PATCH 10/13] refactor: simplify log-related code and improve clarity This commit includes several improvements aimed at simplifying code, improving readability, and optimizing performance: - Inline enum struct fields to reduce indirection and clutter. - Rename structs to improve clarity and better reflect their purpose. - Enable specific feature flags in dependencies for a more streamlined build. - Eliminate unnecessary data allocations to optimize memory usage. - Correct minor grammatical error in documentation. --- Cargo.toml | 2 +- bindings/ldk_node.udl | 10 ++---- src/builder.rs | 44 +++++++++++------------ src/config.rs | 29 ++++++++------- src/lib.rs | 6 ++-- src/logger.rs | 62 +++++++++++++++++---------------- tests/common/mod.rs | 11 +++--- tests/integration_tests_rust.rs | 10 +++--- 8 files changed, 88 insertions(+), 86 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4e33da8d6..346f19936 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,7 @@ libc = "0.2" uniffi = { version = "0.27.3", features = ["build"], optional = true } serde = { version = "1.0.210", default-features = false, features = ["std", "derive"] } serde_json = { version = "1.0.128", default-features = false, features = ["std"] } -log = { version = "0.4.22", features = ["std"]} +log = { version = "0.4.22", default-features = false, features = ["std"]} vss-client = "0.3" prost = { version = "0.11.6", default-features = false} diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 7bcec1435..742a6ea42 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -35,12 +35,8 @@ enum LogLevel { }; dictionary FilesystemLoggerConfig { - string log_file_path; - LogLevel level; -}; - -dictionary LogFacadeLoggerConfig { - LogLevel level; + string? log_file_path; + LogLevel? log_level; }; interface Builder { @@ -58,7 +54,7 @@ interface Builder { void set_liquidity_source_lsps2(SocketAddress address, PublicKey node_id, string? token); void set_storage_dir_path(string storage_dir_path); void set_filesystem_logger(FilesystemLoggerConfig fs_config); - void set_log_facade_logger(LogFacadeLoggerConfig lf_config); + void set_log_facade_logger(LogLevel log_level); void set_network(Network network); [Throws=BuildError] void set_listening_addresses(sequence listening_addresses); diff --git a/src/builder.rs b/src/builder.rs index d7622c23b..46c34a97a 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -7,8 +7,8 @@ use crate::chain::{ChainSource, DEFAULT_ESPLORA_SERVER_URL}; use crate::config::{ - default_user_config, Config, EsploraSyncConfig, FilesystemLoggerConfig, LogFacadeLoggerConfig, - WALLET_KEYS_SEED_LEN, + default_log_file_path, default_log_level, default_user_config, Config, EsploraSyncConfig, + FilesystemLoggerConfig, WALLET_KEYS_SEED_LEN, }; use crate::connection::ConnectionManager; @@ -19,7 +19,7 @@ use crate::io::sqlite_store::SqliteStore; use crate::io::utils::{read_node_metrics, write_node_metrics}; use crate::io::vss_store::VssStore; use crate::liquidity::LiquiditySource; -use crate::logger::{log_error, log_info, LdkLogger, LogWriter, Logger}; +use crate::logger::{log_error, log_info, LdkLogger, LogLevel, LogWriter, Logger}; use crate::message_handler::NodeCustomMessageHandler; use crate::payment::store::PaymentStore; use crate::peer_store::PeerStore; @@ -109,10 +109,10 @@ impl Default for LiquiditySourceConfig { } } -#[derive(Debug)] +#[derive(Debug, Clone)] enum LogWriterConfig { File(FilesystemLoggerConfig), - Log(LogFacadeLoggerConfig), + Log(LogLevel), Custom(Arc), } @@ -324,8 +324,8 @@ impl NodeBuilder { } /// Configures the [`Node`] instance to write logs to the `log` facade. - pub fn set_log_facade_logger(&mut self, lf_config: LogFacadeLoggerConfig) -> &mut Self { - self.log_writer_config = Some(LogWriterConfig::Log(lf_config)); + pub fn set_log_facade_logger(&mut self, log_level: LogLevel) -> &mut Self { + self.log_writer_config = Some(LogWriterConfig::Log(log_level)); self } @@ -416,9 +416,7 @@ impl NodeBuilder { ) -> Result { use bitcoin::key::Secp256k1; - let writer = LogWriterConfig::default(); - let log_writer_config = - if let Some(config) = &self.log_writer_config { config } else { &writer }; + let log_writer_config = self.log_writer_config.clone().unwrap_or_default(); let logger = setup_logger(&log_writer_config)?; let seed_bytes = seed_bytes_from_config( @@ -484,9 +482,7 @@ impl NodeBuilder { pub fn build_with_vss_store_and_header_provider( &self, vss_url: String, store_id: String, header_provider: Arc, ) -> Result { - let writer = LogWriterConfig::default(); - let log_writer_config = - if let Some(config) = &self.log_writer_config { config } else { &writer }; + let log_writer_config = self.log_writer_config.clone().unwrap_or_default(); let logger = setup_logger(&log_writer_config)?; let seed_bytes = seed_bytes_from_config( @@ -519,9 +515,7 @@ impl NodeBuilder { /// Builds a [`Node`] instance according to the options previously configured. pub fn build_with_store(&self, kv_store: Arc) -> Result { - let writer = LogWriterConfig::default(); - let log_writer_config = - if let Some(config) = &self.log_writer_config { config } else { &writer }; + let log_writer_config = self.log_writer_config.clone().unwrap_or_default(); let logger = setup_logger(&log_writer_config)?; let seed_bytes = seed_bytes_from_config( @@ -651,8 +645,8 @@ impl ArcedNodeBuilder { } /// Configures the [`Node`] instance to write logs to the `log` facade. - pub fn set_log_facade_logger(&self, lf_config: LogFacadeLoggerConfig) { - self.inner.write().unwrap().set_log_facade_logger(lf_config); + pub fn set_log_facade_logger(&self, log_level: LogLevel) { + self.inner.write().unwrap().set_log_facade_logger(log_level); } /// Configures the [`Node`] instance to write logs to the provided custom log writer. @@ -1275,16 +1269,20 @@ fn build_with_store_internal( fn setup_logger(config: &LogWriterConfig) -> Result, BuildError> { match config { LogWriterConfig::File(fs_logger_config) => { - let log_file_path = &fs_logger_config.log_file_path; + let log_file_path = if let Some(fp) = &fs_logger_config.log_file_path { + fp + } else { + &default_log_file_path() + }; + let log_level = fs_logger_config.log_level.unwrap_or(default_log_level()); Ok(Arc::new( - Logger::new_fs_writer(log_file_path.to_string(), fs_logger_config.level) + Logger::new_fs_writer(log_file_path, log_level) .map_err(|_| BuildError::LoggerSetupFailed)?, )) }, - LogWriterConfig::Log(log_facade_logger_config) => Ok(Arc::new( - Logger::new_log_facade(log_facade_logger_config.level) - .map_err(|_| BuildError::LoggerSetupFailed)?, + LogWriterConfig::Log(log_level) => Ok(Arc::new( + Logger::new_log_facade(*log_level).map_err(|_| BuildError::LoggerSetupFailed)?, )), LogWriterConfig::Custom(custom_log_writer) => Ok(Arc::new( Logger::new_custom_writer(custom_log_writer.clone()) diff --git a/src/config.rs b/src/config.rs index e89644994..1d6f0634f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -435,26 +435,31 @@ pub struct FilesystemLoggerConfig { /// The log file path. /// /// This specifies the log file path if a destination other than the storage - /// directory, i.e. [`Config::storage_dir_path`], is preferred. - pub log_file_path: String, + /// directory, i.e. [`Config::storage_dir_path`], is preferred. If unconfigured, + /// defaults to [`DEFAULT_STORAGE_DIR_PATH`]/[`DEFAULT_LOG_FILE_PATH`], i.e. + /// `/tmp/ldk_node/ldk_node.log` + pub log_file_path: Option, /// This specifies the log level. - pub level: LogLevel, -} - -/// Configuration options for logging to the `log` facade. -#[derive(Debug, Clone)] -pub struct LogFacadeLoggerConfig { - /// This specifies the log level. - pub level: LogLevel, + /// + /// If unconfigured, defaults to [`DEFAULT_LOG_LEVEL`], i.e. `LogLevel::Debug` + pub log_level: Option, } impl Default for FilesystemLoggerConfig { fn default() -> Self { - let log_file_path = format!("{}/{}", DEFAULT_STORAGE_DIR_PATH, DEFAULT_LOG_FILE_PATH); - Self { log_file_path, level: DEFAULT_LOG_LEVEL } + let log_file_path = default_log_file_path(); + Self { log_file_path: Some(log_file_path), log_level: Some(default_log_level()) } } } +pub(crate) fn default_log_file_path() -> String { + format!("{}/{}", DEFAULT_STORAGE_DIR_PATH, DEFAULT_LOG_FILE_PATH) +} + +pub(crate) fn default_log_level() -> LogLevel { + DEFAULT_LOG_LEVEL +} + #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/src/lib.rs b/src/lib.rs index 66e11a3e7..3605070af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,7 +85,7 @@ pub mod graph; mod hex_utils; pub mod io; mod liquidity; -mod logger; +pub mod logger; mod message_handler; pub mod payment; mod peer_store; @@ -110,8 +110,7 @@ pub use event::Event; pub use io::utils::generate_entropy_mnemonic; -pub use config::{FilesystemLoggerConfig, LogFacadeLoggerConfig}; -pub use logger::{LogLevel, LogRecord, LogWriter}; +pub use config::FilesystemLoggerConfig; #[cfg(feature = "uniffi")] use uniffi_types::*; @@ -146,6 +145,7 @@ use types::{ pub use types::{ChannelDetails, CustomTlvRecord, PeerDetails, UserChannelId}; use logger::{log_error, log_info, log_trace, LdkLogger, Logger}; +pub use logger::{LogLevel, LogRecord, LogWriter}; use lightning::chain::BestBlock; use lightning::events::bump_transaction::Wallet as LdkWallet; diff --git a/src/logger.rs b/src/logger.rs index 9916fdd93..23f74c072 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -5,6 +5,8 @@ // http://opensource.org/licenses/MIT>, at your option. You may not use this file except in // accordance with one or both of these licenses. +//! Logging-related objects. + pub(crate) use lightning::util::logger::{Logger as LdkLogger, Record}; pub(crate) use lightning::{log_bytes, log_debug, log_error, log_info, log_trace}; @@ -50,55 +52,43 @@ pub trait LogWriter: Send + Sync + Debug { fn log(&self, record: LogRecord); } -#[derive(Debug)] -pub(crate) struct FilesystemLogger { - file_path: String, - level: LogLevel, -} - -#[derive(Debug)] -pub(crate) struct LogFacadeLogger { - level: LogLevel, -} - /// Defines a writer for [`Logger`]. #[derive(Debug)] pub(crate) enum Writer { /// Writes logs to the file system. - FileWriter(FilesystemLogger), + FileWriter { file_path: String, level: LogLevel }, /// Forwards logs to the `log` facade. - LogFacadeWriter(LogFacadeLogger), - /// Forwards logs to custom writer. + LogFacadeWriter { level: LogLevel }, + /// Forwards logs to a custom writer. CustomWriter(Arc), } impl LogWriter for Writer { fn log(&self, record: LogRecord) { - let raw_log = record.args.to_string(); let log = format!( "{} {:<5} [{}:{}] {}\n", Utc::now().format("%Y-%m-%d %H:%M:%S"), record.level.to_string(), record.module_path, record.line, - raw_log + record.args ); match self { - Writer::FileWriter(fs_logger) => { - if record.level < fs_logger.level { + Writer::FileWriter { file_path, level } => { + if record.level < *level { return; } fs::OpenOptions::new() .create(true) .append(true) - .open(fs_logger.file_path.clone()) + .open(file_path.clone()) .expect("Failed to open log file") .write_all(log.as_bytes()) .expect("Failed to write to log file") }, - Writer::LogFacadeWriter(log_facade_logger) => match log_facade_logger.level { + Writer::LogFacadeWriter { level } => match level { LogLevel::Gossip => trace!("{}", log), LogLevel::Trace => trace!("{}", log), LogLevel::Debug => debug!("{}", log), @@ -119,8 +109,8 @@ pub(crate) struct Logger { impl Logger { /// Creates a new logger with a filesystem writer. The parameters to this function /// are the path to the log file, and the log level. - pub fn new_fs_writer(log_file_path: String, level: LogLevel) -> Result { - if let Some(parent_dir) = Path::new(&log_file_path).parent() { + pub fn new_fs_writer(file_path: &str, level: LogLevel) -> Result { + if let Some(parent_dir) = Path::new(&file_path).parent() { fs::create_dir_all(parent_dir) .map_err(|e| eprintln!("ERROR: Failed to create log parent directory: {}", e))?; @@ -128,19 +118,15 @@ impl Logger { fs::OpenOptions::new() .create(true) .append(true) - .open(&log_file_path) + .open(&file_path) .map_err(|e| eprintln!("ERROR: Failed to open log file: {}", e))?; } - let fs_writer = FilesystemLogger { file_path: log_file_path, level }; - - Ok(Self { writer: Writer::FileWriter(fs_writer) }) + Ok(Self { writer: Writer::FileWriter { file_path: file_path.to_string(), level } }) } pub fn new_log_facade(level: LogLevel) -> Result { - let log_facade_writer = LogFacadeLogger { level }; - - Ok(Self { writer: Writer::LogFacadeWriter(log_facade_writer) }) + Ok(Self { writer: Writer::LogFacadeWriter { level } }) } pub fn new_custom_writer(log_writer: Arc) -> Result { @@ -150,6 +136,22 @@ impl Logger { impl LdkLogger for Logger { fn log(&self, record: Record) { - self.writer.log(record.into()); + match &self.writer { + Writer::FileWriter { file_path: _, level } => { + if record.level < *level { + return; + } + self.writer.log(record.into()); + }, + Writer::LogFacadeWriter { level } => { + if record.level < *level { + return; + } + self.writer.log(record.into()); + }, + Writer::CustomWriter(_arc) => { + self.writer.log(record.into()); + }, + } } } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 714893c88..78dbe9923 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -11,10 +11,11 @@ use chrono::Utc; use ldk_node::config::{Config, EsploraSyncConfig}; use ldk_node::io::sqlite_store::SqliteStore; +use ldk_node::logger::{LogLevel, LogRecord, LogWriter}; use ldk_node::payment::{PaymentDirection, PaymentKind, PaymentStatus}; use ldk_node::{ - Builder, CustomTlvRecord, Event, FilesystemLoggerConfig, LightningBalance, - LogFacadeLoggerConfig, LogRecord, LogWriter, Node, NodeError, PendingSweepBalance, + Builder, CustomTlvRecord, Event, FilesystemLoggerConfig, LightningBalance, Node, NodeError, + PendingSweepBalance, }; use lightning::ln::msgs::SocketAddress; @@ -254,7 +255,7 @@ pub(crate) enum TestChainSource<'a> { #[derive(Clone)] pub(crate) enum TestLogWriter { File(FilesystemLoggerConfig), - LogFacade(LogFacadeLoggerConfig), + LogFacade(LogLevel), Custom(Arc), } @@ -387,8 +388,8 @@ pub(crate) fn setup_node( TestLogWriter::File(fs_config) => { builder.set_filesystem_logger(fs_config); }, - TestLogWriter::LogFacade(lf_config) => { - builder.set_log_facade_logger(lf_config); + TestLogWriter::LogFacade(log_level) => { + builder.set_log_facade_logger(log_level); }, TestLogWriter::Custom(log_writer) => { builder.set_custom_logger(log_writer); diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index 555d4dde6..2580b70a8 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -16,9 +16,9 @@ use common::{ }; use ldk_node::config::{EsploraSyncConfig, FilesystemLoggerConfig}; +use ldk_node::logger::LogLevel; use ldk_node::payment::{PaymentKind, QrPaymentResult, SendingParameters}; -use ldk_node::LogLevel; -use ldk_node::{Builder, Event, LogFacadeLoggerConfig, NodeError}; +use ldk_node::{Builder, Event, NodeError}; use lightning::ln::channelmanager::PaymentId; use lightning::util::logger::Level; @@ -226,8 +226,8 @@ fn start_stop_reinit() { setup_builder!(builder, config); builder.set_chain_source_esplora(esplora_url.clone(), Some(sync_config)); builder.set_filesystem_logger(FilesystemLoggerConfig { - log_file_path: format!("{}/{}", config.storage_dir_path, "ldk_node.log"), - level: Level::Debug, + log_file_path: Some(format!("{}/{}", config.storage_dir_path, "ldk_node.log")), + log_level: Some(Level::Debug), }); let node = builder.build_with_store(Arc::clone(&test_sync_store)).unwrap(); @@ -848,7 +848,7 @@ fn unified_qr_send_receive() { // Setup `log` facade logger. let mock_logger = init_log_logger(log::LevelFilter::Trace); - let log_writer = TestLogWriter::LogFacade(LogFacadeLoggerConfig { level: LogLevel::Trace }); + let log_writer = TestLogWriter::LogFacade(LogLevel::Trace); let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false, log_writer); let address_a = node_a.onchain_payment().new_address().unwrap(); From e968562a68190991ca56fb5be44e2079736b23ea Mon Sep 17 00:00:00 2001 From: Enigbe Date: Fri, 13 Dec 2024 05:28:20 +0100 Subject: [PATCH 11/13] chore: remove unused CustomTlvRecord --- src/uniffi_types.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/uniffi_types.rs b/src/uniffi_types.rs index 9cb88597d..c8c84dbed 100644 --- a/src/uniffi_types.rs +++ b/src/uniffi_types.rs @@ -16,7 +16,6 @@ pub use crate::config::{ pub use crate::graph::{ChannelInfo, ChannelUpdateInfo, NodeAnnouncementInfo, NodeInfo}; pub use crate::payment::store::{LSPFeeLimits, PaymentDirection, PaymentKind, PaymentStatus}; pub use crate::payment::{MaxTotalRoutingFeeLimit, QrPaymentResult, SendingParameters}; -pub use crate::types::CustomTlvRecord; pub use lightning::chain::channelmonitor::BalanceSource; pub use lightning::events::{ClosureReason, PaymentFailureReason}; From 0347e04d70b39210b1f3a7ebfa0f7d1b8ac5582c Mon Sep 17 00:00:00 2001 From: Enigbe Date: Fri, 13 Dec 2024 05:32:03 +0100 Subject: [PATCH 12/13] feat: address costly log record re-allocation - allocates Strings only when necessary with `uniffi` feature, otherwise, keeps LogRecord fileds as lifetime references. --- src/logger.rs | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/logger.rs b/src/logger.rs index 23f74c072..e3bea9c89 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -15,14 +15,29 @@ pub use lightning::util::logger::Level as LogLevel; use chrono::Utc; use log::{debug, error, info, trace, warn}; +#[cfg(not(feature = "uniffi"))] +use core::fmt; use std::fmt::Debug; use std::fs; use std::io::Write; use std::path::Path; use std::sync::Arc; -/// A unit of logging output with Metadata to enable filtering Module_path, +/// A unit of logging output with Metadata to enable filtering module_path, /// file, line to inform on log's source. +#[cfg(not(feature = "uniffi"))] +pub struct LogRecord<'a> { + /// The verbosity level of the message. + pub level: LogLevel, + /// The message body. + pub args: fmt::Arguments<'a>, + /// The module path of the message. + pub module_path: &'a str, + /// The line containing the message. + pub line: u32, +} + +#[cfg(feature = "uniffi")] pub struct LogRecord { /// The verbosity level of the message. pub level: LogLevel, @@ -34,6 +49,7 @@ pub struct LogRecord { pub line: u32, } +#[cfg(feature = "uniffi")] impl<'a> From> for LogRecord { fn from(record: Record) -> Self { Self { @@ -45,8 +61,27 @@ impl<'a> From> for LogRecord { } } +#[cfg(not(feature = "uniffi"))] +impl<'a> From> for LogRecord<'a> { + fn from(record: Record<'a>) -> Self { + Self { + level: record.level, + args: record.args, + module_path: record.module_path, + line: record.line, + } + } +} + /// LogWriter trait encapsulating the operations required of a /// logger's writer. +#[cfg(not(feature = "uniffi"))] +pub trait LogWriter: Send + Sync + Debug { + /// Log the record. + fn log<'a>(&self, record: LogRecord<'a>); +} + +#[cfg(feature = "uniffi")] pub trait LogWriter: Send + Sync + Debug { /// Log the record. fn log(&self, record: LogRecord); From 26aff81d678c84fe563bd1867c6a65dfd56a3a59 Mon Sep 17 00:00:00 2001 From: Enigbe Date: Fri, 13 Dec 2024 08:58:41 +0100 Subject: [PATCH 13/13] test(android): set custom log writer via builder method This commit adds a CustomLogWriter class to the kotlin library test, configuring the writer via the exposed node builder and tests the ability to log to the custom writer destination. [WIP] --- .../lightningdevkit/ldknode/AndroidLibTest.kt | 55 +++++++++++++++++++ bindings/ldk_node.udl | 1 + 2 files changed, 56 insertions(+) diff --git a/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt b/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt index 03c4b88a7..e87fad923 100644 --- a/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt +++ b/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt @@ -6,6 +6,7 @@ package org.lightningdevkit.ldknode import kotlin.UInt import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertTrue import kotlin.io.path.createTempDirectory import org.junit.runner.RunWith import org.lightningdevkit.ldknode.*; @@ -16,6 +17,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 @RunWith(AndroidJUnit4::class) class AndroidLibTest { @Test fun node_start_stop() { + val logWriter1 = CustomLogWriter(CustomLogWriter.LogLevel.GOSSIP) + val logWriter2 = CustomLogWriter(CustomLogWriter.LogLevel.GOSSIP) + val tmpDir1 = createTempDirectory("ldk_node").toString() println("Random dir 1: $tmpDir1") val tmpDir2 = createTempDirectory("ldk_node").toString() @@ -37,6 +41,9 @@ class AndroidLibTest { val builder1 = Builder.fromConfig(config1) val builder2 = Builder.fromConfig(config2) + builder1.set_custom_logger(logWriter1) + builder2.set_custom_logger(logWriter2) + val node1 = builder1.build() val node2 = builder2.build() @@ -55,7 +62,55 @@ class AndroidLibTest { val address2 = node2.onchain_payment().newOnchainAddress() println("Funding address 2: $address2") + assertTrue(logWriter1.getLogMessages().isNotEmpty()) + assertTrue(logWriter2.getLogMessages().isNotEmpty()) + node1.stop() node2.stop() } } + +class CustomLogWriter(private var currentLogLevel: LogLevel = LogLevel.INFO): LogWriter { + enum class LogLevel { + ERROR, WARN, INFO, DEBUG, TRACE, GOSSIP + } + + private val logMessages = mutableListOf() + + fun setLogLevel(level: LogLevel) { + currentLogLevel = level + } + + override fun log(record: LogRecord) { + val recordLevel = when(record.level.toLowerCase()) { + "error" -> LogLevel.ERROR + "warn" -> LogLevel.WARN + "info" -> LogLevel.INFO + "debug" -> LogLevel.DEBUG + "trace" -> LogLevel.TRACE + "gossip" -> LogLevel.GOSSIP + else -> LogLevel.INFO + } + + if (isLevelEnabled(recordLevel)) { + val log_message = formatRecord(record) + logMessages.add(log_message) + } + } + + private fun formatRecord(record: LogRecord): String { + val timestamp = java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + return String.format( + "%s %-5s [%s:%d] %s\n", + timestamp, + record.level, + record.modulePath, + record.line, + record.message + ) + } + + private fun isLevelEnabled(level: LogLevel): Boolean { + return level.ordinal <= currentLogLevel.ordinal + } +} diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 742a6ea42..36ebbaa84 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -55,6 +55,7 @@ interface Builder { void set_storage_dir_path(string storage_dir_path); void set_filesystem_logger(FilesystemLoggerConfig fs_config); void set_log_facade_logger(LogLevel log_level); + void set_custom_logger(LogWriter log_writer); void set_network(Network network); [Throws=BuildError] void set_listening_addresses(sequence listening_addresses);