From aff70a3ed897ccca2c99d8261e55e6a10b5d08c5 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Fri, 29 Sep 2023 15:51:00 -0700 Subject: [PATCH 01/10] feature: add support for chrono --- Cargo.toml | 12 ++++++++- examples/tokio.rs | 4 +-- src/format.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0d77e3e..e5d8296 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,9 @@ documentation = "https://docs.rs/tracing-glog" [dependencies] tracing = { version = "0.1", default-features = false } -tracing-subscriber = { version = "0.3.3", features = ["std", "fmt", "registry", "time", "local-time"], default-features = false } +tracing-subscriber = { version = "0.3.3", features = ["std", "fmt", "registry", "time", "local-time", "chrono"], default-features = false } time = { version = "0.3.9", features = ["formatting"] } +chrono = { version = "0.4.20", optional = true } nu-ansi-term = { version = "0.46", optional = true } tracing-log = { version = "0.1", optional = true } @@ -27,7 +28,16 @@ tokio = { version = "1.21", features = ["full"] } default = ["ansi"] ansi = ["nu-ansi-term", "tracing-subscriber/ansi"] tracing-log = ["dep:tracing-log"] +chrono = ["dep:chrono", "tracing-subscriber/chrono"] + +[[example]] +name = "tokio" +required-features = ["chrono", "ansi"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] + +[patch.crates-io] +tracing = { git = 'https://github.com/tokio-rs/tracing.git', branch = "davidbarsky/backport-changes" } +tracing-subscriber = { git = 'https://github.com/tokio-rs/tracing.git', branch = "davidbarsky/backport-changes" } diff --git a/examples/tokio.rs b/examples/tokio.rs index 1b9251a..10864fa 100644 --- a/examples/tokio.rs +++ b/examples/tokio.rs @@ -1,7 +1,7 @@ use anyhow::Error; use tokio::task::JoinSet; use tracing::{debug, info, instrument, span, Instrument as _, Level}; -use tracing_glog::{Glog, GlogFields, UtcTime}; +use tracing_glog::{ChronoLocalTime, Glog, GlogFields}; #[instrument] async fn parent_task(subtasks: usize) -> Result<(), Error> { @@ -36,7 +36,7 @@ async fn main() -> Result<(), Error> { Glog::default() .with_target(false) .with_thread_names(false) - .with_timer(UtcTime::default()), + .with_timer(ChronoLocalTime::default()), ) .fmt_fields(GlogFields::default()) .init(); diff --git a/src/format.rs b/src/format.rs index 7868027..49c263d 100644 --- a/src/format.rs +++ b/src/format.rs @@ -5,6 +5,9 @@ use time::{format_description::FormatItem, formatting::Formattable, OffsetDateTi use tracing::{Level, Metadata}; use tracing_subscriber::fmt::{format::Writer, time::FormatTime}; +#[cfg(feature = "chrono")] +use tracing_subscriber::fmt::time::{ChronoLocal, ChronoUtc}; + /// A bridge between `fmt::Write` and `io::Write`. /// /// This is used by the timestamp formatting implementation for the `time` @@ -134,6 +137,37 @@ impl Default for UtcTime { } } +#[cfg(feature = "chrono")] +pub struct ChronoUtcTime { + time: ChronoUtc, +} + +#[cfg(feature = "chrono")] +impl FormatTime for ChronoUtcTime { + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { + #[cfg(feature = "ansi")] + if w.has_ansi_escapes() { + let style = Style::new().dimmed(); + write!(w, "{}", style.prefix())?; + self.time.format_time(w)?; + write!(w, "{}", style.suffix())?; + return Ok(()); + } + + self.time.format_time(w) + } +} + +#[cfg(feature = "chrono")] +impl Default for ChronoUtcTime { + fn default() -> Self { + let fmt_string = String::from("%m%d %H:%M:%S%.6f"); + Self { + time: ChronoUtc::new(fmt_string), + } + } +} + /// Formats the current [local time] using a [formatter] from the [`time` crate]. /// /// To format the current [UTC time] instead, use the [`UtcTime`] type. @@ -189,6 +223,36 @@ where } } +#[cfg(feature = "chrono")] +pub struct ChronoLocalTime { + time: ChronoLocal, +} + +#[cfg(feature = "chrono")] +impl FormatTime for ChronoLocalTime { + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { + #[cfg(feature = "ansi")] + if w.has_ansi_escapes() { + let style = Style::new().dimmed(); + write!(w, "{}", style.prefix())?; + self.time.format_time(w)?; + write!(w, "{}", style.suffix())?; + return Ok(()); + } + + self.time.format_time(w) + } +} + +impl Default for ChronoLocalTime { + fn default() -> Self { + let fmt_string = String::from("%m%d %H:%M:%S%.6f"); + Self { + time: ChronoLocal::new(fmt_string), + } + } +} + fn format_datetime( into: &mut Writer<'_>, now: OffsetDateTime, diff --git a/src/lib.rs b/src/lib.rs index f8309a9..48b1626 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,6 +124,8 @@ mod nu_ansi_term { use crate::nu_ansi_term::Style; use format::FmtLevel; +#[cfg(feature = "chrono")] +pub use format::{ChronoLocalTime, ChronoUtcTime}; pub use format::{LocalTime, UtcTime}; use std::fmt; use tracing::{ From 62a812650615c0c09de17251f402a2281527ebd8 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Mon, 2 Oct 2023 11:09:07 -0400 Subject: [PATCH 02/10] ci: add cargo-hack-check --- .github/workflows/ci.yml | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51e280c..995a246 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,8 +7,8 @@ jobs: name: Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable with: profile: minimal toolchain: stable @@ -21,8 +21,8 @@ jobs: name: Test Suite runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable with: profile: minimal toolchain: stable @@ -35,8 +35,8 @@ jobs: name: Rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable with: profile: minimal toolchain: stable @@ -51,8 +51,8 @@ jobs: name: Clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable with: profile: minimal toolchain: stable @@ -61,4 +61,19 @@ jobs: - uses: actions-rs/cargo@v1 with: command: clippy - args: -- -D warnings \ No newline at end of file + args: -- -D warnings + + cargo-hack: + needs: check + name: cargo check (feature combinations) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + profile: minimal + toolchain: stable + override: true + - name: install cargo-hack + uses: taiki-e/install-action@cargo-hack + run: cargo hack check --feature-powerset --no-dev-deps \ No newline at end of file From 09df5fc66f89a55cc8b99006b2c86353b3022d19 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Mon, 2 Oct 2023 11:10:48 -0400 Subject: [PATCH 03/10] fix missing default + add tracing-log to the patch section. --- Cargo.toml | 5 +++-- src/format.rs | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e5d8296..2032e07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,5 +39,6 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [patch.crates-io] -tracing = { git = 'https://github.com/tokio-rs/tracing.git', branch = "davidbarsky/backport-changes" } -tracing-subscriber = { git = 'https://github.com/tokio-rs/tracing.git', branch = "davidbarsky/backport-changes" } +tracing = { git = 'https://github.com/tokio-rs/tracing.git', branch = "v0.1.x" } +tracing-subscriber = { git = 'https://github.com/tokio-rs/tracing.git', branch = "v0.1.x" } +tracing-log = { git = 'https://github.com/tokio-rs/tracing.git', branch = "v0.1.x" } diff --git a/src/format.rs b/src/format.rs index 49c263d..b30159c 100644 --- a/src/format.rs +++ b/src/format.rs @@ -244,6 +244,7 @@ impl FormatTime for ChronoLocalTime { } } +#[cfg(feature = "chrono")] impl Default for ChronoLocalTime { fn default() -> Self { let fmt_string = String::from("%m%d %H:%M:%S%.6f"); From ba6873905712b9fb4b0329c316eea745686eb4c1 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Mon, 2 Oct 2023 12:06:03 -0400 Subject: [PATCH 04/10] use `with` --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 995a246..96d9e3a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,4 +76,6 @@ jobs: override: true - name: install cargo-hack uses: taiki-e/install-action@cargo-hack - run: cargo hack check --feature-powerset --no-dev-deps \ No newline at end of file + - with: + command: cargo + args: hack check --feature-powerset --no-dev-deps \ No newline at end of file From cbc2803b29c756dc1bb28577b019fb5f95c31f4a Mon Sep 17 00:00:00 2001 From: David Barsky Date: Mon, 2 Oct 2023 12:12:24 -0400 Subject: [PATCH 05/10] man --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96d9e3a..42116de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,8 +74,7 @@ jobs: profile: minimal toolchain: stable override: true - - name: install cargo-hack - uses: taiki-e/install-action@cargo-hack - - with: + - uses: taiki-e/install-action@cargo-hack + with: command: cargo args: hack check --feature-powerset --no-dev-deps \ No newline at end of file From b6a3eb04cc09a3ede41263ef15bd5c2424b07939 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Wed, 4 Oct 2023 13:03:54 -0400 Subject: [PATCH 06/10] docs --- src/format.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/format.rs b/src/format.rs index b30159c..aec9ebb 100644 --- a/src/format.rs +++ b/src/format.rs @@ -137,7 +137,15 @@ impl Default for UtcTime { } } +/// Formats the current [UTC time] using [`chrono` crate]. +/// +/// To format the current local time instead, use the [`ChronoLocalTime`] +/// or the [`LocalTime`] type. +/// +/// [UTC time]: ChronoUtc +/// [`chrono` crate]: chrono #[cfg(feature = "chrono")] +#[derive(Clone, Debug)] pub struct ChronoUtcTime { time: ChronoUtc, } @@ -223,6 +231,13 @@ where } } +/// Formats the current [`local time`] using [`chrono` crate]. +/// +/// To format the UTC time instead, use the [`ChronoUtcTime`] +/// or the [`UtcTime`] type. +/// +/// [`local time`]: ChronoLocal +/// [`chrono` crate]: chrono #[cfg(feature = "chrono")] pub struct ChronoLocalTime { time: ChronoLocal, From f0c69c66ceb5b8ee1c8b43afb5117dd7149915ae Mon Sep 17 00:00:00 2001 From: David Barsky Date: Tue, 14 Nov 2023 15:36:45 -0500 Subject: [PATCH 07/10] update to released version of tracing-subscriber --- Cargo.toml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2032e07..1927bbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/tracing-glog" [dependencies] tracing = { version = "0.1", default-features = false } -tracing-subscriber = { version = "0.3.3", features = ["std", "fmt", "registry", "time", "local-time", "chrono"], default-features = false } +tracing-subscriber = { version = "0.3.18", features = ["std", "fmt", "chrono", "registry", "time", "local-time", "chrono"], default-features = false } time = { version = "0.3.9", features = ["formatting"] } chrono = { version = "0.4.20", optional = true } nu-ansi-term = { version = "0.46", optional = true } @@ -37,8 +37,3 @@ required-features = ["chrono", "ansi"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] - -[patch.crates-io] -tracing = { git = 'https://github.com/tokio-rs/tracing.git', branch = "v0.1.x" } -tracing-subscriber = { git = 'https://github.com/tokio-rs/tracing.git', branch = "v0.1.x" } -tracing-log = { git = 'https://github.com/tokio-rs/tracing.git', branch = "v0.1.x" } From 49976e8bad6883d2ec31ae3b651db2a4dacb312a Mon Sep 17 00:00:00 2001 From: David Barsky Date: Tue, 14 Nov 2023 16:15:55 -0500 Subject: [PATCH 08/10] tracing-glog version --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1927bbe..ed746df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tracing-glog" -version = "0.3.0" +version = "0.3.1" edition = "2021" description = "a glog-inspired formatter for tracing-subscriber" license = "MIT OR Apache-2.0" @@ -11,11 +11,11 @@ documentation = "https://docs.rs/tracing-glog" [dependencies] tracing = { version = "0.1", default-features = false } -tracing-subscriber = { version = "0.3.18", features = ["std", "fmt", "chrono", "registry", "time", "local-time", "chrono"], default-features = false } +tracing-subscriber = { version = "0.3.18", features = ["std", "fmt", "registry", "time", "local-time"], default-features = false } time = { version = "0.3.9", features = ["formatting"] } chrono = { version = "0.4.20", optional = true } nu-ansi-term = { version = "0.46", optional = true } -tracing-log = { version = "0.1", optional = true } +tracing-log = { version = "0.2", optional = true } [dev-dependencies] thiserror = "1" From f56064d80d8263343a16818908203ab258761779 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Thu, 16 Nov 2023 15:45:38 -0500 Subject: [PATCH 09/10] restructure `tracing-glog` to prioritize `chrono` --- Cargo.toml | 15 ++-- examples/tokio_compact.rs | 4 +- src/format.rs | 161 +------------------------------------- src/lib.rs | 12 +-- src/time_crate.rs | 158 +++++++++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+), 173 deletions(-) create mode 100644 src/time_crate.rs diff --git a/Cargo.toml b/Cargo.toml index ed746df..ab49884 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tracing-glog" -version = "0.3.1" +version = "0.4.0" edition = "2021" description = "a glog-inspired formatter for tracing-subscriber" license = "MIT OR Apache-2.0" @@ -11,11 +11,11 @@ documentation = "https://docs.rs/tracing-glog" [dependencies] tracing = { version = "0.1", default-features = false } -tracing-subscriber = { version = "0.3.18", features = ["std", "fmt", "registry", "time", "local-time"], default-features = false } -time = { version = "0.3.9", features = ["formatting"] } -chrono = { version = "0.4.20", optional = true } +tracing-subscriber = { version = "0.3.18", features = ["std", "fmt", "registry", "chrono"], default-features = false } +chrono = { version = "0.4.20" } +time = { version = "0.3.9", features = ["formatting"], default-features = false, optional = true } nu-ansi-term = { version = "0.46", optional = true } -tracing-log = { version = "0.2", optional = true } +tracing-log = { version = "0.2", default-features = false, optional = true } [dev-dependencies] thiserror = "1" @@ -28,11 +28,12 @@ tokio = { version = "1.21", features = ["full"] } default = ["ansi"] ansi = ["nu-ansi-term", "tracing-subscriber/ansi"] tracing-log = ["dep:tracing-log"] -chrono = ["dep:chrono", "tracing-subscriber/chrono"] +time = ["dep:time", "tracing-subscriber/time"] +local-time = ["dep:time", "tracing-subscriber/local-time"] [[example]] name = "tokio" -required-features = ["chrono", "ansi"] +required-features = ["ansi"] [package.metadata.docs.rs] all-features = true diff --git a/examples/tokio_compact.rs b/examples/tokio_compact.rs index 7b8c3ea..83d3919 100644 --- a/examples/tokio_compact.rs +++ b/examples/tokio_compact.rs @@ -1,7 +1,7 @@ use anyhow::Error; use tokio::task::JoinSet; use tracing::{debug, info, instrument, span, Instrument as _, Level}; -use tracing_glog::{Glog, GlogFields, UtcTime}; +use tracing_glog::{ChronoLocalTime, Glog, GlogFields}; #[instrument(skip_all)] async fn no_fields() { @@ -47,7 +47,7 @@ async fn main() -> Result<(), Error> { Glog::default() .with_target(false) .with_thread_names(false) - .with_timer(UtcTime::default()) + .with_timer(ChronoLocalTime::default()) .with_span_names(false), ) .fmt_fields(GlogFields::default().compact()) diff --git a/src/format.rs b/src/format.rs index aec9ebb..1154e11 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,53 +1,11 @@ #[cfg(feature = "ansi")] -use crate::nu_ansi_term::{Color, Style}; -use std::{fmt, io}; -use time::{format_description::FormatItem, formatting::Formattable, OffsetDateTime}; +use nu_ansi_term::{Color, Style}; +use std::fmt; use tracing::{Level, Metadata}; use tracing_subscriber::fmt::{format::Writer, time::FormatTime}; -#[cfg(feature = "chrono")] use tracing_subscriber::fmt::time::{ChronoLocal, ChronoUtc}; -/// A bridge between `fmt::Write` and `io::Write`. -/// -/// This is used by the timestamp formatting implementation for the `time` -/// crate and by the JSON formatter. In both cases, this is needed because -/// `tracing-subscriber`'s `FormatEvent`/`FormatTime` traits expect a -/// `fmt::Write` implementation, while `serde_json::Serializer` and `time`'s -/// `format_into` methods expect an `io::Write`. -pub(crate) struct WriteAdaptor<'a> { - fmt_write: &'a mut dyn fmt::Write, -} - -impl<'a> WriteAdaptor<'a> { - pub(crate) fn new(fmt_write: &'a mut dyn fmt::Write) -> Self { - Self { fmt_write } - } -} - -impl<'a> io::Write for WriteAdaptor<'a> { - fn write(&mut self, buf: &[u8]) -> io::Result { - let s = - std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - self.fmt_write - .write_str(s) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - - Ok(s.as_bytes().len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl<'a> fmt::Debug for WriteAdaptor<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("WriteAdaptor { .. }") - } -} - pub(crate) struct FmtLevel { pub level: Level, #[cfg(feature = "ansi")] @@ -94,49 +52,6 @@ impl fmt::Display for FmtLevel { } } -/// Formats the current [UTC time] using a [formatter] from the [`time` crate]. -/// -/// To format the current [local time] instead, use the [`LocalTime`] type. -/// -/// [UTC time]: time::OffsetDateTime::now_utc -/// [formatter]: time::formatting::Formattable -/// [`time` crate]: time -/// [local time]: time::OffsetDateTime::now_local -#[derive(Clone, Debug)] -pub struct UtcTime>> { - format: F, -} - -impl FormatTime for UtcTime -where - F: Formattable, -{ - fn format_time(&self, writer: &mut Writer<'_>) -> fmt::Result { - let now = OffsetDateTime::now_utc(); - - #[cfg(feature = "ansi")] - if writer.has_ansi_escapes() { - let style = Style::new().dimmed(); - write!(writer, "{}", style.prefix())?; - format_datetime(writer, now, &self.format)?; - write!(writer, "{}", style.suffix())?; - return Ok(()); - } - - format_datetime(writer, now, &self.format) - } -} - -impl Default for UtcTime { - fn default() -> Self { - let format: Vec = time::format_description::parse( - "[month][day] [hour]:[minute]:[second].[subsecond digits:6]", - ) - .expect("Unable to make time formatter"); - Self { format } - } -} - /// Formats the current [UTC time] using [`chrono` crate]. /// /// To format the current local time instead, use the [`ChronoLocalTime`] @@ -144,13 +59,11 @@ impl Default for UtcTime { /// /// [UTC time]: ChronoUtc /// [`chrono` crate]: chrono -#[cfg(feature = "chrono")] #[derive(Clone, Debug)] pub struct ChronoUtcTime { time: ChronoUtc, } -#[cfg(feature = "chrono")] impl FormatTime for ChronoUtcTime { fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { #[cfg(feature = "ansi")] @@ -166,7 +79,6 @@ impl FormatTime for ChronoUtcTime { } } -#[cfg(feature = "chrono")] impl Default for ChronoUtcTime { fn default() -> Self { let fmt_string = String::from("%m%d %H:%M:%S%.6f"); @@ -176,61 +88,6 @@ impl Default for ChronoUtcTime { } } -/// Formats the current [local time] using a [formatter] from the [`time` crate]. -/// -/// To format the current [UTC time] instead, use the [`UtcTime`] type. -/// -///
-///
-///     Warning: The time
-///     crate must be compiled with --cfg unsound_local_offset in order to use
-///     local timestamps. When this cfg is not enabled, local timestamps cannot be recorded, and
-///     events will be logged without timestamps.
-///
-///    See the time
-///    documentation for more details.
-/// 
-/// -/// [local time]: time::OffsetDateTime::now_local -/// [formatter]: time::formatting::Formattable -/// [`time` crate]: time -/// [UTC time]: time::OffsetDateTime::now_utc -#[derive(Clone, Debug)] -pub struct LocalTime>> { - format: F, -} - -impl Default for LocalTime { - fn default() -> Self { - let format: Vec = time::format_description::parse( - "[month][day] [hour]:[minute]:[second].[subsecond digits:6]", - ) - .expect("Unable to make time formatter"); - Self { format } - } -} - -impl FormatTime for LocalTime -where - F: Formattable, -{ - fn format_time(&self, writer: &mut Writer<'_>) -> fmt::Result { - let now = OffsetDateTime::now_local().map_err(|_| fmt::Error)?; - - #[cfg(feature = "ansi")] - if writer.has_ansi_escapes() { - let style = Style::new().dimmed(); - write!(writer, "{}", style.prefix())?; - format_datetime(writer, now, &self.format)?; - // necessary to provide space between the time and the PID - write!(writer, "{}", style.suffix())?; - return Ok(()); - } - - format_datetime(writer, now, &self.format) - } -} - /// Formats the current [`local time`] using [`chrono` crate]. /// /// To format the UTC time instead, use the [`ChronoUtcTime`] @@ -238,12 +95,10 @@ where /// /// [`local time`]: ChronoLocal /// [`chrono` crate]: chrono -#[cfg(feature = "chrono")] pub struct ChronoLocalTime { time: ChronoLocal, } -#[cfg(feature = "chrono")] impl FormatTime for ChronoLocalTime { fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { #[cfg(feature = "ansi")] @@ -259,7 +114,6 @@ impl FormatTime for ChronoLocalTime { } } -#[cfg(feature = "chrono")] impl Default for ChronoLocalTime { fn default() -> Self { let fmt_string = String::from("%m%d %H:%M:%S%.6f"); @@ -269,17 +123,6 @@ impl Default for ChronoLocalTime { } } -fn format_datetime( - into: &mut Writer<'_>, - now: OffsetDateTime, - fmt: &impl Formattable, -) -> fmt::Result { - let mut into = WriteAdaptor::new(into); - now.format_into(&mut into, fmt) - .map_err(|_| fmt::Error) - .map(|_| ()) -} - pub(crate) struct FormatProcessData<'a> { pub(crate) pid: u32, pub(crate) thread_name: Option<&'a str>, diff --git a/src/lib.rs b/src/lib.rs index 48b1626..3a1e258 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,10 +93,14 @@ #[deny(rustdoc::broken_intra_doc_links)] mod format; +#[cfg(feature = "time")] +pub mod time_crate; + #[cfg(feature = "ansi")] mod nu_ansi_term { pub use ::nu_ansi_term::*; } + #[cfg(not(feature = "ansi"))] mod nu_ansi_term { // Minimal API shim for nu_ansi_term to avoid a pile of #[cfg(feature = "ansi")] directives. @@ -124,9 +128,7 @@ mod nu_ansi_term { use crate::nu_ansi_term::Style; use format::FmtLevel; -#[cfg(feature = "chrono")] pub use format::{ChronoLocalTime, ChronoUtcTime}; -pub use format::{LocalTime, UtcTime}; use std::fmt; use tracing::{ field::{Field, Visit}, @@ -147,7 +149,7 @@ use crate::format::{FormatProcessData, FormatSpanFields}; /// A [glog]-inspired span and event formatter. /// /// [glog]: https://github.com/google/glog -pub struct Glog { +pub struct Glog { timer: T, with_span_context: bool, with_thread_names: bool, @@ -239,10 +241,10 @@ impl Glog { } } -impl Default for Glog { +impl Default for Glog { fn default() -> Self { Glog { - timer: UtcTime::default(), + timer: ChronoUtcTime::default(), with_thread_names: false, with_target: false, with_span_context: true, diff --git a/src/time_crate.rs b/src/time_crate.rs new file mode 100644 index 0000000..91df3fb --- /dev/null +++ b/src/time_crate.rs @@ -0,0 +1,158 @@ +#[cfg(feature = "ansi")] +use crate::nu_ansi_term::Style; +use std::{fmt, io}; +use time::{format_description::FormatItem, formatting::Formattable, OffsetDateTime}; +use tracing_subscriber::fmt::{format::Writer, time::FormatTime}; + +/// A bridge between `fmt::Write` and `io::Write`. +/// +/// This is used by the timestamp formatting implementation for the `time` +/// crate and by the JSON formatter. In both cases, this is needed because +/// `tracing-subscriber`'s `FormatEvent`/`FormatTime` traits expect a +/// `fmt::Write` implementation, while `serde_json::Serializer` and `time`'s +/// `format_into` methods expect an `io::Write`. +pub(crate) struct WriteAdaptor<'a> { + fmt_write: &'a mut dyn fmt::Write, +} + +#[cfg(feature = "time")] +fn format_datetime( + into: &mut Writer<'_>, + now: OffsetDateTime, + fmt: &impl Formattable, +) -> fmt::Result { + let mut into = WriteAdaptor::new(into); + now.format_into(&mut into, fmt) + .map_err(|_| fmt::Error) + .map(|_| ()) +} + +impl<'a> WriteAdaptor<'a> { + pub(crate) fn new(fmt_write: &'a mut dyn fmt::Write) -> Self { + Self { fmt_write } + } +} + +impl<'a> std::io::Write for WriteAdaptor<'a> { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let s = std::str::from_utf8(buf) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?; + + self.fmt_write + .write_str(s) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?; + + Ok(s.as_bytes().len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl<'a> fmt::Debug for WriteAdaptor<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("WriteAdaptor { .. }") + } +} + +/// Formats the current [UTC time] using a [formatter] from the [`time` crate]. +/// +/// To format the current [local time] instead, use the [`LocalTime`] type. +/// +/// [UTC time]: time::OffsetDateTime::now_utc +/// [formatter]: time::formatting::Formattable +/// [`time` crate]: time +/// [local time]: time::OffsetDateTime::now_local +#[derive(Clone, Debug)] +pub struct UtcTime>> { + format: F, +} + +impl FormatTime for UtcTime +where + F: Formattable, +{ + fn format_time(&self, writer: &mut Writer<'_>) -> fmt::Result { + let now = OffsetDateTime::now_utc(); + + #[cfg(feature = "ansi")] + if writer.has_ansi_escapes() { + let style = Style::new().dimmed(); + write!(writer, "{}", style.prefix())?; + format_datetime(writer, now, &self.format)?; + write!(writer, "{}", style.suffix())?; + return Ok(()); + } + + format_datetime(writer, now, &self.format) + } +} + +impl Default for UtcTime { + fn default() -> Self { + let format: Vec = time::format_description::parse( + "[month][day] [hour]:[minute]:[second].[subsecond digits:6]", + ) + .expect("Unable to make time formatter"); + Self { format } + } +} + +/// Formats the current [local time] using a [formatter] from the [`time` crate]. +/// +/// To format the current [UTC time] instead, use the [`UtcTime`] type. +/// +///
+///
+///     Warning: The time
+///     crate must be compiled with --cfg unsound_local_offset in order to use
+///     local timestamps. When this cfg is not enabled, local timestamps cannot be recorded, and
+///     events will be logged without timestamps.
+///
+///    See the time
+///    documentation for more details.
+/// 
+/// +/// [local time]: time::OffsetDateTime::now_local +/// [formatter]: time::formatting::Formattable +/// [`time` crate]: time +/// [UTC time]: time::OffsetDateTime::now_utc +#[derive(Clone, Debug)] +#[cfg(feature = "local-time")] +pub struct LocalTime>> { + format: F, +} + +#[cfg(feature = "local-time")] +impl Default for LocalTime { + fn default() -> Self { + let format: Vec = time::format_description::parse( + "[month][day] [hour]:[minute]:[second].[subsecond digits:6]", + ) + .expect("Unable to make time formatter"); + Self { format } + } +} + +#[cfg(feature = "local-time")] +impl FormatTime for LocalTime +where + F: Formattable, +{ + fn format_time(&self, writer: &mut Writer<'_>) -> fmt::Result { + let now = OffsetDateTime::now_local().map_err(|_| fmt::Error)?; + + #[cfg(feature = "ansi")] + if writer.has_ansi_escapes() { + let style = Style::new().dimmed(); + write!(writer, "{}", style.prefix())?; + format_datetime(writer, now, &self.format)?; + // necessary to provide space between the time and the PID + write!(writer, "{}", style.suffix())?; + return Ok(()); + } + + format_datetime(writer, now, &self.format) + } +} From 388d63b9e58dee46e106feff82699bfba3e4f9d5 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Thu, 16 Nov 2023 15:53:06 -0500 Subject: [PATCH 10/10] rename ChronoUtcTime/ChronoLocalTime -> UtcTime/LocalTime --- examples/tokio.rs | 4 ++-- examples/tokio_compact.rs | 4 ++-- src/format.rs | 20 ++++++++++---------- src/lib.rs | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/examples/tokio.rs b/examples/tokio.rs index 10864fa..49dd15f 100644 --- a/examples/tokio.rs +++ b/examples/tokio.rs @@ -1,7 +1,7 @@ use anyhow::Error; use tokio::task::JoinSet; use tracing::{debug, info, instrument, span, Instrument as _, Level}; -use tracing_glog::{ChronoLocalTime, Glog, GlogFields}; +use tracing_glog::{Glog, GlogFields, LocalTime}; #[instrument] async fn parent_task(subtasks: usize) -> Result<(), Error> { @@ -36,7 +36,7 @@ async fn main() -> Result<(), Error> { Glog::default() .with_target(false) .with_thread_names(false) - .with_timer(ChronoLocalTime::default()), + .with_timer(LocalTime::default()), ) .fmt_fields(GlogFields::default()) .init(); diff --git a/examples/tokio_compact.rs b/examples/tokio_compact.rs index 83d3919..091e6aa 100644 --- a/examples/tokio_compact.rs +++ b/examples/tokio_compact.rs @@ -1,7 +1,7 @@ use anyhow::Error; use tokio::task::JoinSet; use tracing::{debug, info, instrument, span, Instrument as _, Level}; -use tracing_glog::{ChronoLocalTime, Glog, GlogFields}; +use tracing_glog::{Glog, GlogFields, LocalTime}; #[instrument(skip_all)] async fn no_fields() { @@ -47,7 +47,7 @@ async fn main() -> Result<(), Error> { Glog::default() .with_target(false) .with_thread_names(false) - .with_timer(ChronoLocalTime::default()) + .with_timer(LocalTime::default()) .with_span_names(false), ) .fmt_fields(GlogFields::default().compact()) diff --git a/src/format.rs b/src/format.rs index 1154e11..a7f6735 100644 --- a/src/format.rs +++ b/src/format.rs @@ -54,17 +54,17 @@ impl fmt::Display for FmtLevel { /// Formats the current [UTC time] using [`chrono` crate]. /// -/// To format the current local time instead, use the [`ChronoLocalTime`] +/// To format the current local time instead, use the [`LocalTime`] /// or the [`LocalTime`] type. /// /// [UTC time]: ChronoUtc /// [`chrono` crate]: chrono #[derive(Clone, Debug)] -pub struct ChronoUtcTime { +pub struct UtcTime { time: ChronoUtc, } -impl FormatTime for ChronoUtcTime { +impl FormatTime for UtcTime { fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { #[cfg(feature = "ansi")] if w.has_ansi_escapes() { @@ -79,7 +79,7 @@ impl FormatTime for ChronoUtcTime { } } -impl Default for ChronoUtcTime { +impl Default for UtcTime { fn default() -> Self { let fmt_string = String::from("%m%d %H:%M:%S%.6f"); Self { @@ -90,16 +90,16 @@ impl Default for ChronoUtcTime { /// Formats the current [`local time`] using [`chrono` crate]. /// -/// To format the UTC time instead, use the [`ChronoUtcTime`] -/// or the [`UtcTime`] type. +/// To format the UTC time instead, use the [`UtcTime`] +/// or the [`crate::time_crate::UtcTime`] type. /// -/// [`local time`]: ChronoLocal +/// [`local time`]: tracing_subscriber::fmt::time::ChronoLocal /// [`chrono` crate]: chrono -pub struct ChronoLocalTime { +pub struct LocalTime { time: ChronoLocal, } -impl FormatTime for ChronoLocalTime { +impl FormatTime for LocalTime { fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { #[cfg(feature = "ansi")] if w.has_ansi_escapes() { @@ -114,7 +114,7 @@ impl FormatTime for ChronoLocalTime { } } -impl Default for ChronoLocalTime { +impl Default for LocalTime { fn default() -> Self { let fmt_string = String::from("%m%d %H:%M:%S%.6f"); Self { diff --git a/src/lib.rs b/src/lib.rs index 3a1e258..cefd889 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,7 +128,7 @@ mod nu_ansi_term { use crate::nu_ansi_term::Style; use format::FmtLevel; -pub use format::{ChronoLocalTime, ChronoUtcTime}; +pub use format::{LocalTime, UtcTime}; use std::fmt; use tracing::{ field::{Field, Visit}, @@ -149,7 +149,7 @@ use crate::format::{FormatProcessData, FormatSpanFields}; /// A [glog]-inspired span and event formatter. /// /// [glog]: https://github.com/google/glog -pub struct Glog { +pub struct Glog { timer: T, with_span_context: bool, with_thread_names: bool, @@ -241,10 +241,10 @@ impl Glog { } } -impl Default for Glog { +impl Default for Glog { fn default() -> Self { Glog { - timer: ChronoUtcTime::default(), + timer: UtcTime::default(), with_thread_names: false, with_target: false, with_span_context: true,