Skip to content

Commit a5b96a9

Browse files
committed
feat: impl LogWriter for enumerable log writers
- Creates a LogWriter interface for different writers to write logs to their preferred destinations. These destinations could be either the filesystem or another logger (e.g. custom logger or any that implements log's facade. - The writer and formatter of LdkNodeLogger can be created by configurable options.
1 parent bfddd4c commit a5b96a9

File tree

5 files changed

+279
-102
lines changed

5 files changed

+279
-102
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ libc = "0.2"
7575
uniffi = { version = "0.27.3", features = ["build"], optional = true }
7676
serde = { version = "1.0.210", default-features = false, features = ["std", "derive"] }
7777
serde_json = { version = "1.0.128", default-features = false, features = ["std"] }
78-
78+
log = { version = "0.4.22" }
7979
vss-client = "0.3"
8080
prost = { version = "0.11.6", default-features = false}
8181

src/builder.rs

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
use crate::chain::{ChainSource, DEFAULT_ESPLORA_SERVER_URL};
99
use crate::config::{
10-
default_user_config, Config, EsploraSyncConfig, LoggingConfig, WALLET_KEYS_SEED_LEN,
10+
default_user_config, Config, EsploraSyncConfig, FormatterConfig, LoggerConfig, WriterConfig,
11+
WriterType, WALLET_KEYS_SEED_LEN,
1112
};
1213

1314
use crate::connection::ConnectionManager;
@@ -18,7 +19,7 @@ use crate::io::sqlite_store::SqliteStore;
1819
use crate::io::utils::{read_node_metrics, write_node_metrics};
1920
use crate::io::vss_store::VssStore;
2021
use crate::liquidity::LiquiditySource;
21-
use crate::logger::{default_format, log_error, log_info, FileWriter, LdkNodeLogger, Logger};
22+
use crate::logger::{build_formatter, log_error, log_info, LdkNodeLogger, Logger, Writer};
2223
use crate::message_handler::NodeCustomMessageHandler;
2324
use crate::payment::store::PaymentStore;
2425
use crate::peer_store::PeerStore;
@@ -300,6 +301,18 @@ impl NodeBuilder {
300301
self
301302
}
302303

304+
/// Sets the logger's writer config.
305+
pub fn set_log_writer_config(&mut self, writer_config: WriterConfig) -> &mut Self {
306+
self.config.logger_config.writer = writer_config;
307+
self
308+
}
309+
310+
/// Sets the logger's formatter config.
311+
pub fn set_log_formatter_config(&mut self, formatter_config: FormatterConfig) -> &mut Self {
312+
self.config.logger_config.formatter = formatter_config;
313+
self
314+
}
315+
303316
/// Sets the Bitcoin network used.
304317
pub fn set_network(&mut self, network: Network) -> &mut Self {
305318
self.config.network = network;
@@ -381,7 +394,7 @@ impl NodeBuilder {
381394
) -> Result<Node, BuildError> {
382395
use bitcoin::key::Secp256k1;
383396

384-
let logger = setup_logger(&self.config)?;
397+
let logger = setup_logger(&self.config.logger_config)?;
385398

386399
let seed_bytes = seed_bytes_from_config(
387400
&self.config,
@@ -446,7 +459,7 @@ impl NodeBuilder {
446459
pub fn build_with_vss_store_and_header_provider(
447460
&self, vss_url: String, store_id: String, header_provider: Arc<dyn VssHeaderProvider>,
448461
) -> Result<Node, BuildError> {
449-
let logger = setup_logger(&self.config)?;
462+
let logger = setup_logger(&self.config.logger_config)?;
450463

451464
let seed_bytes = seed_bytes_from_config(
452465
&self.config,
@@ -478,7 +491,7 @@ impl NodeBuilder {
478491

479492
/// Builds a [`Node`] instance according to the options previously configured.
480493
pub fn build_with_store(&self, kv_store: Arc<DynStore>) -> Result<Node, BuildError> {
481-
let logger = setup_logger(&self.config)?;
494+
let logger = setup_logger(&self.config.logger_config)?;
482495
let seed_bytes = seed_bytes_from_config(
483496
&self.config,
484497
self.entropy_source_config.as_ref(),
@@ -600,6 +613,16 @@ impl ArcedNodeBuilder {
600613
self.inner.write().unwrap().set_storage_dir_path(storage_dir_path);
601614
}
602615

616+
/// Sets the logger's writer config.
617+
pub fn set_log_writer_config(&mut self, writer_config: WriterConfig) -> &mut Self {
618+
self.inner.write().unwrap().set_log_writer_config(writer_config);
619+
}
620+
621+
/// Sets the logger's formatter config.
622+
pub fn set_log_formatter_config(&mut self, formatter_config: FormatterConfig) -> &mut Self {
623+
self.inner.write().unwrap().set_log_formatter_config(formatter_config);
624+
}
625+
603626
/// Sets the Bitcoin network used.
604627
pub fn set_network(&self, network: Network) {
605628
self.inner.write().unwrap().set_network(network);
@@ -1211,24 +1234,23 @@ fn build_with_store_internal(
12111234
})
12121235
}
12131236

1214-
/// Sets up the node logger, creating a new log file if it does not exist, or utilizing
1215-
/// the existing log file.
1216-
fn setup_logger(config: &Config) -> Result<Arc<LdkNodeLogger>, BuildError> {
1217-
match config.logging_config {
1218-
LoggingConfig::Custom(ref logger) => Ok(logger.clone()),
1219-
LoggingConfig::Filesystem { ref log_file_path, log_level } => {
1220-
let filesystem_log_writer = FileWriter::new(log_file_path.clone())
1221-
.map_err(|_| BuildError::LoggerSetupFailed)?;
1222-
Ok(Arc::new(
1223-
LdkNodeLogger::new(
1224-
log_level,
1225-
Box::new(default_format),
1226-
Box::new(move |s| filesystem_log_writer.write(s)),
1227-
)
1228-
.map_err(|_| BuildError::LoggerSetupFailed)?,
1229-
))
1230-
},
1231-
}
1237+
/// Sets up the node logger.
1238+
fn setup_logger(config: &LoggerConfig) -> Result<Arc<LdkNodeLogger>, BuildError> {
1239+
let level = match &config.writer.writer_type {
1240+
WriterType::File(file_writer_config) => file_writer_config.level,
1241+
WriterType::LogRelay(log_relay_writer_config) => log_relay_writer_config.level,
1242+
WriterType::Custom(custom_writer_config) => custom_writer_config.level,
1243+
};
1244+
1245+
let writer =
1246+
Writer::new(&config.writer.writer_type).map_err(|_e| BuildError::LoggerSetupFailed)?;
1247+
1248+
let formatter = build_formatter(config.formatter.clone());
1249+
1250+
let ldk_node_logger =
1251+
LdkNodeLogger::new(level, formatter, writer).map_err(|_e| BuildError::LoggerSetupFailed)?;
1252+
1253+
Ok(Arc::new(ldk_node_logger))
12321254
}
12331255

12341256
fn seed_bytes_from_config(

src/config.rs

Lines changed: 103 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,31 @@
77

88
//! Objects for configuring the node.
99
10-
use crate::logger::LdkNodeLogger;
10+
use crate::logger::LogWriter;
1111
use crate::payment::SendingParameters;
1212

1313
use lightning::ln::msgs::SocketAddress;
1414
use lightning::routing::gossip::NodeAlias;
1515
use lightning::util::config::ChannelConfig as LdkChannelConfig;
1616
use lightning::util::config::MaxDustHTLCExposure as LdkMaxDustHTLCExposure;
1717
use lightning::util::config::UserConfig;
18-
use lightning::util::logger::Level as LogLevel;
18+
use lightning::util::logger::Level;
1919

2020
use bitcoin::secp256k1::PublicKey;
2121
use bitcoin::Network;
2222

23+
use std::sync::Arc;
2324
use std::time::Duration;
2425

2526
// Config defaults
2627
const DEFAULT_STORAGE_DIR_PATH: &str = "/tmp/ldk_node";
28+
const DEFAULT_LOG_FILE_PATH: &str = "/tmp/ldk_node/ldk_node.log";
2729
const DEFAULT_NETWORK: Network = Network::Bitcoin;
2830
const DEFAULT_BDK_WALLET_SYNC_INTERVAL_SECS: u64 = 80;
2931
const DEFAULT_LDK_WALLET_SYNC_INTERVAL_SECS: u64 = 30;
3032
const DEFAULT_FEE_RATE_CACHE_UPDATE_INTERVAL_SECS: u64 = 60 * 10;
3133
const DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER: u64 = 3;
32-
const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Debug;
34+
const DEFAULT_LOG_LEVEL: Level = Level::Debug;
3335
const DEFAULT_ANCHOR_PER_CHANNEL_RESERVE_SATS: u64 = 25_000;
3436

3537
// The 'stop gap' parameter used by BDK's wallet sync. This seems to configure the threshold
@@ -104,9 +106,8 @@ pub(crate) const WALLET_KEYS_SEED_LEN: usize = 64;
104106
pub struct Config {
105107
/// The path where the underlying LDK and BDK persist their data.
106108
pub storage_dir_path: String,
107-
/// In the default configuration logs can be found in the [`DEFAULT_STORAGE_DIR_PATH`] subdirectory in
108-
/// [`Config::storage_dir_path`], and the log level is set to [`DEFAULT_LOG_LEVEL`].
109-
pub logging_config: LoggingConfig,
109+
/// The configuration options for the logger.
110+
pub logger_config: LoggerConfig,
110111
/// The used Bitcoin network.
111112
pub network: Network,
112113
/// The addresses on which the node will listen for incoming connections.
@@ -163,7 +164,7 @@ impl Default for Config {
163164
fn default() -> Self {
164165
Self {
165166
storage_dir_path: DEFAULT_STORAGE_DIR_PATH.to_string(),
166-
logging_config: LoggingConfig::default(),
167+
logger_config: LoggerConfig::default(),
167168
network: DEFAULT_NETWORK,
168169
listening_addresses: None,
169170
trusted_peers_0conf: Vec::new(),
@@ -175,34 +176,109 @@ impl Default for Config {
175176
}
176177
}
177178

178-
/// Configuration options for logging.
179+
/// Logger configuration.
179180
#[derive(Debug, Clone)]
180-
pub enum LoggingConfig {
181-
/// An opinionated filesystem logger.
182-
///
183-
/// This logger will always write at `{log_dir}/ldk_node_latest.log`, which is a symlink to the
184-
/// most recent log file, which is created and timestamped at initialization.
185-
Filesystem {
186-
/// The absolute path where logs are stored.
187-
log_file_path: String,
188-
/// The level at which we log messages.
189-
///
190-
/// Any messages below this level will be excluded from the logs.
191-
log_level: LogLevel,
192-
},
193-
/// A custom logger.
194-
Custom(std::sync::Arc<LdkNodeLogger>),
181+
pub struct LoggerConfig {
182+
/// Writer configuration.
183+
pub writer: WriterConfig,
184+
/// Formatter configuration.
185+
pub formatter: FormatterConfig,
186+
}
187+
188+
impl Default for LoggerConfig {
189+
fn default() -> Self {
190+
Self { writer: WriterConfig::default(), formatter: FormatterConfig::default() }
191+
}
192+
}
193+
194+
/// Logger formatter configuration.
195+
#[derive(Debug, Clone)]
196+
pub struct FormatterConfig {
197+
/// Specifies if timestamps should be included in the log messages.
198+
pub include_timestamp: bool,
199+
/// Specifies timestamp format , e.g., "%Y-%m-%d %H:%M:%S".
200+
pub timestamp_format: Option<String>,
201+
/// Specifies if log levels should be included in the log messages.
202+
pub include_level: bool,
203+
/// Specifies the template for log message format, e.g., "{timestamp} [{level}] {message}".
204+
pub message_template: Option<String>,
195205
}
196206

197-
impl Default for LoggingConfig {
207+
impl Default for FormatterConfig {
198208
fn default() -> Self {
199-
Self::Filesystem {
200-
log_file_path: format!("{}/{}", DEFAULT_STORAGE_DIR_PATH, "ldk_node.log"),
201-
log_level: DEFAULT_LOG_LEVEL,
209+
Self {
210+
include_timestamp: true,
211+
timestamp_format: Some("%Y-%m-%d %H:%M:%S".to_string()),
212+
include_level: true,
213+
message_template: Some(
214+
"{timestamp} {level} [{module_path}:{line}] {message}\n".to_string(),
215+
),
202216
}
203217
}
204218
}
205219

220+
/// Logger writer configuration.
221+
#[derive(Debug, Clone)]
222+
pub struct WriterConfig {
223+
/// Writer type for the logger.
224+
pub writer_type: WriterType,
225+
}
226+
227+
impl Default for WriterConfig {
228+
fn default() -> Self {
229+
WriterConfig {
230+
writer_type: WriterType::File(FileWriterConfig::new(
231+
DEFAULT_LOG_FILE_PATH,
232+
DEFAULT_LOG_LEVEL,
233+
)),
234+
}
235+
}
236+
}
237+
238+
/// Log writer configuration type.
239+
#[derive(Debug, Clone)]
240+
pub enum WriterType {
241+
/// Wraps configuration options for logging to the filesystem.
242+
File(FileWriterConfig),
243+
/// Wraps configuration options for relaying logs to [`log`].
244+
LogRelay(LogRelayWriterConfig),
245+
/// Wraps configuration options for relaying logs to a custom logger.
246+
Custom(CustomWriterConfig),
247+
}
248+
249+
/// Configuration for writing to the filesystem.
250+
#[derive(Debug, Clone)]
251+
pub struct FileWriterConfig {
252+
/// Specifies the file path for the logs.
253+
pub log_file_path: String,
254+
/// Specifies the log level.
255+
pub level: Level,
256+
}
257+
258+
impl FileWriterConfig {
259+
/// Creates a new configuration given the path to the log file
260+
/// and the log level.
261+
pub fn new(log_file_path: &str, level: Level) -> Self {
262+
Self { log_file_path: log_file_path.to_string(), level }
263+
}
264+
}
265+
266+
/// Configuration options for [`log`]'s writer.
267+
#[derive(Debug, Clone)]
268+
pub struct LogRelayWriterConfig {
269+
/// Specifies the log level.
270+
pub level: Level,
271+
}
272+
273+
/// Configuration options for a custom log writer.
274+
#[derive(Debug, Clone)]
275+
pub struct CustomWriterConfig {
276+
/// Pointer to any custom log writer.
277+
pub inner: Arc<dyn LogWriter + Send + Sync>,
278+
/// Specifies the log level.
279+
pub level: Level,
280+
}
281+
206282
/// Configuration options pertaining to 'Anchor' channels, i.e., channels for which the
207283
/// `option_anchors_zero_fee_htlc_tx` channel type is negotiated.
208284
///

0 commit comments

Comments
 (0)