Skip to content

Commit

Permalink
Merge pull request #140 from oherrala/timestamp-formats
Browse files Browse the repository at this point in the history
Add more timestamp precisions
  • Loading branch information
KodrAus committed Sep 13, 2019
2 parents 87616e5 + 95cd4ed commit 75911d7
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 43 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ members = [
log = { version = "0.4", features = ["std"] }
regex = { version = "1.0.3", optional = true }
termcolor = { version = "1.0.2", optional = true }
humantime = { version = "1.1", optional = true }
humantime = { version = "1.3", optional = true }
atty = { version = "0.2.5", optional = true }

[[test]]
Expand Down
67 changes: 60 additions & 7 deletions src/fmt/humantime/extern_impl.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::fmt;
use std::time::SystemTime;

use humantime::{format_rfc3339_nanos, format_rfc3339_seconds};
use humantime::{
format_rfc3339_micros, format_rfc3339_millis,
format_rfc3339_nanos, format_rfc3339_seconds,
};

use ::fmt::Formatter;
use ::fmt::{Formatter, TimestampPrecision};

pub(in ::fmt) mod glob {
pub use super::*;
Expand All @@ -30,10 +33,50 @@ impl Formatter {
///
/// [`Timestamp`]: struct.Timestamp.html
pub fn timestamp(&self) -> Timestamp {
Timestamp(SystemTime::now())
Timestamp {
time: SystemTime::now(),
precision: TimestampPrecision::Seconds,
}
}

/// Get a [`Timestamp`] for the current date and time in UTC with full
/// second precision.
pub fn timestamp_seconds(&self) -> Timestamp {
Timestamp {
time: SystemTime::now(),
precision: TimestampPrecision::Seconds,
}
}

/// Get a [`Timestamp`] for the current date and time in UTC with
/// millisecond precision.
pub fn timestamp_millis(&self) -> Timestamp {
Timestamp {
time: SystemTime::now(),
precision: TimestampPrecision::Millis,
}
}

/// Get a [`Timestamp`] for the current date and time in UTC with
/// microsecond precision.
pub fn timestamp_micros(&self) -> Timestamp {
Timestamp {
time: SystemTime::now(),
precision: TimestampPrecision::Micros,
}
}

/// Get a [`Timestamp`] for the current date and time in UTC with
/// nanosecond precision.
pub fn timestamp_nanos(&self) -> Timestamp {
Timestamp {
time: SystemTime::now(),
precision: TimestampPrecision::Nanos,
}
}

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

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

impl fmt::Display for Timestamp {
fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result {
format_rfc3339_seconds(self.0).fmt(f)
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let formatter = match self.precision {
TimestampPrecision::Seconds => format_rfc3339_seconds,
TimestampPrecision::Millis => format_rfc3339_millis,
TimestampPrecision::Micros => format_rfc3339_micros,
TimestampPrecision::Nanos => format_rfc3339_nanos,
};

formatter(self.time).fmt(f)
}
}

impl fmt::Display for PreciseTimestamp {
fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result {
format_rfc3339_nanos(self.0).fmt(f)
}
}
}
72 changes: 40 additions & 32 deletions src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,25 @@ impl fmt::Debug for Formatter {
}
}

/// Formatting precision of timestamps.
///
/// Seconds give precision of full seconds, milliseconds give thousands of a
/// second (3 decimal digits), microseconds are millionth of a second (6 decimal
/// digits) and nanoseconds are billionth of a second (9 decimal digits).
#[derive(Copy, Clone, Debug)]
pub enum TimestampPrecision {
/// Full second precision (0 decimal digits)
Seconds,
/// Millisecond precision (3 decimal digits)
Millis,
/// Microsecond precision (6 decimal digits)
Micros,
/// Nanosecond precision (9 decimal digits)
Nanos,
}

pub(crate) struct Builder {
pub default_format_timestamp: bool,
pub default_format_timestamp_nanos: bool,
pub default_format_timestamp: Option<TimestampPrecision>,
pub default_format_module_path: bool,
pub default_format_level: bool,
pub default_format_indent: Option<usize>,
Expand All @@ -126,8 +142,7 @@ pub(crate) struct Builder {
impl Default for Builder {
fn default() -> Self {
Builder {
default_format_timestamp: true,
default_format_timestamp_nanos: false,
default_format_timestamp: Some(TimestampPrecision::Seconds),
default_format_module_path: true,
default_format_level: true,
default_format_indent: Some(4),
Expand All @@ -139,7 +154,7 @@ impl Default for Builder {

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

/// The default format.
///
///
/// This format needs to work with any combination of crate features.
struct DefaultFormat<'a> {
timestamp: bool,
timestamp: Option<TimestampPrecision>,
module_path: bool,
level: bool,
timestamp_nanos: bool,
written_header_value: bool,
indent: Option<usize>,
buf: &'a mut Formatter,
Expand Down Expand Up @@ -251,22 +264,22 @@ impl<'a> DefaultFormat<'a> {
fn write_timestamp(&mut self) -> io::Result<()> {
#[cfg(feature = "humantime")]
{
if !self.timestamp {
return Ok(())
}

if self.timestamp_nanos {
let ts_nanos = self.buf.precise_timestamp();
self.write_header_value(ts_nanos)
} else {
let ts = self.buf.timestamp();
self.write_header_value(ts)
}
use fmt::TimestampPrecision::*;
let ts = match self.timestamp {
None => return Ok(()),
Some(Seconds) => self.buf.timestamp_seconds(),
Some(Millis) => self.buf.timestamp_millis(),
Some(Micros) => self.buf.timestamp_micros(),
Some(Nanos) => self.buf.timestamp_nanos(),
};

self.write_header_value(ts)
}
#[cfg(not(feature = "humantime"))]
{
// Trick the compiler to think we have used self.timestamp
// Workaround for "field is never used: `timestamp`" compiler nag.
let _ = self.timestamp;
let _ = self.timestamp_nanos;
Ok(())
}
}
Expand Down Expand Up @@ -294,7 +307,7 @@ impl<'a> DefaultFormat<'a> {

fn write_args(&mut self, record: &Record) -> io::Result<()> {
match self.indent {

// Fast path for no indentation
None => writeln!(self.buf, "{}", record.args()),

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

let written = write(DefaultFormat {
timestamp: false,
timestamp_nanos: false,
timestamp: None,
module_path: true,
level: true,
written_header_value: false,
Expand All @@ -397,8 +409,7 @@ mod tests {
let mut f = Formatter::new(&writer);

let written = write(DefaultFormat {
timestamp: false,
timestamp_nanos: false,
timestamp: None,
module_path: false,
level: false,
written_header_value: false,
Expand All @@ -418,8 +429,7 @@ mod tests {
let mut f = Formatter::new(&writer);

let written = write(DefaultFormat {
timestamp: false,
timestamp_nanos: false,
timestamp: None,
module_path: true,
level: true,
written_header_value: false,
Expand All @@ -439,8 +449,7 @@ mod tests {
let mut f = Formatter::new(&writer);

let written = write(DefaultFormat {
timestamp: false,
timestamp_nanos: false,
timestamp: None,
module_path: true,
level: true,
written_header_value: false,
Expand All @@ -460,8 +469,7 @@ mod tests {
let mut f = Formatter::new(&writer);

let written = write(DefaultFormat {
timestamp: false,
timestamp_nanos: false,
timestamp: None,
module_path: false,
level: false,
written_header_value: false,
Expand Down
24 changes: 21 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ use self::filter::Filter;
use self::fmt::Formatter;
use self::fmt::writer::{self, Writer};

pub use self::fmt::TimestampPrecision as Timestamp;

/// The default name for the environment variable to read filters from.
pub const DEFAULT_FILTER_ENV: &'static str = "RUST_LOG";

Expand Down Expand Up @@ -518,14 +520,24 @@ impl Builder {
}

/// Whether or not to write the timestamp in the default format.
#[deprecated = "Use format_timestamp() instead"]
pub fn default_format_timestamp(&mut self, write: bool) -> &mut Self {
self.format.default_format_timestamp = write;
if write {
self.format_timestamp(Some(Timestamp::Seconds));
} else {
self.format_timestamp(None);
}
self
}

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

Expand All @@ -536,6 +548,12 @@ impl Builder {
self
}

/// Configures if timestamp should be included and in what precision.
pub fn format_timestamp(&mut self, timestamp: Option<Timestamp>) -> &mut Self {
self.format.default_format_timestamp = timestamp;
self
}

/// Adds a directive to the filter for a specific module.
///
/// # Examples
Expand Down

0 comments on commit 75911d7

Please sign in to comment.