Skip to content

Commit 8a993c2

Browse files
authored
feature: add support for chrono (#18)
1 parent 0eaa2e2 commit 8a993c2

File tree

7 files changed

+244
-136
lines changed

7 files changed

+244
-136
lines changed

.github/workflows/ci.yml

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ jobs:
77
name: Check
88
runs-on: ubuntu-latest
99
steps:
10-
- uses: actions/checkout@v2
11-
- uses: actions-rs/toolchain@v1
10+
- uses: actions/checkout@v3
11+
- uses: dtolnay/rust-toolchain@stable
1212
with:
1313
profile: minimal
1414
toolchain: stable
@@ -21,8 +21,8 @@ jobs:
2121
name: Test Suite
2222
runs-on: ubuntu-latest
2323
steps:
24-
- uses: actions/checkout@v2
25-
- uses: actions-rs/toolchain@v1
24+
- uses: actions/checkout@v3
25+
- uses: dtolnay/rust-toolchain@stable
2626
with:
2727
profile: minimal
2828
toolchain: stable
@@ -35,8 +35,8 @@ jobs:
3535
name: Rustfmt
3636
runs-on: ubuntu-latest
3737
steps:
38-
- uses: actions/checkout@v2
39-
- uses: actions-rs/toolchain@v1
38+
- uses: actions/checkout@v3
39+
- uses: dtolnay/rust-toolchain@stable
4040
with:
4141
profile: minimal
4242
toolchain: stable
@@ -51,8 +51,8 @@ jobs:
5151
name: Clippy
5252
runs-on: ubuntu-latest
5353
steps:
54-
- uses: actions/checkout@v2
55-
- uses: actions-rs/toolchain@v1
54+
- uses: actions/checkout@v3
55+
- uses: dtolnay/rust-toolchain@stable
5656
with:
5757
profile: minimal
5858
toolchain: stable
@@ -61,4 +61,20 @@ jobs:
6161
- uses: actions-rs/cargo@v1
6262
with:
6363
command: clippy
64-
args: -- -D warnings
64+
args: -- -D warnings
65+
66+
cargo-hack:
67+
needs: check
68+
name: cargo check (feature combinations)
69+
runs-on: ubuntu-latest
70+
steps:
71+
- uses: actions/checkout@v3
72+
- uses: dtolnay/rust-toolchain@stable
73+
with:
74+
profile: minimal
75+
toolchain: stable
76+
override: true
77+
- uses: taiki-e/install-action@cargo-hack
78+
with:
79+
command: cargo
80+
args: hack check --feature-powerset --no-dev-deps

Cargo.toml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "tracing-glog"
3-
version = "0.3.0"
3+
version = "0.4.0"
44
edition = "2021"
55
description = "a glog-inspired formatter for tracing-subscriber"
66
license = "MIT OR Apache-2.0"
@@ -11,10 +11,11 @@ documentation = "https://docs.rs/tracing-glog"
1111

1212
[dependencies]
1313
tracing = { version = "0.1", default-features = false }
14-
tracing-subscriber = { version = "0.3.3", features = ["std", "fmt", "registry", "time", "local-time"], default-features = false }
15-
time = { version = "0.3.9", features = ["formatting"] }
14+
tracing-subscriber = { version = "0.3.18", features = ["std", "fmt", "registry", "chrono"], default-features = false }
15+
chrono = { version = "0.4.20" }
16+
time = { version = "0.3.9", features = ["formatting"], default-features = false, optional = true }
1617
nu-ansi-term = { version = "0.46", optional = true }
17-
tracing-log = { version = "0.1", optional = true }
18+
tracing-log = { version = "0.2", default-features = false, optional = true }
1819

1920
[dev-dependencies]
2021
thiserror = "1"
@@ -27,6 +28,12 @@ tokio = { version = "1.21", features = ["full"] }
2728
default = ["ansi"]
2829
ansi = ["nu-ansi-term", "tracing-subscriber/ansi"]
2930
tracing-log = ["dep:tracing-log"]
31+
time = ["dep:time", "tracing-subscriber/time"]
32+
local-time = ["dep:time", "tracing-subscriber/local-time"]
33+
34+
[[example]]
35+
name = "tokio"
36+
required-features = ["ansi"]
3037

3138
[package.metadata.docs.rs]
3239
all-features = true

examples/tokio.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use anyhow::Error;
22
use tokio::task::JoinSet;
33
use tracing::{debug, info, instrument, span, Instrument as _, Level};
4-
use tracing_glog::{Glog, GlogFields, UtcTime};
4+
use tracing_glog::{Glog, GlogFields, LocalTime};
55

66
#[instrument]
77
async fn parent_task(subtasks: usize) -> Result<(), Error> {
@@ -36,7 +36,7 @@ async fn main() -> Result<(), Error> {
3636
Glog::default()
3737
.with_target(false)
3838
.with_thread_names(false)
39-
.with_timer(UtcTime::default()),
39+
.with_timer(LocalTime::default()),
4040
)
4141
.fmt_fields(GlogFields::default())
4242
.init();

examples/tokio_compact.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use anyhow::Error;
22
use tokio::task::JoinSet;
33
use tracing::{debug, info, instrument, span, Instrument as _, Level};
4-
use tracing_glog::{Glog, GlogFields, UtcTime};
4+
use tracing_glog::{Glog, GlogFields, LocalTime};
55

66
#[instrument(skip_all)]
77
async fn no_fields() {
@@ -47,7 +47,7 @@ async fn main() -> Result<(), Error> {
4747
Glog::default()
4848
.with_target(false)
4949
.with_thread_names(false)
50-
.with_timer(UtcTime::default())
50+
.with_timer(LocalTime::default())
5151
.with_span_names(false),
5252
)
5353
.fmt_fields(GlogFields::default().compact())

src/format.rs

Lines changed: 42 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,10 @@
11
#[cfg(feature = "ansi")]
2-
use crate::nu_ansi_term::{Color, Style};
3-
use std::{fmt, io};
4-
use time::{format_description::FormatItem, formatting::Formattable, OffsetDateTime};
2+
use nu_ansi_term::{Color, Style};
3+
use std::fmt;
54
use tracing::{Level, Metadata};
65
use tracing_subscriber::fmt::{format::Writer, time::FormatTime};
76

8-
/// A bridge between `fmt::Write` and `io::Write`.
9-
///
10-
/// This is used by the timestamp formatting implementation for the `time`
11-
/// crate and by the JSON formatter. In both cases, this is needed because
12-
/// `tracing-subscriber`'s `FormatEvent`/`FormatTime` traits expect a
13-
/// `fmt::Write` implementation, while `serde_json::Serializer` and `time`'s
14-
/// `format_into` methods expect an `io::Write`.
15-
pub(crate) struct WriteAdaptor<'a> {
16-
fmt_write: &'a mut dyn fmt::Write,
17-
}
18-
19-
impl<'a> WriteAdaptor<'a> {
20-
pub(crate) fn new(fmt_write: &'a mut dyn fmt::Write) -> Self {
21-
Self { fmt_write }
22-
}
23-
}
24-
25-
impl<'a> io::Write for WriteAdaptor<'a> {
26-
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
27-
let s =
28-
std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
29-
30-
self.fmt_write
31-
.write_str(s)
32-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
33-
34-
Ok(s.as_bytes().len())
35-
}
36-
37-
fn flush(&mut self) -> io::Result<()> {
38-
Ok(())
39-
}
40-
}
41-
42-
impl<'a> fmt::Debug for WriteAdaptor<'a> {
43-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44-
f.pad("WriteAdaptor { .. }")
45-
}
46-
}
7+
use tracing_subscriber::fmt::time::{ChronoLocal, ChronoUtc};
478

489
pub(crate) struct FmtLevel {
4910
pub level: Level,
@@ -91,113 +52,75 @@ impl fmt::Display for FmtLevel {
9152
}
9253
}
9354

94-
/// Formats the current [UTC time] using a [formatter] from the [`time` crate].
55+
/// Formats the current [UTC time] using [`chrono` crate].
9556
///
96-
/// To format the current [local time] instead, use the [`LocalTime`] type.
57+
/// To format the current local time instead, use the [`LocalTime`]
58+
/// or the [`LocalTime`] type.
9759
///
98-
/// [UTC time]: time::OffsetDateTime::now_utc
99-
/// [formatter]: time::formatting::Formattable
100-
/// [`time` crate]: time
101-
/// [local time]: time::OffsetDateTime::now_local
60+
/// [UTC time]: ChronoUtc
61+
/// [`chrono` crate]: chrono
10262
#[derive(Clone, Debug)]
103-
pub struct UtcTime<F = Vec<FormatItem<'static>>> {
104-
format: F,
63+
pub struct UtcTime {
64+
time: ChronoUtc,
10565
}
10666

107-
impl<F> FormatTime for UtcTime<F>
108-
where
109-
F: Formattable,
110-
{
111-
fn format_time(&self, writer: &mut Writer<'_>) -> fmt::Result {
112-
let now = OffsetDateTime::now_utc();
113-
67+
impl FormatTime for UtcTime {
68+
fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
11469
#[cfg(feature = "ansi")]
115-
if writer.has_ansi_escapes() {
70+
if w.has_ansi_escapes() {
11671
let style = Style::new().dimmed();
117-
write!(writer, "{}", style.prefix())?;
118-
format_datetime(writer, now, &self.format)?;
119-
write!(writer, "{}", style.suffix())?;
72+
write!(w, "{}", style.prefix())?;
73+
self.time.format_time(w)?;
74+
write!(w, "{}", style.suffix())?;
12075
return Ok(());
12176
}
12277

123-
format_datetime(writer, now, &self.format)
78+
self.time.format_time(w)
12479
}
12580
}
12681

12782
impl Default for UtcTime {
12883
fn default() -> Self {
129-
let format: Vec<FormatItem> = time::format_description::parse(
130-
"[month][day] [hour]:[minute]:[second].[subsecond digits:6]",
131-
)
132-
.expect("Unable to make time formatter");
133-
Self { format }
84+
let fmt_string = String::from("%m%d %H:%M:%S%.6f");
85+
Self {
86+
time: ChronoUtc::new(fmt_string),
87+
}
13488
}
13589
}
13690

137-
/// Formats the current [local time] using a [formatter] from the [`time` crate].
138-
///
139-
/// To format the current [UTC time] instead, use the [`UtcTime`] type.
140-
///
141-
/// <div class="example-wrap" style="display:inline-block">
142-
/// <pre class="compile_fail" style="white-space:normal;font:inherit;">
143-
/// <strong>Warning</strong>: The <a href = "https://docs.rs/time/0.3/time/"><code>time</code>
144-
/// crate</a> must be compiled with <code>--cfg unsound_local_offset</code> in order to use
145-
/// local timestamps. When this cfg is not enabled, local timestamps cannot be recorded, and
146-
/// events will be logged without timestamps.
91+
/// Formats the current [`local time`] using [`chrono` crate].
14792
///
148-
/// See the <a href="https://docs.rs/time/0.3.4/time/#feature-flags"><code>time</code>
149-
/// documentation</a> for more details.
150-
/// </pre></div>
93+
/// To format the UTC time instead, use the [`UtcTime`]
94+
/// or the [`crate::time_crate::UtcTime`] type.
15195
///
152-
/// [local time]: time::OffsetDateTime::now_local
153-
/// [formatter]: time::formatting::Formattable
154-
/// [`time` crate]: time
155-
/// [UTC time]: time::OffsetDateTime::now_utc
156-
#[derive(Clone, Debug)]
157-
pub struct LocalTime<F = Vec<FormatItem<'static>>> {
158-
format: F,
96+
/// [`local time`]: tracing_subscriber::fmt::time::ChronoLocal
97+
/// [`chrono` crate]: chrono
98+
pub struct LocalTime {
99+
time: ChronoLocal,
159100
}
160101

161-
impl Default for LocalTime {
162-
fn default() -> Self {
163-
let format: Vec<FormatItem> = time::format_description::parse(
164-
"[month][day] [hour]:[minute]:[second].[subsecond digits:6]",
165-
)
166-
.expect("Unable to make time formatter");
167-
Self { format }
168-
}
169-
}
170-
171-
impl<F> FormatTime for LocalTime<F>
172-
where
173-
F: Formattable,
174-
{
175-
fn format_time(&self, writer: &mut Writer<'_>) -> fmt::Result {
176-
let now = OffsetDateTime::now_local().map_err(|_| fmt::Error)?;
177-
102+
impl FormatTime for LocalTime {
103+
fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
178104
#[cfg(feature = "ansi")]
179-
if writer.has_ansi_escapes() {
105+
if w.has_ansi_escapes() {
180106
let style = Style::new().dimmed();
181-
write!(writer, "{}", style.prefix())?;
182-
format_datetime(writer, now, &self.format)?;
183-
// necessary to provide space between the time and the PID
184-
write!(writer, "{}", style.suffix())?;
107+
write!(w, "{}", style.prefix())?;
108+
self.time.format_time(w)?;
109+
write!(w, "{}", style.suffix())?;
185110
return Ok(());
186111
}
187112

188-
format_datetime(writer, now, &self.format)
113+
self.time.format_time(w)
189114
}
190115
}
191116

192-
fn format_datetime(
193-
into: &mut Writer<'_>,
194-
now: OffsetDateTime,
195-
fmt: &impl Formattable,
196-
) -> fmt::Result {
197-
let mut into = WriteAdaptor::new(into);
198-
now.format_into(&mut into, fmt)
199-
.map_err(|_| fmt::Error)
200-
.map(|_| ())
117+
impl Default for LocalTime {
118+
fn default() -> Self {
119+
let fmt_string = String::from("%m%d %H:%M:%S%.6f");
120+
Self {
121+
time: ChronoLocal::new(fmt_string),
122+
}
123+
}
201124
}
202125

203126
pub(crate) struct FormatProcessData<'a> {

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,14 @@
9393
#[deny(rustdoc::broken_intra_doc_links)]
9494
mod format;
9595

96+
#[cfg(feature = "time")]
97+
pub mod time_crate;
98+
9699
#[cfg(feature = "ansi")]
97100
mod nu_ansi_term {
98101
pub use ::nu_ansi_term::*;
99102
}
103+
100104
#[cfg(not(feature = "ansi"))]
101105
mod nu_ansi_term {
102106
// Minimal API shim for nu_ansi_term to avoid a pile of #[cfg(feature = "ansi")] directives.

0 commit comments

Comments
 (0)