diff --git a/src/config.rs b/src/config.rs index 505d2211..4502e402 100644 --- a/src/config.rs +++ b/src/config.rs @@ -58,6 +58,17 @@ pub(crate) enum TimeFormat { Custom(&'static [time::format_description::FormatItem<'static>]), } +#[derive(Debug, Clone, Copy)] +/// Padding to be used for logging the time +pub enum TimePadding { + /// Add spaces on the right side, up to usize many + Right(usize), + /// Do not pad the time + Off, + /// If appliciable, add zeros to the subseconds + AddZeros +} + /// Configuration for the Loggers /// /// All loggers print the message in the following form: @@ -82,6 +93,7 @@ pub struct Config { pub(crate) module: LevelFilter, pub(crate) time_format: TimeFormat, pub(crate) time_offset: UtcOffset, + pub(crate) time_padding: TimePadding, pub(crate) filter_allow: Cow<'static, [Cow<'static, str>]>, pub(crate) filter_ignore: Cow<'static, [Cow<'static, str>]>, #[cfg(feature = "termcolor")] @@ -226,6 +238,12 @@ impl ConfigBuilder { self } + /// Set how the time should be padded + pub fn set_time_padding(&mut self, padding: TimePadding) -> &mut ConfigBuilder { + self.0.time_padding = padding; + self + } + /// Sets the offset used to the current local time offset /// (overriding values previously set by [`ConfigBuilder::set_time_offset`]). /// @@ -345,6 +363,7 @@ impl Default for Config { module: LevelFilter::Off, time_format: TimeFormat::Custom(format_description!("[hour]:[minute]:[second]")), time_offset: UtcOffset::UTC, + time_padding: TimePadding::AddZeros, filter_allow: Cow::Borrowed(&[]), filter_ignore: Cow::Borrowed(&[]), write_log_enable_colors: false, diff --git a/src/loggers/logging.rs b/src/loggers/logging.rs index 47bc99ff..8a390ac2 100644 --- a/src/loggers/logging.rs +++ b/src/loggers/logging.rs @@ -1,4 +1,4 @@ -use crate::config::{TargetPadding, TimeFormat}; +use crate::config::{TargetPadding, TimeFormat, TimePadding}; use crate::{Config, LevelPadding, ThreadLogMode, ThreadPadding}; use log::{LevelFilter, Record}; use std::io::{Error, Write}; @@ -72,22 +72,35 @@ pub fn write_time(write: &mut W, config: &Config) -> Result<(), Error> where W: Write + Sized, { - use time::error::Format; use time::format_description::well_known::*; let time = time::OffsetDateTime::now_utc().to_offset(config.time_offset); - let res = match config.time_format { - TimeFormat::Rfc2822 => time.format_into(write, &Rfc2822), - TimeFormat::Rfc3339 => time.format_into(write, &Rfc3339), - TimeFormat::Custom(format) => time.format_into(write, &format), + let formatted = match config.time_format { + TimeFormat::Rfc2822 => time.format(&Rfc2822), + TimeFormat::Rfc3339 => time.format(&Rfc3339), + TimeFormat::Custom(format) => time.format(&format), }; - match res { - Err(Format::StdIo(err)) => return Err(err), - Err(err) => panic!("Invalid time format: {}", err), - _ => {} + let mut formatted: String = + formatted.unwrap_or_else(|err| panic!("Invalid time format: {}", err)); + + formatted = match config.time_padding { + TimePadding::Right(offset) => format!("{: <1$}", formatted, offset), + TimePadding::AddZeros => { + if matches!(config.time_format, TimeFormat::Rfc3339) { + // only appliciable with Rfc3339 + // + // the rfc3339 timestamp is 30 characters long, if it would not end with a 0 in the + // subseconds part. To fix this inconsistency, we add zeros before the Z. + while formatted.len() < 30 { + formatted.insert(formatted.len() - 1, '0') + } + } + format!("{}", formatted) + } + TimePadding::Off => format!("{}", formatted), }; - write!(write, " ")?; + write!(write, "{} ", formatted)?; Ok(()) }