Skip to main content

hack_log/
lib.rs

1extern crate env_logger;
2#[macro_use]
3extern crate lazy_static;
4#[macro_use]
5extern crate log;
6extern crate clap;
7#[cfg(feature = "color")]
8extern crate ansi_term;
9
10#[cfg(feature = "color")]
11use ansi_term::Colour::{Blue, Green, Red, White, Yellow};
12use clap::ArgMatches;
13use env_logger::LogBuilder;
14use log::{LogLevel, LogLevelFilter, LogRecord, SetLoggerError};
15use std::sync::atomic::{AtomicUsize, Ordering};
16
17lazy_static! {
18    static ref HACKLOG_INDENT:AtomicUsize = {
19        AtomicUsize::new(0)
20    };
21}
22
23
24pub fn init(opts: Option<&ArgMatches>, level: Option<LogLevelFilter>) -> Result<(), SetLoggerError> {
25    let mut builder = LogBuilder::new();
26    init_format(&mut builder);
27    if let Some(opts) = opts {
28        init_clap(opts, &mut builder);
29    }
30    if let Some(level) = level {
31        builder.filter(None, level);
32    }
33    builder.init()
34}
35
36fn init_format(builder: &mut LogBuilder) {
37    #[cfg(not(feature = "color"))]
38    builder.format(|record: &LogRecord| {
39        format!("{:>ident$} {}",
40                match record.level() {
41                    LogLevel::Error => "[-]",
42                    LogLevel::Warn => "[*]",
43                    LogLevel::Info => "[+]",
44                    LogLevel::Debug => "[#]",
45                    LogLevel::Trace => "[%]",
46                },
47                record.args(),
48                ident=HACKLOG_INDENT.load(Ordering::SeqCst) * 4)
49    });
50    #[cfg(feature = "color")]
51    builder.format(|record: &LogRecord| {
52        format!("{holder:>ident$}{} {}",
53                match record.level() {
54                    LogLevel::Error => Red.paint("[-]"),
55                    LogLevel::Warn => Yellow.paint("[*]"),
56                    LogLevel::Info => Green.paint("[+]"),
57                    LogLevel::Debug => Blue.paint("[#]"),
58                    LogLevel::Trace => White.paint("[%]"),
59                },
60                record.args(),
61                holder="",
62                ident=HACKLOG_INDENT.load(Ordering::SeqCst) * 4)
63    });
64}
65
66fn init_clap(opts: &ArgMatches, builder: &mut LogBuilder) {
67    builder.filter(None,
68                   match opts.occurrences_of("verbose") {
69                       n if n >= 3 => LogLevelFilter::Trace,
70                       n if n == 2 => LogLevelFilter::Debug,
71                       n if n == 1 => LogLevelFilter::Info,
72                       _ => LogLevelFilter::Warn,
73                   });
74}
75
76fn indent() -> usize {
77    HACKLOG_INDENT.fetch_add(1, Ordering::SeqCst)
78}
79
80fn unindent() -> usize {
81    HACKLOG_INDENT.fetch_sub(1, Ordering::SeqCst)
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use log::LogLevelFilter;
88
89    #[test]
90    fn test() {
91        init(None, Some(LogLevelFilter::Trace)).unwrap();
92        error!("level 1 - error message 1");
93        indent();
94        error!("level 2 - error message 1");
95        indent();
96        error!("level 3 - error message 1");
97        unindent();
98        error!("level 2 - error message 2");
99        unindent();
100        error!("level 1 - error message 1");
101        warn!("a warning message");
102        info!("a info message");
103        debug!("a debug message");
104        trace!("a trace message");
105    }
106}