-
Notifications
You must be signed in to change notification settings - Fork 46
Implement configurable native size/time log rotation & deletion #189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,7 +48,7 @@ use crate::io::persist::{ | |
| }; | ||
| use crate::service::NodeService; | ||
| use crate::util::config::{load_config, ArgsConfig, ChainSource}; | ||
| use crate::util::logger::ServerLogger; | ||
| use crate::util::logger::{LogConfig, ServerLogger}; | ||
| use crate::util::metrics::Metrics; | ||
| use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; | ||
| use crate::util::systemd; | ||
|
|
@@ -110,18 +110,30 @@ fn main() { | |
| Network::Regtest => storage_dir.join("regtest"), | ||
| }; | ||
|
|
||
| let log_file_path = config_file.log_file_path.map(PathBuf::from).unwrap_or_else(|| { | ||
| let mut default_log_path = network_dir.clone(); | ||
| default_log_path.push("ldk-server.log"); | ||
| default_log_path | ||
| }); | ||
| let log_file_path = if config_file.log_to_file || config_file.log_file_path.is_some() { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. need to remove |
||
| let path = config_file.log_file_path.map(PathBuf::from).unwrap_or_else(|| { | ||
| let mut default_log_path = network_dir.clone(); | ||
| default_log_path.push("ldk-server.log"); | ||
| default_log_path | ||
| }); | ||
|
|
||
| if log_file_path == storage_dir || log_file_path == network_dir { | ||
| eprintln!("Log file path cannot be the same as storage directory path."); | ||
| std::process::exit(-1); | ||
| } | ||
| if path == storage_dir || path == network_dir { | ||
| eprintln!("Log file path cannot be the same as storage directory path."); | ||
| std::process::exit(-1); | ||
| } | ||
| Some(path) | ||
| } else { | ||
| None | ||
| }; | ||
|
|
||
| let log_config = LogConfig { | ||
| log_to_file: config_file.log_to_file, | ||
| log_max_files: config_file.log_max_files, | ||
| log_max_size_bytes: config_file.log_max_size_bytes, | ||
| log_rotation_interval_secs: config_file.log_rotation_interval_secs, | ||
| }; | ||
|
|
||
| let logger = match ServerLogger::init(config_file.log_level, &log_file_path) { | ||
| let logger = match ServerLogger::init(config_file.log_level, log_file_path, log_config) { | ||
| Ok(logger) => logger, | ||
| Err(e) => { | ||
| eprintln!("Failed to initialize logger: {e}"); | ||
|
|
@@ -519,6 +531,7 @@ fn main() { | |
| break; | ||
| } | ||
| _ = sighup_stream.recv() => { | ||
| info!("Received SIGHUP, reopening log file.."); | ||
| if let Err(e) = logger.reopen() { | ||
| error!("Failed to reopen log file on SIGHUP: {e}"); | ||
| } | ||
|
|
@@ -535,6 +548,7 @@ fn main() { | |
| systemd::notify_stopping(); | ||
| node.stop().expect("Shutdown should always succeed."); | ||
| info!("Shutdown complete.."); | ||
| log::logger().flush(); | ||
| } | ||
|
|
||
| fn send_event_and_upsert_payment( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,6 +56,10 @@ pub struct Config { | |
| pub lsps2_service_config: Option<LSPS2ServiceConfig>, | ||
| pub log_level: LevelFilter, | ||
| pub log_file_path: Option<String>, | ||
| pub log_max_size_bytes: usize, | ||
| pub log_rotation_interval_secs: u64, | ||
| pub log_max_files: usize, | ||
| pub log_to_file: bool, | ||
| pub pathfinding_scores_source_url: Option<String>, | ||
| pub metrics_enabled: bool, | ||
| pub poll_metrics_interval: Option<u64>, | ||
|
|
@@ -110,6 +114,10 @@ struct ConfigBuilder { | |
| lsps2: Option<LiquidityConfig>, | ||
| log_level: Option<String>, | ||
| log_file_path: Option<String>, | ||
| log_max_size_mb: Option<u64>, | ||
| log_rotation_interval_hours: Option<u64>, | ||
| log_max_files: Option<usize>, | ||
| log_to_file: Option<bool>, | ||
| pathfinding_scores_source_url: Option<String>, | ||
| metrics_enabled: Option<bool>, | ||
| poll_metrics_interval: Option<u64>, | ||
|
|
@@ -158,6 +166,11 @@ impl ConfigBuilder { | |
| if let Some(log) = toml.log { | ||
| self.log_level = log.level.or(self.log_level.clone()); | ||
| self.log_file_path = log.file.or(self.log_file_path.clone()); | ||
| self.log_max_size_mb = log.max_size_mb.or(self.log_max_size_mb); | ||
| self.log_rotation_interval_hours = | ||
| log.rotation_interval_hours.or(self.log_rotation_interval_hours); | ||
| self.log_max_files = log.max_files.or(self.log_max_files); | ||
| self.log_to_file = log.log_to_file.or(self.log_to_file); | ||
| } | ||
|
|
||
| if let Some(liquidity) = toml.liquidity { | ||
|
|
@@ -249,6 +262,22 @@ impl ConfigBuilder { | |
| if let Some(tor_proxy_address) = &args.tor_proxy_address { | ||
| self.tor_proxy_address = Some(tor_proxy_address.clone()); | ||
| } | ||
|
|
||
| if let Some(log_max_size_mb) = args.log_max_size_mb { | ||
| self.log_max_size_mb = Some(log_max_size_mb); | ||
| } | ||
|
|
||
| if let Some(log_rotation_interval_hours) = args.log_rotation_interval_hours { | ||
| self.log_rotation_interval_hours = Some(log_rotation_interval_hours); | ||
| } | ||
|
|
||
| if let Some(log_max_files) = args.log_max_files { | ||
| self.log_max_files = Some(log_max_files); | ||
| } | ||
|
|
||
| if args.log_to_file { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since this defaults to true, there is no actual way to set |
||
| self.log_to_file = Some(true); | ||
| } | ||
| } | ||
|
|
||
| fn build(self) -> io::Result<Config> { | ||
|
|
@@ -358,6 +387,11 @@ impl ConfigBuilder { | |
| .transpose()? | ||
| .unwrap_or(LevelFilter::Debug); | ||
|
|
||
| let log_max_size_bytes = self.log_max_size_mb.unwrap_or(50) * 1024 * 1024; | ||
| let log_rotation_interval_secs = self.log_rotation_interval_hours.unwrap_or(24) * 60 * 60; | ||
| let log_max_files = self.log_max_files.unwrap_or(5); | ||
|
Comment on lines
+390
to
+392
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we have these defaults be constants |
||
| let log_to_file = self.log_to_file.unwrap_or(true); | ||
|
|
||
| let lsps2_client_config = self | ||
| .lsps2 | ||
| .as_ref() | ||
|
|
@@ -428,6 +462,10 @@ impl ConfigBuilder { | |
| lsps2_service_config, | ||
| log_level, | ||
| log_file_path: self.log_file_path, | ||
| log_max_size_bytes: log_max_size_bytes as usize, | ||
| log_rotation_interval_secs, | ||
| log_max_files, | ||
| log_to_file, | ||
| pathfinding_scores_source_url, | ||
| metrics_enabled, | ||
| poll_metrics_interval, | ||
|
|
@@ -497,6 +535,10 @@ struct EsploraConfig { | |
| struct LogConfig { | ||
| level: Option<String>, | ||
| file: Option<String>, | ||
| max_size_mb: Option<u64>, | ||
| rotation_interval_hours: Option<u64>, | ||
| max_files: Option<usize>, | ||
| log_to_file: Option<bool>, | ||
| } | ||
|
|
||
| #[derive(Deserialize, Serialize)] | ||
|
|
@@ -733,6 +775,34 @@ pub struct ArgsConfig { | |
| )] | ||
| node_alias: Option<String>, | ||
|
|
||
| #[arg( | ||
| long, | ||
| env = "LDK_SERVER_LOG_MAX_SIZE_MB", | ||
| help = "The maximum size of the log file in MB before rotation. Defaults to 50MB." | ||
| )] | ||
| log_max_size_mb: Option<u64>, | ||
|
|
||
| #[arg( | ||
| long, | ||
| env = "LDK_SERVER_LOG_ROTATION_INTERVAL_HOURS", | ||
| help = "The maximum age of the log file in hours before rotation. Defaults to 24h." | ||
| )] | ||
| log_rotation_interval_hours: Option<u64>, | ||
|
|
||
| #[arg( | ||
| long, | ||
| env = "LDK_SERVER_LOG_MAX_FILES", | ||
| help = "The maximum number of rotated log files to keep. Defaults to 5." | ||
| )] | ||
| log_max_files: Option<usize>, | ||
|
|
||
| #[arg( | ||
| long, | ||
| env = "LDK_SERVER_LOG_TO_FILE", | ||
| help = "The option to enable logging to a file. Defaults to true. If false, logging to file is disabled." | ||
| )] | ||
| log_to_file: bool, | ||
|
|
||
| #[arg( | ||
| long, | ||
| env = "LDK_SERVER_BITCOIND_RPC_ADDRESS", | ||
|
|
@@ -896,6 +966,10 @@ mod tests { | |
| [log] | ||
| level = "Trace" | ||
| file = "/var/log/ldk-server.log" | ||
| max_size_mb = 50 | ||
| rotation_interval_hours = 24 | ||
| max_files = 5 | ||
| log_to_file = true | ||
|
|
||
| [bitcoind] | ||
| rpc_address = "127.0.0.1:8332" | ||
|
|
@@ -941,6 +1015,10 @@ mod tests { | |
| metrics_username: None, | ||
| metrics_password: None, | ||
| tor_proxy_address: None, | ||
| log_to_file: true, | ||
| log_max_size_mb: Some(50), | ||
| log_rotation_interval_hours: Some(24), | ||
| log_max_files: Some(5), | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -962,6 +1040,10 @@ mod tests { | |
| metrics_username: None, | ||
| metrics_password: None, | ||
| tor_proxy_address: None, | ||
| log_to_file: true, | ||
| log_max_size_mb: None, | ||
| log_rotation_interval_hours: None, | ||
| log_max_files: None, | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -1029,6 +1111,10 @@ mod tests { | |
| }), | ||
| log_level: LevelFilter::Trace, | ||
| log_file_path: Some("/var/log/ldk-server.log".to_string()), | ||
| log_max_size_bytes: 50 * 1024 * 1024, | ||
| log_rotation_interval_secs: 24 * 60 * 60, | ||
| log_max_files: 5, | ||
| log_to_file: true, | ||
| pathfinding_scores_source_url: None, | ||
| metrics_enabled: false, | ||
| poll_metrics_interval: None, | ||
|
|
@@ -1344,6 +1430,10 @@ mod tests { | |
| metrics_password: None, | ||
| tor_config: None, | ||
| hrn_config: HumanReadableNamesConfig::default(), | ||
| log_max_size_bytes: 50 * 1024 * 1024, | ||
| log_rotation_interval_secs: 24 * 60 * 60, | ||
| log_max_files: 5, | ||
| log_to_file: true, | ||
| }; | ||
|
|
||
| assert_eq!(config.listening_addrs, expected.listening_addrs); | ||
|
|
@@ -1357,6 +1447,10 @@ mod tests { | |
| assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url); | ||
| assert_eq!(config.metrics_enabled, expected.metrics_enabled); | ||
| assert_eq!(config.tor_config, expected.tor_config); | ||
| assert_eq!(config.log_max_size_bytes, expected.log_max_size_bytes); | ||
| assert_eq!(config.log_rotation_interval_secs, expected.log_rotation_interval_secs); | ||
| assert_eq!(config.log_max_files, expected.log_max_files); | ||
| assert_eq!(config.log_to_file, expected.log_to_file); | ||
| } | ||
|
|
||
| #[test] | ||
|
|
@@ -1454,6 +1548,10 @@ mod tests { | |
| proxy_address: SocketAddress::from_str("127.0.0.1:9050").unwrap(), | ||
| }), | ||
| hrn_config: HumanReadableNamesConfig::default(), | ||
| log_max_size_bytes: 50 * 1024 * 1024, | ||
| log_rotation_interval_secs: 24 * 60 * 60, | ||
| log_max_files: 5, | ||
| log_to_file: false, | ||
| }; | ||
|
|
||
| assert_eq!(config.listening_addrs, expected.listening_addrs); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, it seems we're now no longer compatible with
logrotate, but rather rotate ourselves whenlog_to_fileis configured? I guess that's fine, but we might want to update docs here and elsewhere?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still are, I added that back in 42cd66a.
Yes, we rotate ourselves when
log_to_fileis configured, but also have theSIGHUPsignal handler for users relying onlogrotateUh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But how would the user disable our internal log rotation if they use
logrotatethemselves?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the catch. Addressed this in the fixup to decouple our internal log rotation from the
SIGHUPsignal handler for users relying onlogrotate.