Skip to content

Commit 75911d7

Browse files
authored
Merge pull request #140 from oherrala/timestamp-formats
Add more timestamp precisions
2 parents 87616e5 + 95cd4ed commit 75911d7

File tree

4 files changed

+122
-43
lines changed

4 files changed

+122
-43
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ members = [
2222
log = { version = "0.4", features = ["std"] }
2323
regex = { version = "1.0.3", optional = true }
2424
termcolor = { version = "1.0.2", optional = true }
25-
humantime = { version = "1.1", optional = true }
25+
humantime = { version = "1.3", optional = true }
2626
atty = { version = "0.2.5", optional = true }
2727

2828
[[test]]

src/fmt/humantime/extern_impl.rs

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
use std::fmt;
22
use std::time::SystemTime;
33

4-
use humantime::{format_rfc3339_nanos, format_rfc3339_seconds};
4+
use humantime::{
5+
format_rfc3339_micros, format_rfc3339_millis,
6+
format_rfc3339_nanos, format_rfc3339_seconds,
7+
};
58

6-
use ::fmt::Formatter;
9+
use ::fmt::{Formatter, TimestampPrecision};
710

811
pub(in ::fmt) mod glob {
912
pub use super::*;
@@ -30,10 +33,50 @@ impl Formatter {
3033
///
3134
/// [`Timestamp`]: struct.Timestamp.html
3235
pub fn timestamp(&self) -> Timestamp {
33-
Timestamp(SystemTime::now())
36+
Timestamp {
37+
time: SystemTime::now(),
38+
precision: TimestampPrecision::Seconds,
39+
}
40+
}
41+
42+
/// Get a [`Timestamp`] for the current date and time in UTC with full
43+
/// second precision.
44+
pub fn timestamp_seconds(&self) -> Timestamp {
45+
Timestamp {
46+
time: SystemTime::now(),
47+
precision: TimestampPrecision::Seconds,
48+
}
49+
}
50+
51+
/// Get a [`Timestamp`] for the current date and time in UTC with
52+
/// millisecond precision.
53+
pub fn timestamp_millis(&self) -> Timestamp {
54+
Timestamp {
55+
time: SystemTime::now(),
56+
precision: TimestampPrecision::Millis,
57+
}
58+
}
59+
60+
/// Get a [`Timestamp`] for the current date and time in UTC with
61+
/// microsecond precision.
62+
pub fn timestamp_micros(&self) -> Timestamp {
63+
Timestamp {
64+
time: SystemTime::now(),
65+
precision: TimestampPrecision::Micros,
66+
}
67+
}
68+
69+
/// Get a [`Timestamp`] for the current date and time in UTC with
70+
/// nanosecond precision.
71+
pub fn timestamp_nanos(&self) -> Timestamp {
72+
Timestamp {
73+
time: SystemTime::now(),
74+
precision: TimestampPrecision::Nanos,
75+
}
3476
}
3577

3678
/// Get a [`PreciseTimestamp`] for the current date and time in UTC with nanos.
79+
#[deprecated = "Use timestamp_nanos() instead"]
3780
pub fn precise_timestamp(&self) -> PreciseTimestamp {
3881
PreciseTimestamp(SystemTime::now())
3982
}
@@ -46,7 +89,10 @@ impl Formatter {
4689
/// [RFC3339]: https://www.ietf.org/rfc/rfc3339.txt
4790
/// [`Display`]: https://doc.rust-lang.org/stable/std/fmt/trait.Display.html
4891
/// [`Formatter`]: struct.Formatter.html
49-
pub struct Timestamp(SystemTime);
92+
pub struct Timestamp {
93+
time: SystemTime,
94+
precision: TimestampPrecision,
95+
}
5096

5197
/// An [RFC3339] formatted timestamp with nanos.
5298
///
@@ -72,13 +118,20 @@ impl fmt::Debug for Timestamp {
72118
}
73119

74120
impl fmt::Display for Timestamp {
75-
fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result {
76-
format_rfc3339_seconds(self.0).fmt(f)
121+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122+
let formatter = match self.precision {
123+
TimestampPrecision::Seconds => format_rfc3339_seconds,
124+
TimestampPrecision::Millis => format_rfc3339_millis,
125+
TimestampPrecision::Micros => format_rfc3339_micros,
126+
TimestampPrecision::Nanos => format_rfc3339_nanos,
127+
};
128+
129+
formatter(self.time).fmt(f)
77130
}
78131
}
79132

80133
impl fmt::Display for PreciseTimestamp {
81134
fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result {
82135
format_rfc3339_nanos(self.0).fmt(f)
83136
}
84-
}
137+
}

src/fmt/mod.rs

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,25 @@ impl fmt::Debug for Formatter {
112112
}
113113
}
114114

115+
/// Formatting precision of timestamps.
116+
///
117+
/// Seconds give precision of full seconds, milliseconds give thousands of a
118+
/// second (3 decimal digits), microseconds are millionth of a second (6 decimal
119+
/// digits) and nanoseconds are billionth of a second (9 decimal digits).
120+
#[derive(Copy, Clone, Debug)]
121+
pub enum TimestampPrecision {
122+
/// Full second precision (0 decimal digits)
123+
Seconds,
124+
/// Millisecond precision (3 decimal digits)
125+
Millis,
126+
/// Microsecond precision (6 decimal digits)
127+
Micros,
128+
/// Nanosecond precision (9 decimal digits)
129+
Nanos,
130+
}
131+
115132
pub(crate) struct Builder {
116-
pub default_format_timestamp: bool,
117-
pub default_format_timestamp_nanos: bool,
133+
pub default_format_timestamp: Option<TimestampPrecision>,
118134
pub default_format_module_path: bool,
119135
pub default_format_level: bool,
120136
pub default_format_indent: Option<usize>,
@@ -126,8 +142,7 @@ pub(crate) struct Builder {
126142
impl Default for Builder {
127143
fn default() -> Self {
128144
Builder {
129-
default_format_timestamp: true,
130-
default_format_timestamp_nanos: false,
145+
default_format_timestamp: Some(TimestampPrecision::Seconds),
131146
default_format_module_path: true,
132147
default_format_level: true,
133148
default_format_indent: Some(4),
@@ -139,7 +154,7 @@ impl Default for Builder {
139154

140155
impl Builder {
141156
/// Convert the format into a callable function.
142-
///
157+
///
143158
/// If the `custom_format` is `Some`, then any `default_format` switches are ignored.
144159
/// If the `custom_format` is `None`, then a default format is returned.
145160
/// Any `default_format` switches set to `false` won't be written by the format.
@@ -159,7 +174,6 @@ impl Builder {
159174
Box::new(move |buf, record| {
160175
let fmt = DefaultFormat {
161176
timestamp: built.default_format_timestamp,
162-
timestamp_nanos: built.default_format_timestamp_nanos,
163177
module_path: built.default_format_module_path,
164178
level: built.default_format_level,
165179
written_header_value: false,
@@ -179,13 +193,12 @@ type SubtleStyle = StyledValue<'static, &'static str>;
179193
type SubtleStyle = &'static str;
180194

181195
/// The default format.
182-
///
196+
///
183197
/// This format needs to work with any combination of crate features.
184198
struct DefaultFormat<'a> {
185-
timestamp: bool,
199+
timestamp: Option<TimestampPrecision>,
186200
module_path: bool,
187201
level: bool,
188-
timestamp_nanos: bool,
189202
written_header_value: bool,
190203
indent: Option<usize>,
191204
buf: &'a mut Formatter,
@@ -251,22 +264,22 @@ impl<'a> DefaultFormat<'a> {
251264
fn write_timestamp(&mut self) -> io::Result<()> {
252265
#[cfg(feature = "humantime")]
253266
{
254-
if !self.timestamp {
255-
return Ok(())
256-
}
257-
258-
if self.timestamp_nanos {
259-
let ts_nanos = self.buf.precise_timestamp();
260-
self.write_header_value(ts_nanos)
261-
} else {
262-
let ts = self.buf.timestamp();
263-
self.write_header_value(ts)
264-
}
267+
use fmt::TimestampPrecision::*;
268+
let ts = match self.timestamp {
269+
None => return Ok(()),
270+
Some(Seconds) => self.buf.timestamp_seconds(),
271+
Some(Millis) => self.buf.timestamp_millis(),
272+
Some(Micros) => self.buf.timestamp_micros(),
273+
Some(Nanos) => self.buf.timestamp_nanos(),
274+
};
275+
276+
self.write_header_value(ts)
265277
}
266278
#[cfg(not(feature = "humantime"))]
267279
{
280+
// Trick the compiler to think we have used self.timestamp
281+
// Workaround for "field is never used: `timestamp`" compiler nag.
268282
let _ = self.timestamp;
269-
let _ = self.timestamp_nanos;
270283
Ok(())
271284
}
272285
}
@@ -294,7 +307,7 @@ impl<'a> DefaultFormat<'a> {
294307

295308
fn write_args(&mut self, record: &Record) -> io::Result<()> {
296309
match self.indent {
297-
310+
298311
// Fast path for no indentation
299312
None => writeln!(self.buf, "{}", record.args()),
300313

@@ -376,8 +389,7 @@ mod tests {
376389
let mut f = Formatter::new(&writer);
377390

378391
let written = write(DefaultFormat {
379-
timestamp: false,
380-
timestamp_nanos: false,
392+
timestamp: None,
381393
module_path: true,
382394
level: true,
383395
written_header_value: false,
@@ -397,8 +409,7 @@ mod tests {
397409
let mut f = Formatter::new(&writer);
398410

399411
let written = write(DefaultFormat {
400-
timestamp: false,
401-
timestamp_nanos: false,
412+
timestamp: None,
402413
module_path: false,
403414
level: false,
404415
written_header_value: false,
@@ -418,8 +429,7 @@ mod tests {
418429
let mut f = Formatter::new(&writer);
419430

420431
let written = write(DefaultFormat {
421-
timestamp: false,
422-
timestamp_nanos: false,
432+
timestamp: None,
423433
module_path: true,
424434
level: true,
425435
written_header_value: false,
@@ -439,8 +449,7 @@ mod tests {
439449
let mut f = Formatter::new(&writer);
440450

441451
let written = write(DefaultFormat {
442-
timestamp: false,
443-
timestamp_nanos: false,
452+
timestamp: None,
444453
module_path: true,
445454
level: true,
446455
written_header_value: false,
@@ -460,8 +469,7 @@ mod tests {
460469
let mut f = Formatter::new(&writer);
461470

462471
let written = write(DefaultFormat {
463-
timestamp: false,
464-
timestamp_nanos: false,
472+
timestamp: None,
465473
module_path: false,
466474
level: false,
467475
written_header_value: false,

src/lib.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ use self::filter::Filter;
272272
use self::fmt::Formatter;
273273
use self::fmt::writer::{self, Writer};
274274

275+
pub use self::fmt::TimestampPrecision as Timestamp;
276+
275277
/// The default name for the environment variable to read filters from.
276278
pub const DEFAULT_FILTER_ENV: &'static str = "RUST_LOG";
277279

@@ -518,14 +520,24 @@ impl Builder {
518520
}
519521

520522
/// Whether or not to write the timestamp in the default format.
523+
#[deprecated = "Use format_timestamp() instead"]
521524
pub fn default_format_timestamp(&mut self, write: bool) -> &mut Self {
522-
self.format.default_format_timestamp = write;
525+
if write {
526+
self.format_timestamp(Some(Timestamp::Seconds));
527+
} else {
528+
self.format_timestamp(None);
529+
}
523530
self
524531
}
525532

526-
/// Whether or not to write the timestamp with nanos.
533+
/// Whether or not to write the timestamp with nanosecond precision.
534+
#[deprecated = "Use format_timestamp() instead"]
527535
pub fn default_format_timestamp_nanos(&mut self, write: bool) -> &mut Self {
528-
self.format.default_format_timestamp_nanos = write;
536+
// The old logic included two booleans: One for timestamp on/off and one
537+
// for nanosecond precision. Mimic it here for compatibility.
538+
if write && self.format.default_format_timestamp.is_some() {
539+
self.format.default_format_timestamp = Some(fmt::TimestampPrecision::Nanos);
540+
}
529541
self
530542
}
531543

@@ -536,6 +548,12 @@ impl Builder {
536548
self
537549
}
538550

551+
/// Configures if timestamp should be included and in what precision.
552+
pub fn format_timestamp(&mut self, timestamp: Option<Timestamp>) -> &mut Self {
553+
self.format.default_format_timestamp = timestamp;
554+
self
555+
}
556+
539557
/// Adds a directive to the filter for a specific module.
540558
///
541559
/// # Examples

0 commit comments

Comments
 (0)