-
Notifications
You must be signed in to change notification settings - Fork 24
refactor(logging): Cleaner logging setup #442
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: unstable
Are you sure you want to change the base?
Changes from all commits
4f7eeb7
25b787a
0b6031d
dcb0428
a06f94e
853fbee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -1,6 +1,218 @@ | ||||||||||
//! Collection of logging logic for initialising Anchor. | ||||||||||
|
||||||||||
use std::{ | ||||||||||
path::{Path, PathBuf}, | ||||||||||
str::FromStr, | ||||||||||
}; | ||||||||||
|
||||||||||
use clap::Parser; | ||||||||||
use count_layer::CountLayer; | ||||||||||
use global_config::GlobalConfig; | ||||||||||
use logroller::{Compression, LogRollerBuilder, Rotation, RotationSize}; | ||||||||||
use tracing::Level; | ||||||||||
use tracing_appender::non_blocking::{NonBlocking, WorkerGuard}; | ||||||||||
use tracing_subscriber::{EnvFilter, Layer, fmt, layer::SubscriberExt, util::SubscriberInitExt}; | ||||||||||
|
||||||||||
use crate::{ | ||||||||||
tracing_libp2p_discv5_layer::create_libp2p_discv5_tracing_layer, utils::build_workspace_filter, | ||||||||||
}; | ||||||||||
|
||||||||||
mod count_layer; | ||||||||||
mod logging; | ||||||||||
mod tracing_libp2p_discv5_layer; | ||||||||||
pub mod utils; | ||||||||||
pub use count_layer::CountLayer; | ||||||||||
pub use logging::*; | ||||||||||
mod utils; | ||||||||||
|
||||||||||
#[derive(Parser, Debug, Clone)] | ||||||||||
pub struct FileLoggingFlags { | ||||||||||
#[arg( | ||||||||||
long, | ||||||||||
global = true, | ||||||||||
default_value_t = Level::DEBUG, | ||||||||||
value_parser = Level::from_str, | ||||||||||
help = "Specifies the verbosity level used when emitting logs to the log file")] | ||||||||||
pub logfile_debug_level: Level, | ||||||||||
|
||||||||||
#[arg( | ||||||||||
long, | ||||||||||
global = true, | ||||||||||
value_name = "SIZE", | ||||||||||
help = "Maximum size of each log file in MB. Set to 0 to disable file logging.", | ||||||||||
default_value_t = 50 | ||||||||||
)] | ||||||||||
pub logfile_max_size: u64, | ||||||||||
|
||||||||||
#[arg( | ||||||||||
long, | ||||||||||
global = true, | ||||||||||
value_name = "NUMBER", | ||||||||||
help = "Maximum number of log files to keep. Set to 0 to disable file logging.", | ||||||||||
default_value_t = 100 | ||||||||||
)] | ||||||||||
pub logfile_max_number: u64, | ||||||||||
|
||||||||||
#[arg( | ||||||||||
long, | ||||||||||
global = true, | ||||||||||
value_name = "DIR", | ||||||||||
help = "Directory path where the log file will be stored" | ||||||||||
)] | ||||||||||
pub logfile_dir: Option<PathBuf>, | ||||||||||
|
||||||||||
#[arg( | ||||||||||
long, | ||||||||||
global = true, | ||||||||||
help = "If present, compress old log files. This can help reduce the space needed \ | ||||||||||
to store old logs." | ||||||||||
)] | ||||||||||
pub logfile_compression: bool, | ||||||||||
|
||||||||||
#[arg(long, global = true, help = "Enables colors in logfile.")] | ||||||||||
pub logfile_color: bool, | ||||||||||
|
||||||||||
#[arg( | ||||||||||
long, | ||||||||||
global = true, | ||||||||||
default_value_t = Level::DEBUG, | ||||||||||
value_parser = Level::from_str, | ||||||||||
help = "Specifies the verbosity level used for the discv5 dependency log file")] | ||||||||||
pub discv5_log_level: Level, | ||||||||||
|
||||||||||
#[arg( | ||||||||||
long, | ||||||||||
global = true, | ||||||||||
default_value_t = Level::DEBUG, | ||||||||||
value_parser = Level::from_str, | ||||||||||
help = "Specifies the verbosity level used for the libp2p dependency log file. \ | ||||||||||
Certain score penalty information is logged regardless of this setting.")] | ||||||||||
pub libp2p_log_level: Level, | ||||||||||
} | ||||||||||
|
||||||||||
impl FileLoggingFlags { | ||||||||||
pub fn disabled_file_logging(&self) -> bool { | ||||||||||
self.logfile_max_number == 0 || self.logfile_max_size == 0 | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
pub struct LoggingLayer { | ||||||||||
pub non_blocking_writer: NonBlocking, | ||||||||||
pub guard: WorkerGuard, | ||||||||||
} | ||||||||||
impl LoggingLayer { | ||||||||||
pub fn new(non_blocking_writer: NonBlocking, guard: WorkerGuard) -> Self { | ||||||||||
Self { | ||||||||||
non_blocking_writer, | ||||||||||
guard, | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
pub fn init_file_logging( | ||||||||||
logs_dir: &Path, | ||||||||||
config: &FileLoggingFlags, | ||||||||||
) -> Result<Option<LoggingLayer>, String> { | ||||||||||
if config.disabled_file_logging() { | ||||||||||
return Ok(None); | ||||||||||
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. The return type has changed from
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||
} | ||||||||||
|
||||||||||
let filename = PathBuf::from("anchor.log"); | ||||||||||
let mut appender = LogRollerBuilder::new(logs_dir, &filename) | ||||||||||
.rotation(Rotation::SizeBased(RotationSize::MB( | ||||||||||
config.logfile_max_size, | ||||||||||
))) | ||||||||||
.max_keep_files(config.logfile_max_number); | ||||||||||
|
||||||||||
if config.logfile_compression { | ||||||||||
appender = appender.compression(Compression::Gzip); | ||||||||||
} | ||||||||||
|
||||||||||
let file_appender = appender | ||||||||||
.build() | ||||||||||
.map_err(|e| format!("Failed to create rolling file appender: {e}"))?; | ||||||||||
|
||||||||||
let (writer, guard) = tracing_appender::non_blocking(file_appender); | ||||||||||
Ok(Some(LoggingLayer::new(writer, guard))) | ||||||||||
} | ||||||||||
|
||||||||||
pub fn enable_logging( | ||||||||||
file_logging_flags: Option<&FileLoggingFlags>, | ||||||||||
global_config: &GlobalConfig, | ||||||||||
) -> Result<Vec<WorkerGuard>, String> { | ||||||||||
let mut logging_layers = Vec::new(); | ||||||||||
let mut guards = Vec::new(); | ||||||||||
|
||||||||||
let workspace_filter = match build_workspace_filter() { | ||||||||||
Ok(filter) => filter, | ||||||||||
Err(e) => { | ||||||||||
return Err(format!("Unable to build workspace filter: {e}")); | ||||||||||
} | ||||||||||
}; | ||||||||||
|
||||||||||
logging_layers.push( | ||||||||||
fmt::layer() | ||||||||||
.with_filter( | ||||||||||
EnvFilter::builder() | ||||||||||
.with_default_directive(global_config.debug_level.into()) | ||||||||||
.from_env_lossy(), | ||||||||||
) | ||||||||||
.with_filter(workspace_filter.clone()) | ||||||||||
.boxed(), | ||||||||||
); | ||||||||||
|
||||||||||
if let Some(file_logging_flags) = file_logging_flags { | ||||||||||
let logs_dir = file_logging_flags | ||||||||||
.logfile_dir | ||||||||||
.clone() | ||||||||||
.unwrap_or_else(|| global_config.data_dir.default_logs_dir()); | ||||||||||
|
||||||||||
let filter_level: Level = file_logging_flags.logfile_debug_level; | ||||||||||
|
||||||||||
let libp2p_discv5_layer = | ||||||||||
create_libp2p_discv5_tracing_layer(&logs_dir, file_logging_flags)?; | ||||||||||
let file_logging_layer = init_file_logging(&logs_dir, file_logging_flags)?; | ||||||||||
|
||||||||||
if let Some((libp2p_discv5_layer, layer_guards)) = libp2p_discv5_layer { | ||||||||||
guards.extend(layer_guards); | ||||||||||
// Create filter that reduces external library noise to separately configured levels | ||||||||||
// while preserving the configured file log level for Anchor crates | ||||||||||
|
||||||||||
let default = format!( | ||||||||||
"discv5={},libp2p_gossipsub={}", | ||||||||||
file_logging_flags.discv5_log_level, file_logging_flags.libp2p_log_level | ||||||||||
); | ||||||||||
|
||||||||||
logging_layers.push( | ||||||||||
libp2p_discv5_layer | ||||||||||
.with_filter( | ||||||||||
EnvFilter::try_from_default_env() | ||||||||||
.unwrap_or_else(|_| EnvFilter::new(default)), | ||||||||||
) | ||||||||||
.boxed(), | ||||||||||
); | ||||||||||
} | ||||||||||
|
||||||||||
if let Some(file_logging_layer) = file_logging_layer { | ||||||||||
guards.push(file_logging_layer.guard); | ||||||||||
logging_layers.push( | ||||||||||
fmt::layer() | ||||||||||
.with_writer(file_logging_layer.non_blocking_writer) | ||||||||||
.with_ansi(file_logging_flags.logfile_color) | ||||||||||
.with_filter( | ||||||||||
EnvFilter::builder() | ||||||||||
.with_default_directive(filter_level.into()) | ||||||||||
.from_env_lossy(), | ||||||||||
) | ||||||||||
.with_filter(workspace_filter.clone()) | ||||||||||
.boxed(), | ||||||||||
); | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
// Add the CountLayer | ||||||||||
logging_layers.push(CountLayer.boxed()); | ||||||||||
|
||||||||||
tracing_subscriber::registry() | ||||||||||
.with(logging_layers) | ||||||||||
.try_init() | ||||||||||
.map_err(|e| format!("Failed to initialize logging: {e}"))?; | ||||||||||
|
||||||||||
Ok(guards) | ||||||||||
} |
This file was deleted.
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.
The function signature change from
config: FileLoggingFlags
(by value) toconfig: &FileLoggingFlags
(by reference) is a breaking change that could affect existing callers expecting to pass the struct by value.Copilot uses AI. Check for mistakes.