From 595ff06bf9ebcb9a441744fb3b0c01a65573ece2 Mon Sep 17 00:00:00 2001 From: djugei Date: Sat, 19 Apr 2025 14:26:21 +0200 Subject: [PATCH] refactor: remove fmt::Builder, and retool Builder::format into build_with_format_fn --- examples/custom_format.rs | 5 +- examples/syslog_friendly_format.rs | 5 +- src/fmt/humantime.rs | 2 +- src/fmt/mod.rs | 40 +-------- src/lib.rs | 4 +- src/logger.rs | 136 +++++++++++++++-------------- 6 files changed, 82 insertions(+), 110 deletions(-) diff --git a/examples/custom_format.rs b/examples/custom_format.rs index 80b9aaa3..30a56b9b 100644 --- a/examples/custom_format.rs +++ b/examples/custom_format.rs @@ -29,7 +29,7 @@ fn main() { .write_style("MY_LOG_STYLE"); Builder::from_env(env) - .format(|buf, record| { + .build_with_format_fn(|buf, record| { // We are reusing `anstyle` but there are `anstyle-*` crates to adapt it to your // preferred styling crate. let warn_style = buf.default_level_style(log::Level::Warn); @@ -41,7 +41,8 @@ fn main() { record.args() ) }) - .init(); + .try_init() + .unwrap(); } init_logger(); diff --git a/examples/syslog_friendly_format.rs b/examples/syslog_friendly_format.rs index 9809ab3f..a0a719dc 100644 --- a/examples/syslog_friendly_format.rs +++ b/examples/syslog_friendly_format.rs @@ -3,7 +3,7 @@ use std::io::Write; fn main() { match std::env::var("RUST_LOG_STYLE") { Ok(s) if s == "SYSTEMD" => env_logger::builder() - .format(|buf, record| { + .build_with_format_fn(|buf, record| { writeln!( buf, "<{}>{}: {}", @@ -18,7 +18,8 @@ fn main() { record.args() ) }) - .init(), + .try_init() + .unwrap(), _ => env_logger::init(), }; } diff --git a/src/fmt/humantime.rs b/src/fmt/humantime.rs index a6bab88e..63cd1f58 100644 --- a/src/fmt/humantime.rs +++ b/src/fmt/humantime.rs @@ -15,7 +15,7 @@ impl Formatter { /// /// let mut builder = env_logger::Builder::new(); /// - /// builder.format(|buf, record| { + /// builder.build_with_format_fn(|buf, record| { /// let ts = buf.timestamp(); /// /// writeln!(buf, "{}: {}: {}", ts, record.level(), record.args()) diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs index bd2a2b8f..d04016f0 100644 --- a/src/fmt/mod.rs +++ b/src/fmt/mod.rs @@ -7,7 +7,7 @@ //! //! # Formatting log records //! -//! The format used to print log records can be customised using the [`Builder::format`] +//! The format used to print log records can be customised using the [`Builder::build_with_format_fn`] //! method. //! //! Terminal styling is done through ANSI escape codes and will be adapted to the capabilities of @@ -25,7 +25,7 @@ //! //! let mut builder = env_logger::Builder::new(); //! -//! builder.format(|buf, record| { +//! builder.build_with_format_fn(|buf, record| { //! writeln!(buf, "{}: {}", //! record.level(), //! record.args()) @@ -61,7 +61,7 @@ use std::cell::RefCell; use std::fmt::Display; use std::io::prelude::Write; use std::rc::Rc; -use std::{fmt, io, mem}; +use std::{fmt, io}; #[cfg(feature = "color")] use log::Level; @@ -125,7 +125,7 @@ impl Default for TimestampPrecision { /// /// let mut builder = env_logger::Builder::new(); /// -/// builder.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args())); +/// builder.build_with_format_fn(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args())); /// ``` /// /// [`Write`]: std::io::Write @@ -215,38 +215,6 @@ where pub(crate) type FormatFn = Box; -#[derive(Default)] -pub(crate) struct Builder { - pub(crate) default_format: ConfigurableFormat, - pub(crate) custom_format: Option, - built: bool, -} - -impl Builder { - /// Convert the format into a callable function. - /// - /// If the `custom_format` is `Some`, then any `default_format` switches are ignored. - /// If the `custom_format` is `None`, then a default format is returned. - /// Any `default_format` switches set to `false` won't be written by the format. - pub(crate) fn build(&mut self) -> FormatFn { - assert!(!self.built, "attempt to re-use consumed builder"); - - let built = mem::replace( - self, - Builder { - built: true, - ..Default::default() - }, - ); - - if let Some(fmt) = built.custom_format { - fmt - } else { - Box::new(built.default_format) - } - } -} - #[cfg(feature = "color")] type SubtleStyle = StyledValue<&'static str>; #[cfg(not(feature = "color"))] diff --git a/src/lib.rs b/src/lib.rs index e0afd1c2..bfbf070e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -235,10 +235,10 @@ //! use std::io::Write; //! //! env_logger::builder() -//! .format(|buf, record| { +//! .build_with_format_fn(|buf, record| { //! writeln!(buf, "{}: {}", record.level(), record.args()) //! }) -//! .init(); +//! .try_init().unwrap(); //! ``` //! //! See the [`fmt`] module for more details about custom formats. diff --git a/src/logger.rs b/src/logger.rs index bd4d13b7..88f08f5f 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -27,9 +27,9 @@ pub const DEFAULT_WRITE_STYLE_ENV: &str = "RUST_LOG_STYLE"; /// let mut builder = Builder::from_default_env(); /// /// builder -/// .format(|buf, record| writeln!(buf, "{} - {}", record.level(), record.args())) /// .filter(None, LevelFilter::Info) -/// .init(); +/// .build_with_format_fn(|buf, record| writeln!(buf, "{} - {}", record.level(), record.args())) +/// .try_init().unwrap(); /// /// error!("error message"); /// info!("info message"); @@ -38,7 +38,7 @@ pub const DEFAULT_WRITE_STYLE_ENV: &str = "RUST_LOG_STYLE"; pub struct Builder { filter: env_filter::Builder, writer: writer::Builder, - format: fmt::Builder, + format: fmt::ConfigurableFormat, built: bool, } @@ -211,60 +211,15 @@ impl Builder { self.parse_env(Env::default()) } - /// Sets the format function for formatting the log output. - /// - /// This function is called on each record logged and should format the - /// log record and output it to the given [`Formatter`]. - /// - /// The format function is expected to output the string directly to the - /// `Formatter` so that implementations can use the [`std::fmt`] macros - /// to format and output without intermediate heap allocations. The default - /// `env_logger` formatter takes advantage of this. - /// - /// When the `color` feature is enabled, styling via ANSI escape codes is supported and the - /// output will automatically respect [`Builder::write_style`]. - /// - /// # Examples - /// - /// Use a custom format to write only the log message: - /// - /// ``` - /// use std::io::Write; - /// use env_logger::Builder; - /// - /// let mut builder = Builder::new(); - /// - /// builder.format(|buf, record| writeln!(buf, "{}", record.args())); - /// ``` - /// - /// [`Formatter`]: fmt/struct.Formatter.html - /// [`String`]: https://doc.rust-lang.org/stable/std/string/struct.String.html - /// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html - pub fn format(&mut self, format: F) -> &mut Self - where - F: Fn(&mut Formatter, &Record<'_>) -> io::Result<()> + Sync + Send + 'static, - { - self.format.custom_format = Some(Box::new(format)); - self - } - - /// Use the default format. - /// - /// This method will clear any custom format set on the builder. - pub fn default_format(&mut self) -> &mut Self { - self.format = Default::default(); - self - } - /// Whether or not to write the level in the default format. pub fn format_level(&mut self, write: bool) -> &mut Self { - self.format.default_format.level(write); + self.format.level(write); self } /// Whether or not to write the source file path in the default format. pub fn format_file(&mut self, write: bool) -> &mut Self { - self.format.default_format.file(write); + self.format.file(write); self } @@ -272,7 +227,7 @@ impl Builder { /// /// Only has effect if `format_file` is also enabled pub fn format_line_number(&mut self, write: bool) -> &mut Self { - self.format.default_format.line_number(write); + self.format.line_number(write); self } @@ -287,26 +242,26 @@ impl Builder { /// Whether or not to write the module path in the default format. pub fn format_module_path(&mut self, write: bool) -> &mut Self { - self.format.default_format.module_path(write); + self.format.module_path(write); self } /// Whether or not to write the target in the default format. pub fn format_target(&mut self, write: bool) -> &mut Self { - self.format.default_format.target(write); + self.format.target(write); self } /// Configures the amount of spaces to use to indent multiline log records. /// A value of `None` disables any kind of indentation. pub fn format_indent(&mut self, indent: Option) -> &mut Self { - self.format.default_format.indent(indent); + self.format.indent(indent); self } /// Configures if timestamp should be included and in what precision. pub fn format_timestamp(&mut self, timestamp: Option) -> &mut Self { - self.format.default_format.timestamp(timestamp); + self.format.timestamp(timestamp); self } @@ -332,7 +287,7 @@ impl Builder { /// Configures the end of line suffix. pub fn format_suffix(&mut self, suffix: &'static str) -> &mut Self { - self.format.default_format.suffix(suffix); + self.format.suffix(suffix); self } @@ -351,7 +306,7 @@ impl Builder { where F: Fn(&mut Formatter, &dyn log::kv::Source) -> io::Result<()> + Sync + Send + 'static, { - self.format.default_format.key_values(format); + self.format.key_values(format); self } @@ -497,15 +452,7 @@ impl Builder { /// library has already initialized a global logger. pub fn try_init(&mut self) -> Result<(), SetLoggerError> { let logger = self.build(); - - let max_level = logger.filter(); - let r = log::set_boxed_logger(Box::new(logger)); - - if r.is_ok() { - log::set_max_level(max_level); - } - - r + logger.try_init() } /// Initializes the global logger with the built env logger. @@ -533,7 +480,51 @@ impl Builder { Logger { writer: self.writer.build(), filter: self.filter.build(), - format: self.format.build(), + format: Box::new(std::mem::take(&mut self.format)), + } + } + + /// Sets the format function for formatting the log output, + /// and builds the Logger. + /// + /// This function is called on each record logged and should format the + /// log record and output it to the given [`Formatter`]. + /// + /// The format function is expected to output the string directly to the + /// `Formatter` so that implementations can use the [`std::fmt`] macros + /// to format and output without intermediate heap allocations. The default + /// `env_logger` formatter takes advantage of this. + /// + /// When the `color` feature is enabled, styling via ANSI escape codes is supported and the + /// output will automatically respect [`Builder::write_style`]. + /// + /// # Examples + /// + /// Use a custom format to write only the log message: + /// + /// ``` + /// use std::io::Write; + /// use env_logger::Builder; + /// + /// let mut builder = Builder::new(); + /// + /// builder.build_with_format_fn(|buf, record| writeln!(buf, "{}", record.args())); + /// ``` + /// + /// [`Formatter`]: fmt/struct.Formatter.html + /// [`String`]: https://doc.rust-lang.org/stable/std/string/struct.String.html + /// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html + pub fn build_with_format_fn(&mut self, format: F) -> Logger + where + F: Fn(&mut Formatter, &Record<'_>) -> io::Result<()> + Sync + Send + 'static, + { + assert!(!self.built, "attempt to re-use consumed builder"); + self.built = true; + + Logger { + writer: self.writer.build(), + filter: self.filter.build(), + format: Box::new(format), } } } @@ -641,6 +632,17 @@ impl Logger { pub fn matches(&self, record: &Record<'_>) -> bool { self.filter.matches(record) } + + pub fn try_init(self) -> Result<(), SetLoggerError> { + let max_level = self.filter(); + let r = log::set_boxed_logger(Box::new(self)); + + if r.is_ok() { + log::set_max_level(max_level); + } + + r + } } impl Log for Logger {