diff --git a/tracing-subscriber/src/fmt/format.rs b/tracing-subscriber/src/fmt/format.rs index b9c37e3c..555b15dc 100644 --- a/tracing-subscriber/src/fmt/format.rs +++ b/tracing-subscriber/src/fmt/format.rs @@ -141,7 +141,17 @@ impl Format { } } - /// Use the given `timer` for log message timestamps. + /// Use the given [`timer`] for log message timestamps. + /// + /// See [`time`] for the provided timer implementations. + /// + /// Note that using the `chrono` feature flag enables the + /// additional time formatters [`ChronoUtc`] and [`ChronoLocal`]. + /// + /// [`time`]: ./time/index.html + /// [`timer`]: ./time/trait.FormatTime.html + /// [`ChronoUtc`]: ./time/struct.ChronoUtc.html + /// [`ChronoLocal`]: ./time/struct.ChronoLocal.html pub fn with_timer(self, timer: T2) -> Format { Format { format: self.format, diff --git a/tracing-subscriber/src/fmt/mod.rs b/tracing-subscriber/src/fmt/mod.rs index f1acad2e..8975411c 100644 --- a/tracing-subscriber/src/fmt/mod.rs +++ b/tracing-subscriber/src/fmt/mod.rs @@ -457,7 +457,17 @@ impl Builder, F, W> where N: for<'writer> FormatFields<'writer> + 'static, { - /// Use the given `timer` for log message timestamps. + /// Use the given [`timer`] for log message timestamps. + /// + /// See [`time`] for the provided timer implementations. + /// + /// Note that using the `chrono` feature flag enables the + /// additional time formatters [`ChronoUtc`] and [`ChronoLocal`]. + /// + /// [`time`]: ./time/index.html + /// [`timer`]: ./time/trait.FormatTime.html + /// [`ChronoUtc`]: ./time/struct.ChronoUtc.html + /// [`ChronoLocal`]: ./time/struct.ChronoLocal.html pub fn with_timer(self, timer: T2) -> Builder, F, W> { Builder { fmt_fields: self.fmt_fields, diff --git a/tracing-subscriber/src/fmt/time.rs b/tracing-subscriber/src/fmt/time.rs index 818d3ae6..3f97340a 100644 --- a/tracing-subscriber/src/fmt/time.rs +++ b/tracing-subscriber/src/fmt/time.rs @@ -17,6 +17,10 @@ use std::time::Instant; /// current time as reported by `std::time::SystemTime`, and the latter does not print the current /// time at all. `FormatTime` is also automatically implemented for any function pointer with the /// appropriate signature. +/// +/// The full list of provided implementations can be found in [`time`]. +/// +/// [`time`]: ./index.html pub trait FormatTime { /// Measure and write out the current time. /// @@ -96,6 +100,111 @@ impl FormatTime for Uptime { } } +/// The RFC 3339 format is used by default and using +/// this struct allows chrono to bypass the parsing +/// used when a custom format string is provided +#[cfg(feature = "chrono")] +#[derive(Debug, Clone, Eq, PartialEq)] +enum ChronoFmtType { + Rfc3339, + Custom(String), +} + +#[cfg(feature = "chrono")] +impl Default for ChronoFmtType { + fn default() -> Self { + ChronoFmtType::Rfc3339 + } +} + +/// Retrieve and print the current UTC time. +#[cfg(feature = "chrono")] +#[derive(Debug, Clone, Eq, PartialEq, Default)] +pub struct ChronoUtc { + format: ChronoFmtType, +} + +#[cfg(feature = "chrono")] +impl ChronoUtc { + /// Format the time using the [`RFC 3339`] format + /// (a subset of [`ISO 8601`]). + /// + /// [`RFC 3339`]: https://tools.ietf.org/html/rfc3339 + /// [`ISO 8601`]: https://en.wikipedia.org/wiki/ISO_8601 + pub fn rfc3339() -> Self { + ChronoUtc { + format: ChronoFmtType::Rfc3339, + } + } + + /// Format the time using the given format string. + /// + /// See [`chrono::format::strftime`] + /// for details on the supported syntax. + /// + /// [`chrono::format::strftime`]: https://docs.rs/chrono/0.4.9/chrono/format/strftime/index.html + pub fn with_format(format_string: String) -> Self { + ChronoUtc { + format: ChronoFmtType::Custom(format_string), + } + } +} + +#[cfg(feature = "chrono")] +impl FormatTime for ChronoUtc { + fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { + let time = chrono::Utc::now(); + match self.format { + ChronoFmtType::Rfc3339 => write!(w, "{} ", time.to_rfc3339()), + ChronoFmtType::Custom(ref format_str) => write!(w, "{} ", time.format(format_str)), + } + } +} + +/// Retrieve and print the current local time. +#[cfg(feature = "chrono")] +#[derive(Debug, Clone, Eq, PartialEq, Default)] +pub struct ChronoLocal { + format: ChronoFmtType, +} + +#[cfg(feature = "chrono")] +impl ChronoLocal { + /// Format the time using the [`RFC 3339`] format + /// (a subset of [`ISO 8601`]). + /// + /// [`RFC 3339`]: https://tools.ietf.org/html/rfc3339 + /// [`ISO 8601`]: https://en.wikipedia.org/wiki/ISO_8601 + pub fn rfc3339() -> Self { + ChronoLocal { + format: ChronoFmtType::Rfc3339, + } + } + + /// Format the time using the given format string. + /// + /// See [`chrono::format::strftime`] + /// for details on the supported syntax. + /// + /// [`chrono::format::strftime`]: https://docs.rs/chrono/0.4.9/chrono/format/strftime/index.html + pub fn with_format(format_string: String) -> Self { + ChronoLocal { + format: ChronoFmtType::Custom(format_string), + } + } +} + +#[cfg(feature = "chrono")] +impl FormatTime for ChronoLocal { + fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { + let time = chrono::Local::now(); + match self.format { + ChronoFmtType::Rfc3339 => write!(w, "{} ", time.to_rfc3339()), + ChronoFmtType::Custom(ref format_str) => write!(w, "{} ", time.format(format_str)), + } + } +} + #[inline(always)] #[cfg(feature = "ansi")] pub(crate) fn write(timer: T, writer: &mut dyn fmt::Write, with_ansi: bool) -> fmt::Result