Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make all dependencies optional #100

Merged
merged 11 commits into from Nov 3, 2018
8 changes: 4 additions & 4 deletions Cargo.toml
Expand Up @@ -19,9 +19,9 @@ status = "actively-developed"
[dependencies]
log = { version = "0.4", features = ["std"] }
regex = { version = "1", optional = true }
termcolor = "1"
humantime = "1.1"
atty = "0.2"
termcolor = { version = "1", optional = true }
humantime = { version = "1.1", optional = true }
atty = { version = "0.2", optional = true }

[[test]]
name = "regexp_filter"
Expand All @@ -32,4 +32,4 @@ name = "log-in-log"
harness = false

[features]
default = ["regex"]
default = ["termcolor", "atty", "humantime", "regex"]
2 changes: 2 additions & 0 deletions examples/custom_format.rs
Expand Up @@ -33,6 +33,8 @@ fn init_logger() {
let mut builder = Builder::from_env(env);

// Use a different format for writing log records
// The colors are only available when the `termcolor` dependency is (which it is by default)
#[cfg(feature = "termcolor")]
builder.format(|buf, record| {
let mut style = buf.style();
style.set_bg(fmt::Color::Yellow).set_bold(true);
Expand Down
34 changes: 34 additions & 0 deletions src/fmt/atty.rs
@@ -0,0 +1,34 @@
/*
This internal module contains the terminal detection implementation.

If the `atty` crate is available then we use it to detect whether we're
attached to a particular TTY. If the `atty` crate is not available we
assume we're not attached to anything. This effectively prevents styles
from being printed.
*/

#[cfg(feature = "atty")]
mod imp {
use atty;

pub(in ::fmt) fn is_stdout() -> bool {
atty::is(atty::Stream::Stdout)
}

pub(in ::fmt) fn is_stderr() -> bool {
atty::is(atty::Stream::Stderr)
}
}

#[cfg(not(feature = "atty"))]
mod imp {
pub(in ::fmt) fn is_stdout() -> bool {
false
}

pub(in ::fmt) fn is_stderr() -> bool {
false
}
}

pub(in ::fmt) use self::imp::*;
82 changes: 82 additions & 0 deletions src/fmt/humantime/extern_impl.rs
@@ -0,0 +1,82 @@
use std::fmt;
use std::time::SystemTime;

use humantime::{format_rfc3339_nanos, format_rfc3339_seconds};

use ::fmt::Formatter;

pub(in ::fmt) mod pub_use_in_super {
pub use super::*;
}

impl Formatter {
/// Get a [`Timestamp`] for the current date and time in UTC.
///
/// # Examples
///
/// Include the current timestamp with the log record:
///
/// ```
/// use std::io::Write;
///
/// let mut builder = env_logger::Builder::new();
///
/// builder.format(|buf, record| {
/// let ts = buf.timestamp();
///
/// writeln!(buf, "{}: {}: {}", ts, record.level(), record.args())
/// });
/// ```
///
/// [`Timestamp`]: struct.Timestamp.html
pub fn timestamp(&self) -> Timestamp {
Timestamp(SystemTime::now())
}

/// Get a [`PreciseTimestamp`] for the current date and time in UTC with nanos.
pub fn precise_timestamp(&self) -> PreciseTimestamp {
PreciseTimestamp(SystemTime::now())
}
}

/// An [RFC3339] formatted timestamp.
///
/// The timestamp implements [`Display`] and can be written to a [`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);

/// An [RFC3339] formatted timestamp with nanos
#[derive(Debug)]
pub struct PreciseTimestamp(SystemTime);

impl fmt::Debug for Timestamp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// A `Debug` wrapper for `Timestamp` that uses the `Display` implementation.
struct TimestampValue<'a>(&'a Timestamp);

impl<'a> fmt::Debug for TimestampValue<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}

f.debug_tuple("Timestamp")
.field(&TimestampValue(&self))
.finish()
}
}

impl fmt::Display for Timestamp {
fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result {
format_rfc3339_seconds(self.0).fmt(f)
}
}

impl fmt::Display for PreciseTimestamp {
fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result {
format_rfc3339_nanos(self.0).fmt(f)
}
}
11 changes: 11 additions & 0 deletions src/fmt/humantime/mod.rs
@@ -0,0 +1,11 @@
/*
This internal module contains the timestamp implementation.

Its public API is available when the `humantime` crate is available.
*/

#[cfg_attr(feature = "humantime", path = "extern_impl.rs")]
#[cfg_attr(not(feature = "humantime"), path = "shim_impl.rs")]
mod imp;

pub(in ::fmt) use self::imp::*;
7 changes: 7 additions & 0 deletions src/fmt/humantime/shim_impl.rs
@@ -0,0 +1,7 @@
/*
Timestamps aren't available when we don't have a `humantime` dependency.
*/

pub(in ::fmt) mod pub_use_in_super {

}