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
116
117
//!
//! A tiny, simple, thread-safe logging library.
//! No configuration options, take it or leave it.
//!
//! Writes log messages to `stdout`/`stderr`. The writes are thread-safe.
//! If an error occurs when writing to the log file it panics.
//!
//! Provided logging macros:
//!
//! - `log!()`
//! - `info!()`
//! - `warn!()`
//! - `err!()`
//!
//! Usage
//! -----
//!
//! ```rust
//! extern crate mhlog;
//!
//! use mhlog::{log,info,warn,err};
//!
//! log!("Log message. Prefixed with a timestamp. It's {}", "thread-safe!");
//! info!("Logging message prefixed by '<timestamp> Info:' ");
//! warn!("Warning message prefixed by '<timestamp> Warning:' ");
//! err!("Error message prefixed by '<timestamp> Error:' ");
//! ```

extern crate chrono;
#[cfg(feature = "colours")]
extern crate console;

#[cfg(feature = "colours")]
#[doc(hidden)]
pub use console::style;

use chrono::prelude::*;
use std::fmt::Display;

// -----------------------------------------------------------------------------
// Globals variables

// Time format in logging messages
const TIME_FMT: &'static str = "%F %T";

#[doc(hidden)]
pub fn _log(prefix: impl Display, msg: String, err: bool) {
    use std::io::{stderr, stdout, Write};

    let timestamp = Local::now().format(TIME_FMT).to_string();
    // Style the timestamp if colours enabled. Must be handlet differently
    // for stderr and stdout.
    #[cfg(feature = "colours")]
    let timestamp = match err || cfg!(not(feature = "log2stdout")) {
        true  => style(timestamp).for_stderr().cyan().dim(),
        false => style(timestamp).for_stdout().cyan().dim(),
    };

    let txt = format!("{} {}{}\n", timestamp, prefix, msg);

    // Unless log2stdout enabled, always print to stderr.
    if err || cfg!(not(feature = "log2stdout")) {
        let _ = stderr().lock().write_all(txt.as_bytes());
    } else {
        let _ = stdout().lock().write_all(txt.as_bytes());
    }
}

/*******************************************************************************
 *                                                                             *
 *  macros
 *                                                                             *
 *******************************************************************************/

/// Print a log message, prefixed by a timestamp.
#[macro_export]
macro_rules! log {
    ($($arg:tt)+) => (
        $crate::_log("", format!($($arg)+), false);
    )
}

/// Print an info log message, prefixed by a timestamp and _Info_.
#[macro_export]
macro_rules! info {
    ($($arg:tt)+) => ({
        #[cfg(not(feature = "colours"))]
        $crate::_log("Info: ", format!($($arg)+), false);
        #[cfg(feature = "colours")]
        match cfg!(feature = "log2stdout") {
            true  => $crate::_log($crate::style("Info: ").for_stdout().bold().green(), format!($($arg)+), false),
            false => $crate::_log($crate::style("Info: ").for_stderr().bold().green(), format!($($arg)+), false),
        }
    })
}

/// Print a warning log message, prefixed by a timestamp and _Warning_.
#[macro_export]
macro_rules! warn {
    ($($arg:tt)+) => (
        #[cfg(not(feature = "colours"))]
        $crate::_log("Warning: ", format!($($arg)+), true);
        #[cfg(feature = "colours")]
        $crate::_log($crate::style("Warning: ").for_stderr().bold().yellow(), format!($($arg)+), true);
    )
}

/// Print an error log message, prefixed by a timestamp and _Error_.
#[macro_export]
macro_rules! err {
    ($($arg:tt)+) => (
        #[cfg(not(feature = "colours"))]
        $crate::_log("Error: ", format!($($arg)+), true);
        #[cfg(feature = "colours")]
        $crate::_log($crate::style("Error: ").for_stderr().bold().red(), format!($($arg)+), true);
    )
}