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
use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError};
use chrono::{Local, Utc};
use std::path::Path;
use ansi_term::Color;
pub enum Timezone {
None,
Utc,
Local,
}
static LOG_LEVEL_NAMES: [&str; 6] = ["N/A", "E", "W", "I", "D", "T"];
fn level_to_str(l: &Level) -> &'static str {
LOG_LEVEL_NAMES[*l as usize]
}
static DEFAULT_TIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S";
pub struct XLog {
level: LevelFilter,
timezone: Timezone,
colored: bool,
}
impl XLog {
#[must_use = "You must call init() to begin logging"]
pub fn new() -> XLog {
XLog {
level: LevelFilter::Trace,
timezone: Timezone::Local,
colored: true,
}
}
pub fn with_level(mut self, level: LevelFilter) -> XLog {
self.level = level;
self
}
pub fn with_timezone(mut self, timezone: Timezone) -> XLog {
self.timezone = timezone;
self
}
pub fn with_color(mut self, colored: bool) -> XLog {
self.colored = colored;
self
}
pub fn init(self) -> Result<(), SetLoggerError> {
log::set_max_level(log::STATIC_MAX_LEVEL);
log::set_boxed_logger(Box::new(self))?;
Ok(())
}
}
impl Default for XLog {
fn default() -> Self {
XLog::new()
}
}
impl Log for XLog {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level().to_level_filter() <= self.level
}
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
let timestamp = {
match self.timezone{
Timezone::None => "".to_string(),
Timezone::Local => format!("{} ", Local::now().format(DEFAULT_TIME_FORMAT)),
Timezone::Utc => format!("{} ", Utc::now().format(DEFAULT_TIME_FORMAT)),
}
};
let path = Path::new(record.file().unwrap_or("???"));
let pathname = path.file_stem().unwrap().to_owned().into_string().unwrap();
let mut pathname = format!("{}:{}", pathname, record.line().unwrap_or(0));
let level_string = level_to_str(&record.level());
let mut color_msg = format!("[{}]: {}", level_string, record.args());
if self.colored {
color_msg = match record.level() {
Level::Error => Color::Red.paint(color_msg).to_string(),
Level::Warn => Color::Yellow.paint(color_msg).to_string(),
Level::Info => Color::Green.paint(color_msg).to_string(),
Level::Debug => Color::Blue.paint(color_msg).to_string(),
Level::Trace => Color::White.paint(color_msg).to_string(),
};
pathname = Color::Blue.paint(pathname).to_string();
}
let message = format!("{}{} {}", timestamp, pathname, color_msg);
#[cfg(not(feature = "stderr"))]
println!("{}", message);
#[cfg(feature = "stderr")]
eprintln!("{}", message);
}
}
fn flush(&self) {}
}