Skip to content

refactor: move format/with_format from builder to formatter #363

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions examples/custom_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -41,7 +41,8 @@ fn main() {
record.args()
)
})
.init();
.try_init()
.unwrap();
}

init_logger();
Expand Down
5 changes: 3 additions & 2 deletions examples/syslog_friendly_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
"<{}>{}: {}",
Expand All @@ -18,7 +18,8 @@ fn main() {
record.args()
)
})
.init(),
.try_init()
.unwrap(),
_ => env_logger::init(),
};
}
2 changes: 1 addition & 1 deletion src/fmt/humantime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
40 changes: 4 additions & 36 deletions src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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())
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -215,38 +215,6 @@ where

pub(crate) type FormatFn = Box<dyn RecordFormat + Sync + Send>;

#[derive(Default)]
pub(crate) struct Builder {
pub(crate) default_format: ConfigurableFormat,
pub(crate) custom_format: Option<FormatFn>,
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"))]
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
136 changes: 69 additions & 67 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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,
}

Expand Down Expand Up @@ -211,68 +211,23 @@ 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<F>(&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
}

/// Whether or not to write the source line number path in the default format.
///
/// 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
}

Expand All @@ -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<usize>) -> &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<fmt::TimestampPrecision>) -> &mut Self {
self.format.default_format.timestamp(timestamp);
self.format.timestamp(timestamp);
self
}

Expand All @@ -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
}

Expand All @@ -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
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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<F>(&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),
}
}
}
Expand Down Expand Up @@ -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 {
Expand Down