Skip to content

Commit eb0fd4d

Browse files
committed
Fully implement the transition
1 parent 23e5d83 commit eb0fd4d

File tree

3 files changed

+153
-65
lines changed

3 files changed

+153
-65
lines changed

src/fmt/chrono/extern_impl.rs

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use std::fmt::{self, write};
2-
use std::time::SystemTime;
1+
use std::fmt;
32

43
use chrono::{DateTime, SecondsFormat, Utc};
54

6-
use crate::fmt::{Formatter, TimestampPrecision};
5+
use crate::fmt::{Formatter, TimestampFormat, TimestampPrecision};
76

87
pub(in crate::fmt) mod glob {
98
pub use super::*;
@@ -32,57 +31,55 @@ impl Formatter {
3231
pub fn timestamp(&self) -> Timestamp {
3332
Timestamp {
3433
time: Utc::now(),
35-
precision: TimestampPrecision::Seconds,
34+
precision: Default::default(),
35+
format: Default::default(),
3636
}
3737
}
3838

39-
/// Get a [`Timestamp`] for the current date and time in UTC with full
40-
/// second precision.
41-
pub fn timestamp_seconds(&self) -> Timestamp {
42-
Timestamp {
43-
time: Utc::now(),
44-
precision: TimestampPrecision::Seconds,
45-
}
46-
}
47-
48-
/// Get a [`Timestamp`] for the current date and time in UTC with
49-
/// millisecond precision.
50-
pub fn timestamp_millis(&self) -> Timestamp {
51-
Timestamp {
52-
time: Utc::now(),
53-
precision: TimestampPrecision::Millis,
54-
}
55-
}
56-
57-
/// Get a [`Timestamp`] for the current date and time in UTC with
58-
/// microsecond precision.
59-
pub fn timestamp_micros(&self) -> Timestamp {
60-
Timestamp {
61-
time: Utc::now(),
62-
precision: TimestampPrecision::Micros,
63-
}
64-
}
65-
66-
/// Get a [`Timestamp`] for the current date and time in UTC with
67-
/// nanosecond precision.
68-
pub fn timestamp_nanos(&self) -> Timestamp {
39+
/// Get a [`Timestamp`] for the current date and time in UTC with a specified style and precision.
40+
///
41+
/// # Examples
42+
///
43+
/// Include the current timestamp, in a 12-hour format to second precision, with the log record:
44+
///
45+
/// ```
46+
/// use std::io::Write;
47+
/// use env_logger::fmt;
48+
///
49+
/// let mut builder = env_logger::Builder::new();
50+
///
51+
/// builder.format(|buf, record| {
52+
/// let ts = buf.timestamp_custom(fmt::TimestampPrecision::Seconds, fmt::TimestampFormat::Human12Hour);
53+
///
54+
/// writeln!(buf, "{}: {}: {}", ts, record.level(), record.args())
55+
/// });
56+
/// ```
57+
///
58+
/// [`Timestamp`]: struct.Timestamp.html
59+
pub fn timestamp_custom(
60+
&self,
61+
precision: TimestampPrecision,
62+
format: TimestampFormat,
63+
) -> Timestamp {
6964
Timestamp {
7065
time: Utc::now(),
71-
precision: TimestampPrecision::Nanos,
66+
precision,
67+
format,
7268
}
7369
}
7470
}
7571

76-
/// An [RFC3339] formatted timestamp.
72+
/// An formatted timestamp.
7773
///
78-
/// The timestamp implements [`Display`] and can be written to a [`Formatter`].
74+
/// The timestamp implements [`Display`] and can be written to a [`Formatter`]. This defaults to formatting with [RFC3339] with second precision.
7975
///
8076
/// [RFC3339]: https://www.ietf.org/rfc/rfc3339.txt
8177
/// [`Display`]: https://doc.rust-lang.org/stable/std/fmt/trait.Display.html
8278
/// [`Formatter`]: struct.Formatter.html
8379
pub struct Timestamp {
8480
time: DateTime<Utc>,
8581
precision: TimestampPrecision,
82+
format: TimestampFormat,
8683
}
8784

8885
impl fmt::Debug for Timestamp {
@@ -104,16 +101,33 @@ impl fmt::Debug for Timestamp {
104101

105102
impl fmt::Display for Timestamp {
106103
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107-
self.time
108-
.to_rfc3339_opts(
109-
match self.precision {
110-
TimestampPrecision::Seconds => SecondsFormat::Secs,
111-
TimestampPrecision::Millis => SecondsFormat::Millis,
112-
TimestampPrecision::Micros => SecondsFormat::Micros,
113-
TimestampPrecision::Nanos => SecondsFormat::Nanos,
114-
},
115-
true,
116-
)
117-
.fmt(f)
104+
match self.format {
105+
TimestampFormat::RFC3339 => self
106+
.time
107+
.to_rfc3339_opts(
108+
match self.precision {
109+
TimestampPrecision::Seconds => SecondsFormat::Secs,
110+
TimestampPrecision::Millis => SecondsFormat::Millis,
111+
TimestampPrecision::Micros => SecondsFormat::Micros,
112+
TimestampPrecision::Nanos => SecondsFormat::Nanos,
113+
},
114+
true,
115+
)
116+
.fmt(f),
117+
TimestampFormat::Human12Hour => {
118+
if self.precision != TimestampPrecision::Seconds {
119+
panic!("Sorry, currently with the new human timestamp formats, we only support second precision.");
120+
}
121+
122+
self.time.format("%v %p").fmt(f)
123+
}
124+
TimestampFormat::Human24Hour => {
125+
if self.precision != TimestampPrecision::Seconds {
126+
panic!("Sorry, currently with the new human timestamp formats, we only support second precision.");
127+
}
128+
129+
self.time.format("%v %X").fmt(f)
130+
}
131+
}
118132
}
119133
}

src/fmt/mod.rs

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub(crate) mod glob {
5454
/// Seconds give precision of full seconds, milliseconds give thousands of a
5555
/// second (3 decimal digits), microseconds are millionth of a second (6 decimal
5656
/// digits) and nanoseconds are billionth of a second (9 decimal digits).
57-
#[derive(Copy, Clone, Debug)]
57+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
5858
pub enum TimestampPrecision {
5959
/// Full second precision (0 decimal digits)
6060
Seconds,
@@ -73,6 +73,52 @@ impl Default for TimestampPrecision {
7373
}
7474
}
7575

76+
/// Standard used for formatting of timestamps.
77+
///
78+
/// RFC339 is the default and is a widely used internet standard, however it is not particularly human-readable.
79+
/// Currently, we also support human-readable formats with either a 12 or 24 hour clock. Note that this currently only works with `TimestampPrecision::Seconds`.
80+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
81+
pub enum TimestampFormat {
82+
/// Full RFC3339 conformance
83+
RFC3339,
84+
/// A human-readable standard of the form "YYYY:MM:DD HH:MM:SS AM/PM".
85+
Human12Hour,
86+
/// A human-readable standard of the form "YYYY:MM:DD HH:MM:SS"
87+
Human24Hour,
88+
}
89+
90+
/// The default timestamp style is the RFC3339 standard.
91+
impl Default for TimestampFormat {
92+
fn default() -> Self {
93+
TimestampFormat::RFC3339
94+
}
95+
}
96+
97+
/// A styled timestamp, with precision and formatting.
98+
///
99+
/// Defaults to `TimestampFormat::RFC3339` and `TimestampPrecision::Seconds`.
100+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
101+
pub struct TimestampStyle {
102+
/// The format used for this style.
103+
///
104+
/// Determines how the timestamp is displayed. E.G. HH:MM:SS or YY:MM:DD
105+
pub format: TimestampFormat,
106+
107+
/// The precision used for this style.
108+
///
109+
/// Determines how accurate the displayed timestamp is.
110+
pub precision: TimestampPrecision,
111+
}
112+
113+
impl TimestampStyle {
114+
/// Create a new `TimestampStyle` from a format and precision.
115+
///
116+
/// Rust's constructors can also be used instead of this method.
117+
pub fn new(format: TimestampFormat, precision: TimestampPrecision) -> Self {
118+
Self { format, precision }
119+
}
120+
}
121+
76122
/// A formatter to write logs into.
77123
///
78124
/// `Formatter` implements the standard [`Write`] trait for writing log records.
@@ -139,7 +185,7 @@ impl fmt::Debug for Formatter {
139185
pub(crate) type FormatFn = Box<dyn Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send>;
140186

141187
pub(crate) struct Builder {
142-
pub format_timestamp: Option<TimestampPrecision>,
188+
pub format_timestamp: Option<TimestampStyle>,
143189
pub format_module_path: bool,
144190
pub format_target: bool,
145191
pub format_level: bool,
@@ -211,7 +257,7 @@ type SubtleStyle = &'static str;
211257
///
212258
/// This format needs to work with any combination of crate features.
213259
struct DefaultFormat<'a> {
214-
timestamp: Option<TimestampPrecision>,
260+
timestamp: Option<TimestampStyle>,
215261
module_path: bool,
216262
target: bool,
217263
level: bool,
@@ -284,13 +330,12 @@ impl<'a> DefaultFormat<'a> {
284330
fn write_timestamp(&mut self) -> io::Result<()> {
285331
#[cfg(feature = "chrono")]
286332
{
287-
use self::TimestampPrecision::*;
288-
let ts = match self.timestamp {
289-
None => return Ok(()),
290-
Some(Seconds) => self.buf.timestamp_seconds(),
291-
Some(Millis) => self.buf.timestamp_millis(),
292-
Some(Micros) => self.buf.timestamp_micros(),
293-
Some(Nanos) => self.buf.timestamp_nanos(),
333+
// Make sure that timestamp is defined, otherwise omit writing the timestamp.
334+
let ts = if let Some(timestamp) = self.timestamp {
335+
self.buf
336+
.timestamp_custom(timestamp.precision, timestamp.format)
337+
} else {
338+
return Ok(());
294339
};
295340

296341
self.write_header_value(ts)

src/lib.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@
286286

287287
use std::{borrow::Cow, cell::RefCell, env, io};
288288

289+
use fmt::TimestampFormat;
289290
use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};
290291

291292
pub mod filter;
@@ -617,30 +618,58 @@ impl Builder {
617618
self
618619
}
619620

620-
/// Configures if timestamp should be included and in what precision.
621-
pub fn format_timestamp(&mut self, timestamp: Option<fmt::TimestampPrecision>) -> &mut Self {
622-
self.format.format_timestamp = timestamp;
621+
/// Configures if timestamp should be included and in what precision and style.
622+
pub fn format_timestamp(&mut self, style: Option<fmt::TimestampStyle>) -> &mut Self {
623+
self.format.format_timestamp = style;
623624
self
624625
}
625626

626627
/// Configures the timestamp to use second precision.
627628
pub fn format_timestamp_secs(&mut self) -> &mut Self {
628-
self.format_timestamp(Some(fmt::TimestampPrecision::Seconds))
629+
self.format_timestamp(Some(fmt::TimestampStyle::new(
630+
TimestampFormat::default(),
631+
TimestampPrecision::Seconds,
632+
)))
629633
}
630634

631635
/// Configures the timestamp to use millisecond precision.
632636
pub fn format_timestamp_millis(&mut self) -> &mut Self {
633-
self.format_timestamp(Some(fmt::TimestampPrecision::Millis))
637+
self.format_timestamp(Some(fmt::TimestampStyle::new(
638+
TimestampFormat::default(),
639+
TimestampPrecision::Millis,
640+
)))
634641
}
635642

636643
/// Configures the timestamp to use microsecond precision.
637644
pub fn format_timestamp_micros(&mut self) -> &mut Self {
638-
self.format_timestamp(Some(fmt::TimestampPrecision::Micros))
645+
self.format_timestamp(Some(fmt::TimestampStyle::new(
646+
TimestampFormat::default(),
647+
TimestampPrecision::Micros,
648+
)))
639649
}
640650

641651
/// Configures the timestamp to use nanosecond precision.
642652
pub fn format_timestamp_nanos(&mut self) -> &mut Self {
643-
self.format_timestamp(Some(fmt::TimestampPrecision::Nanos))
653+
self.format_timestamp(Some(fmt::TimestampStyle::new(
654+
TimestampFormat::default(),
655+
TimestampPrecision::Nanos,
656+
)))
657+
}
658+
659+
/// Configures the timestamp to use second precision, formatted as a 12-hour clock.
660+
pub fn format_timestamp_12hour(&mut self) -> &mut Self {
661+
self.format_timestamp(Some(fmt::TimestampStyle::new(
662+
TimestampFormat::Human12Hour,
663+
TimestampPrecision::Seconds,
664+
)))
665+
}
666+
667+
/// Configures the timestamp to use second precision, formatted as a 24-hour clock.
668+
pub fn format_timestamp_24hour(&mut self) -> &mut Self {
669+
self.format_timestamp(Some(fmt::TimestampStyle::new(
670+
TimestampFormat::Human24Hour,
671+
TimestampPrecision::Seconds,
672+
)))
644673
}
645674

646675
/// Configures the end of line suffix.

0 commit comments

Comments
 (0)