1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#![deny(missing_docs)]

//! A ridiculously minimal and good-looking logger.

extern crate ansi_term;
extern crate env_logger;
extern crate libc;
extern crate log;
extern crate time;

use ansi_term::Colour;
use ansi_term::Colour::*;
use env_logger::LogBuilder;
use log::LogLevel::*;
use log::LogLevelFilter;
use std::env;

const DETAILS_COLOR: Colour = Fixed(8);

/// Use the given string as the log level.
pub fn init<T: AsRef<str>>(level: Option<T>) {
    inner(level, false)
}

/// Use the value of the given environment variable as the log level.
pub fn init_from_env<T: AsRef<str>>(envar: T) {
    init(env::var(envar.as_ref()).ok())
}

/// Same as `init`, but hiding timestamps and target modules.
pub fn minimal<T: AsRef<str>>(level: Option<T>) {
    inner(level, true)
}

/// Same as `init_from_env`, but hiding timestamps and target modules.
pub fn minimal_from_env<T: AsRef<str>>(envar: T) {
    minimal(env::var(envar.as_ref()).ok())
}

fn inner<T: AsRef<str>>(level: Option<T>, minimal: bool) {
    let mut builder = LogBuilder::new();

    builder.filter(None, LogLevelFilter::Info);

    let (error, warn, info, debug, trace) =
        if ansi_supported() {(
               Red.paint("[ERROR]"),
            Yellow.paint("[WARN] "),
              Cyan.paint("[INFO] "),
             Green.paint("[DEBUG]"),
            Purple.paint("[TRACE]")
        )} else {(
            "[ERROR]".into(),
            "[WARN] ".into(),
            "[INFO] ".into(),
            "[DEBUG]".into(),
            "[TRACE]".into()
        )};

    builder.format(move |record| {
        if minimal {
            format!("{} {}",
                match record.level() {
                    Error => &error,
                    Warn  => &warn,
                    Info  => &info,
                    Debug => &debug,
                    Trace => &trace
                },

                record.args()
            )
        } else {
            format!("{}{}{} {} {}[{}]{} {}",
                DETAILS_COLOR.prefix(),
                time::now()
                    .strftime("%H:%M:%S")
                    .unwrap(),
                DETAILS_COLOR.suffix(),

                match record.level() {
                    Error => &error,
                    Warn  => &warn,
                    Info  => &info,
                    Debug => &debug,
                    Trace => &trace
                },

                DETAILS_COLOR.prefix(),
                record.target(),
                DETAILS_COLOR.suffix(),

                record.args()
            )
        }
    });

    if let Some(level) = level {
       builder.parse(level.as_ref());
    }

    builder.init().unwrap();
}

#[cfg(windows)] 
fn ansi_supported() -> bool {
    false
}

#[cfg(not(windows))]
fn ansi_supported() -> bool {
    0 != unsafe {
        libc::isatty(libc::STDERR_FILENO)
    }
}