diff --git a/Cargo.toml b/Cargo.toml index 55ffdc5bf..d89ad28e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,6 +80,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", default-features = false, features = ["std"]} vss-client = "0.3" prost = { version = "0.11.6", default-features = false} 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..fb29d3219 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 @@ -3,19 +3,16 @@ */ package org.lightningdevkit.ldknode -import kotlin.UInt -import kotlin.test.Test -import kotlin.test.assertEquals +import androidx.test.ext.junit.runners.AndroidJUnit4 import kotlin.io.path.createTempDirectory +import kotlin.test.Test import org.junit.runner.RunWith -import org.lightningdevkit.ldknode.*; -import android.content.Context.MODE_PRIVATE -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.lightningdevkit.ldknode.* @RunWith(AndroidJUnit4::class) class AndroidLibTest { - @Test fun node_start_stop() { + @Test + fun node_start_stop() { val tmpDir1 = createTempDirectory("ldk_node").toString() println("Random dir 1: $tmpDir1") val tmpDir2 = createTempDirectory("ldk_node").toString() @@ -28,13 +25,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 0feaccf1d..c82a5d92e 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 @@ -9,6 +9,7 @@ import java.net.http.HttpRequest import java.net.http.HttpResponse import kotlin.io.path.createTempDirectory import kotlin.test.assertEquals +import kotlin.test.assertTrue fun runCommandAndWait(vararg cmd: String): String { println("Running command \"${cmd.joinToString(" ")}\"") @@ -92,6 +93,60 @@ fun waitForBlock(esploraEndpoint: String, blockHash: String) { } } +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 + } + + fun getLogMessages(): List { + return logMessages.toList() + } + + override fun log(record: LogRecord) { + val recordLevel = + when (record.level.toString().lowercase()) { + "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 logMessage = formatRecord(record) + logMessages.add(logMessage) + println("$logMessage") + } + } + + 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 %-6s [%s:%s] %s\n", + timestamp, + record.level, + record.modulePath, + record.line, + record.args + ) + } + + private fun isLevelEnabled(level: LogLevel): Boolean { + return level.ordinal <= currentLogLevel.ordinal + } +} + @TestInstance(TestInstance.Lifecycle.PER_CLASS) class LibraryTest { @@ -106,6 +161,9 @@ class LibraryTest { } @Test fun fullCycle() { + 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() @@ -118,7 +176,6 @@ class LibraryTest { config1.storageDirPath = tmpDir1 config1.listeningAddresses = listOf(listenAddress1) config1.network = Network.REGTEST - config1.logLevel = LogLevel.TRACE println("Config 1: $config1") @@ -126,13 +183,15 @@ 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) builder1.setChainSourceEsplora(esploraEndpoint, null) + builder1.setCustomLogger(logWriter1) + val builder2 = Builder.fromConfig(config2) builder2.setChainSourceEsplora(esploraEndpoint, null) + builder2.setCustomLogger(logWriter2) val node1 = builder1.build() val node2 = builder2.build() @@ -265,6 +324,9 @@ class LibraryTest { assert(spendableBalance1AfterClose < 100000u) assertEquals(102500uL, spendableBalance2AfterClose) + assertTrue(logWriter1.getLogMessages().isNotEmpty()) + assertTrue(logWriter2.getLogMessages().isNotEmpty()) + node1.stop() node2.stop() } diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index a9ed4ff5b..b0ff44b0a 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,27 @@ dictionary EsploraSyncConfig { u64 fee_rate_cache_update_interval_secs; }; +enum LogLevel { + "Gossip", + "Trace", + "Debug", + "Info", + "Warn", + "Error", +}; + +dictionary LogRecord { + LogLevel level; + string args; + string module_path; + u32 line; +}; + +[Trait, WithForeign] +interface LogWriter { + void log(LogRecord record); +}; + interface Builder { constructor(); [Name=from_config] @@ -41,6 +60,9 @@ 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(string? log_file_path, LogLevel? log_level); + 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); @@ -535,15 +557,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 ceb3c0918..bcd91eeb8 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -6,7 +6,10 @@ // 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, DEFAULT_LOG_FILE_PATH, DEFAULT_LOG_LEVEL, + DEFAULT_STORAGE_DIR_PATH, WALLET_KEYS_SEED_LEN, +}; use crate::connection::ConnectionManager; use crate::event::EventQueue; @@ -16,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, FilesystemLogger, 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; @@ -27,8 +30,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 +109,49 @@ impl Default for LiquiditySourceConfig { } } +#[derive(Clone)] +enum LogWriterConfig { + File { + /// 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. If unconfigured, + /// defaults to [`DEFAULT_LOG_FILE_PATH`] in default storage directory. + log_file_path: Option, + /// This specifies the log level. + /// + /// If unconfigured, defaults to `Debug`. + log_level: Option, + }, + Log(LogLevel), + Custom(Arc), +} + +impl std::fmt::Debug for LogWriterConfig { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + LogWriterConfig::File { log_level, log_file_path } => f + .debug_struct("LogWriterConfig") + .field("log_level", log_level) + .field("log_file_path", log_file_path) + .finish(), + LogWriterConfig::Log(level) => f.debug_tuple("Log").field(level).finish(), + LogWriterConfig::Custom(_) => { + f.debug_tuple("Custom").field(&"").finish() + }, + } + } +} + +impl Default for LogWriterConfig { + fn default() -> Self { + Self::File { + log_file_path: Some(DEFAULT_LOG_FILE_PATH.to_string()), + log_level: Some(DEFAULT_LOG_LEVEL), + } + } +} + /// An error encountered during building a [`Node`]. /// /// [`Node`]: crate::Node @@ -182,6 +228,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 +244,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 +347,27 @@ 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. + /// + /// The `log_file_path` defaults to the [`DEFAULT_LOG_FILE_PATH`] in the default + /// storage directory if set to None. + /// The `log_level` defaults to [`DEFAULT_LOG_LEVEL`] if set to None. + pub fn set_filesystem_logger( + &mut self, log_file_path: Option, log_level: Option, + ) -> &mut Self { + self.log_writer_config = Some(LogWriterConfig::File { log_file_path, log_level }); + self + } + + /// Configures the [`Node`] instance to write logs to the [`log`](https://crates.io/crates/log) facade. + pub fn set_log_facade_logger(&mut self, log_level: LogLevel) -> &mut Self { + self.log_writer_config = Some(LogWriterConfig::Log(log_level)); + self + } + + /// Configures the [`Node`] instance to write logs to the provided custom [`LogWriter`]. + pub fn set_custom_logger(&mut self, log_writer: Arc) -> &mut Self { + self.log_writer_config = Some(LogWriterConfig::Custom(log_writer)); self } @@ -333,12 +400,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 +452,7 @@ impl NodeBuilder { ) -> Result { use bitcoin::key::Secp256k1; - let logger = setup_logger(&self.config)?; + let logger = setup_logger(&self.log_writer_config, &self.config)?; let seed_bytes = seed_bytes_from_config( &self.config, @@ -456,7 +517,7 @@ 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 logger = setup_logger(&self.log_writer_config, &self.config)?; let seed_bytes = seed_bytes_from_config( &self.config, @@ -488,7 +549,8 @@ 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 logger = setup_logger(&self.log_writer_config, &self.config)?; + let seed_bytes = seed_bytes_from_config( &self.config, self.entropy_source_config.as_ref(), @@ -610,9 +672,25 @@ 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. + /// + /// The `log_file_path` defaults to the [`DEFAULT_LOG_FILENAME`] in the default + /// storage directory if set to None. + /// The `log_level` defaults to [`DEFAULT_LOG_LEVEL`] if set to None. + pub fn set_filesystem_logger( + &self, log_file_path: Option, log_level: Option, + ) { + self.inner.write().unwrap().set_filesystem_logger(log_file_path, log_level); + } + + /// Configures the [`Node`] instance to write logs to the [`log`](https://crates.io/crates/log) facade. + 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 [`LogWriter`]. + pub fn set_custom_logger(&self, log_writer: Arc) { + self.inner.write().unwrap().set_custom_logger(log_writer); } /// Sets the Bitcoin network used. @@ -635,11 +713,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 +807,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)); @@ -1242,23 +1315,42 @@ 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. +/// +/// If `log_writer_conf` is set to None, uses [`LogWriterConfig::default()`]. +/// The `node_conf` is provided to access the configured storage directory. +fn setup_logger( + log_writer_conf: &Option, node_conf: &Config, +) -> Result, BuildError> { + let is_default = log_writer_conf.is_none(); + let default_lw_config = LogWriterConfig::default(); + let log_writer_config = + if let Some(conf) = log_writer_conf { conf } else { &default_lw_config }; + + let logger = match log_writer_config { + LogWriterConfig::File { log_file_path, log_level } => { + let fp = DEFAULT_LOG_FILE_PATH + .replace(DEFAULT_STORAGE_DIR_PATH, &node_conf.storage_dir_path); + let log_file_path = + if is_default { &fp } else { log_file_path.as_ref().map(|p| p).unwrap_or(&fp) }; + + let log_level = log_level.unwrap_or(DEFAULT_LOG_LEVEL); + + Logger::new_fs_writer(log_file_path, log_level) + .map_err(|_| BuildError::LoggerSetupFailed)? + }, + LogWriterConfig::Log(log_level) => Logger::new_log_facade(*log_level), + + LogWriterConfig::Custom(custom_log_writer) => { + Logger::new_custom_writer(Arc::clone(&custom_log_writer)) + }, }; - Ok(Arc::new( - FilesystemLogger::new(log_file_path, config.log_level) - .map_err(|_| BuildError::LoggerSetupFailed)?, - )) + Ok(Arc::new(logger)) } 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()), @@ -1280,7 +1372,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 d9fedd453..59ce78f37 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}; @@ -113,13 +113,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 { @@ -132,7 +132,7 @@ pub(crate) enum ChainSource { tx_broadcaster: Arc, kv_store: Arc, config: Arc, - logger: Arc, + logger: Arc, node_metrics: Arc>, }, } @@ -141,7 +141,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); @@ -171,7 +171,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)); @@ -1125,7 +1125,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..f38d7f63d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,6 +7,7 @@ //! Objects for configuring the node. +use crate::logger::LogLevel; 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,15 +22,22 @@ use bitcoin::Network; use std::time::Duration; // Config defaults -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; +/// The default log level. +pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Debug; + +/// The default log file path. +pub const DEFAULT_LOG_FILE_PATH: &'static str = "/tmp/ldk_node/ldk_node.log"; + +/// The default storage directory. +pub const DEFAULT_STORAGE_DIR_PATH: &str = "/tmp/ldk_node"; + // 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. pub(crate) const BDK_CLIENT_STOP_GAP: usize = 20; @@ -103,11 +110,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 +135,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 +166,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, 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 1de77e937..edaa561dd 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}; @@ -282,7 +282,7 @@ impl_writeable_tlv_based_enum!(Event, pub struct EventQueue where - L::Target: Logger, + L::Target: LdkLogger, { queue: Arc>>, waker: Arc>>, @@ -293,7 +293,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())); @@ -372,7 +372,7 @@ where impl ReadableArgs<(Arc, L)> for EventQueue where - L::Target: Logger, + L::Target: LdkLogger, { #[inline] fn read( @@ -436,7 +436,7 @@ impl Future for EventFuture { pub(crate) struct EventHandler where - L::Target: Logger, + L::Target: LdkLogger, { event_queue: Arc>, wallet: Arc, @@ -454,7 +454,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 45ceb536f..be6598c5a 100644 --- a/src/gossip.rs +++ b/src/gossip.rs @@ -7,7 +7,7 @@ use crate::chain::ChainSource; use crate::config::RGS_SYNC_TIMEOUT_SECS; -use crate::logger::{log_error, log_trace, FilesystemLogger, Logger}; +use crate::logger::{log_error, log_trace, LdkLogger, Logger}; use crate::types::{GossipSync, Graph, P2PGossipSync, PeerManager, RapidGossipSync, UtxoLookup}; use crate::Error; @@ -21,18 +21,18 @@ use std::time::Duration; pub(crate) enum GossipSource { P2PNetwork { gossip_sync: Arc, - logger: Arc, + logger: Arc, }, RapidGossipSync { 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::>, @@ -43,7 +43,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); @@ -128,12 +128,12 @@ impl GossipSource { pub(crate) struct RuntimeSpawner { runtime: Arc>>>, - logger: Arc, + logger: Arc, } impl RuntimeSpawner { pub(crate) fn new( - runtime: Arc>>>, logger: Arc, + runtime: Arc>>>, logger: Arc, ) -> Self { Self { runtime, logger } } diff --git a/src/io/utils.rs b/src/io/utils.rs index 218fec473..b5537ed7d 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| { @@ -99,6 +98,17 @@ where let mut key = [0; WALLET_KEYS_SEED_LEN]; thread_rng().fill_bytes(&mut key); + if let Some(parent_dir) = Path::new(&keys_seed_path).parent() { + fs::create_dir_all(parent_dir).map_err(|e| { + log_error!( + logger, + "Failed to create parent directory for key seed file: {}.", + keys_seed_path + ); + e + })?; + } + let mut f = fs::File::create(keys_seed_path).map_err(|e| { log_error!(logger, "Failed to create keys seed file: {}", keys_seed_path); e @@ -123,7 +133,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 +151,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 +171,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 +189,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 +207,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 +236,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 +274,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 +359,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 +376,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 +496,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 +536,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 +610,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 140c6bb41..3df6e4234 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; @@ -143,7 +143,8 @@ 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}; +pub use logger::{LogLevel, LogRecord, LogWriter}; use lightning::chain::BestBlock; use lightning::events::bump_transaction::Wallet as LdkWallet; @@ -153,8 +154,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; @@ -181,23 +180,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 0188b939b..9e9450f8f 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..a850a4e05 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -5,26 +5,177 @@ // 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; +//! Logging-related objects. + +pub(crate) use lightning::util::logger::{Logger as LdkLogger, Record as LdkRecord}; 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 LogLevel; use chrono::Utc; +use log::{debug, error, info, trace, warn}; +#[cfg(not(feature = "uniffi"))] +use core::fmt; 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`, and `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, +} + +/// A unit of logging output with metadata to enable filtering `module_path`, +/// `file`, and `line` to inform on log's source. +/// +/// This version is used when the `uniffi` feature is enabled. +/// It is similar to the non-`uniffi` version, but it omits the lifetime parameter +/// for the `LogRecord`, as the Uniffi-exposed interface cannot handle lifetimes. +#[cfg(feature = "uniffi")] +pub struct LogRecord { + /// The verbosity level of the message. + pub level: LogLevel, + /// The message body. + pub args: String, + /// The module path of the message. + pub module_path: String, + /// The line containing the message. + pub line: u32, +} + +#[cfg(feature = "uniffi")] +impl<'a> From> for LogRecord { + fn from(record: LdkRecord) -> Self { + Self { + level: record.level, + args: record.args.to_string(), + module_path: record.module_path.to_string(), + line: record.line, + } + } +} + +#[cfg(not(feature = "uniffi"))] +impl<'a> From> for LogRecord<'a> { + fn from(record: LdkRecord<'a>) -> Self { + Self { + level: record.level, + args: record.args, + module_path: record.module_path, + line: record.line, + } + } +} + +/// Defines the behavior required for writing log records. +/// +/// Implementors of this trait are responsible for handling log messages, +/// which may involve formatting, filtering, and forwarding them to specific +/// outputs. +#[cfg(not(feature = "uniffi"))] +pub trait LogWriter: Send + Sync { + /// Log the record. + fn log<'a>(&self, record: LogRecord<'a>); +} -pub(crate) struct FilesystemLogger { - file_path: String, - level: Level, +/// Defines the behavior required for writing log records. +/// +/// Implementors of this trait are responsible for handling log messages, +/// which may involve formatting, filtering, and forwarding them to specific +/// outputs. +/// This version is used when the `uniffi` feature is enabled. +/// It is similar to the non-`uniffi` version, but it omits the lifetime parameter +/// for the `LogRecord`, as the Uniffi-exposed interface cannot handle lifetimes. +#[cfg(feature = "uniffi")] +pub trait LogWriter: Send + Sync { + /// Log the record. + fn log(&self, record: LogRecord); } -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 { - if let Some(parent_dir) = Path::new(&log_file_path).parent() { +/// Defines a writer for [`Logger`]. +pub(crate) enum Writer { + /// Writes logs to the file system. + FileWriter { file_path: String, level: LogLevel }, + /// Forwards logs to the `log` facade. + LogFacadeWriter { level: LogLevel }, + /// Forwards logs to a custom writer. + CustomWriter(Arc), +} + +impl LogWriter for Writer { + fn log(&self, record: LogRecord) { + match self { + Writer::FileWriter { file_path, level } => { + if record.level < *level { + return; + } + + let log = format!( + "{} {:<5} [{}:{}] {}\n", + Utc::now().format("%Y-%m-%d %H:%M:%S"), + record.level.to_string(), + record.module_path, + record.line, + record.args + ); + + fs::OpenOptions::new() + .create(true) + .append(true) + .open(file_path) + .expect("Failed to open log file") + .write_all(log.as_bytes()) + .expect("Failed to write to log file") + }, + Writer::LogFacadeWriter { level } => { + macro_rules! log_with_level { + ($log_level:expr, $($args:tt)*) => { + match $log_level { + LogLevel::Gossip | LogLevel::Trace => trace!($($args)*), + LogLevel::Debug => debug!($($args)*), + LogLevel::Info => info!($($args)*), + LogLevel::Warn => warn!($($args)*), + LogLevel::Error => error!($($args)*), + } + }; + } + + log_with_level!( + level, + "{} {:<5} [{}:{}] {}", + Utc::now().format("%Y-%m-%d %H:%M:%S"), + record.level, + record.module_path, + record.line, + record.args + ) + }, + Writer::CustomWriter(custom_logger) => custom_logger.log(record), + } + } +} + +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(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))?; @@ -32,33 +183,40 @@ impl FilesystemLogger { 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))?; } - Ok(Self { file_path: log_file_path, level }) + Ok(Self { writer: Writer::FileWriter { file_path: file_path.to_string(), level } }) + } + + pub fn new_log_facade(level: LogLevel) -> Self { + Self { writer: Writer::LogFacadeWriter { level } } + } + + pub fn new_custom_writer(log_writer: Arc) -> Self { + Self { writer: Writer::CustomWriter(log_writer) } } } -impl Logger for FilesystemLogger { - fn log(&self, record: Record) { - if record.level < self.level { - return; + +impl LdkLogger for Logger { + fn log(&self, record: LdkRecord) { + 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()); + }, } - 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 - ); - 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") } } diff --git a/src/payment/bolt11.rs b/src/payment/bolt11.rs index 4c89ca261..386da30df 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, @@ -65,23 +65,22 @@ macro_rules! maybe_convert_description { pub struct Bolt11Payment { runtime: Arc>>>, channel_manager: Arc, - connection_manager: Arc>>, - liquidity_source: Option>>>, - payment_store: Arc>>, - peer_store: Arc>>, + connection_manager: 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>>, - liquidity_source: Option>>>, - payment_store: Arc>>, - peer_store: Arc>>, config: Arc, - logger: Arc, + connection_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 c32b1a1a8..1ff8739be 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 23d6b6a0b..046d66c69 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; @@ -45,13 +45,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 cff630781..984619855 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, }; @@ -38,17 +38,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 fbeba669b..9ae137de9 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; @@ -344,7 +344,7 @@ impl PaymentDetailsUpdate { pub(crate) struct PaymentStore where - L::Target: Logger, + L::Target: LdkLogger, { payments: Mutex>, kv_store: Arc, @@ -353,7 +353,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 1651358e5..92c405056 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 2b350be63..1c9ab64b9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -9,7 +9,7 @@ use crate::chain::ChainSource; use crate::config::ChannelConfig; use crate::fee_estimator::OnchainFeeEstimator; use crate::gossip::RuntimeSpawner; -use crate::logger::FilesystemLogger; +use crate::logger::Logger; use crate::message_handler::NodeCustomMessageHandler; use lightning::chain::chainmonitor; @@ -43,7 +43,7 @@ pub(crate) type ChainMonitor = chainmonitor::ChainMonitor< Arc, Arc, Arc, - Arc, + Arc, Arc, >; @@ -52,8 +52,8 @@ pub(crate) type PeerManager = lightning::ln::peer_handler::PeerManager< Arc, Arc, Arc, - Arc, - Arc>>, + Arc, + Arc>>, Arc, >; @@ -69,52 +69,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 = - GossipVerifier, Arc>; +pub(crate) type UtxoLookup = GossipVerifier, Arc>; 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, @@ -125,7 +121,7 @@ pub(crate) type OnionMessenger = lightning::onion_message::messenger::OnionMesse pub(crate) type MessageRouter = lightning::onion_message::messenger::DefaultMessageRouter< Arc, - Arc, + Arc, Arc, >; @@ -135,16 +131,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 b52d937a3..755328379 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; @@ -59,7 +59,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>, @@ -73,7 +73,7 @@ impl Wallet where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { pub(crate) fn new( wallet: bdk_wallet::PersistedWallet, @@ -450,7 +450,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, @@ -510,7 +510,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(); @@ -652,7 +652,7 @@ pub(crate) struct WalletKeysManager where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { inner: KeysManager, wallet: Arc>, @@ -663,7 +663,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. /// @@ -694,7 +694,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) @@ -731,7 +731,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( @@ -754,7 +754,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() @@ -765,7 +765,7 @@ impl SignerProvider for WalletKeysManager where B::Target: BroadcasterInterface, E::Target: FeeEstimator, - L::Target: Logger, + L::Target: LdkLogger, { type EcdsaSigner = InMemorySigner; @@ -816,7 +816,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 1e82fc60e..cb58a28cd 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -10,10 +10,10 @@ use ldk_node::config::{Config, EsploraSyncConfig}; use ldk_node::io::sqlite_store::SqliteStore; +use ldk_node::logger::LogLevel; 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; @@ -237,8 +237,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 } @@ -311,6 +309,9 @@ pub(crate) fn setup_node( }, } + let log_file_path = format!("{}/{}", config.storage_dir_path, "ldk_node.log"); + builder.set_filesystem_logger(Some(log_file_path), Some(LogLevel::Gossip)); + 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 7645747b3..8dd39133b 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -780,6 +780,7 @@ 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 address_a = node_a.onchain_payment().new_address().unwrap(); @@ -822,6 +823,7 @@ 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 address_a = node_a.onchain_payment().new_address().unwrap();