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}