forked from nushell/nushell
-
Notifications
You must be signed in to change notification settings - Fork 0
/
logger.rs
138 lines (115 loc) · 3.7 KB
/
logger.rs
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use log::{Level, LevelFilter, SetLoggerError};
use nu_protocol::ShellError;
use simplelog::{
format_description, Color, ColorChoice, Config, ConfigBuilder, LevelPadding, TermLogger,
TerminalMode, WriteLogger,
};
use std::{fs::File, path::Path, str::FromStr};
pub enum LogTarget {
Stdout,
Stderr,
Mixed,
File,
}
impl From<&str> for LogTarget {
fn from(s: &str) -> Self {
match s {
"stdout" => Self::Stdout,
"mixed" => Self::Mixed,
"file" => Self::File,
_ => Self::Stderr,
}
}
}
pub fn logger(
f: impl FnOnce(&mut ConfigBuilder) -> (LevelFilter, LogTarget),
) -> Result<(), ShellError> {
let mut builder = ConfigBuilder::new();
let (level, target) = f(&mut builder);
let config = builder.build();
let _ = match target {
LogTarget::Stdout => {
TermLogger::init(level, config, TerminalMode::Stdout, ColorChoice::Auto)
}
LogTarget::Mixed => TermLogger::init(level, config, TerminalMode::Mixed, ColorChoice::Auto),
LogTarget::File => {
let pid = std::process::id();
let mut path = std::env::temp_dir();
path.push(format!("nu-{pid}.log"));
set_write_logger(level, config, &path)
}
_ => TermLogger::init(level, config, TerminalMode::Stderr, ColorChoice::Auto),
};
Ok(())
}
fn set_write_logger(level: LevelFilter, config: Config, path: &Path) -> Result<(), SetLoggerError> {
// Use TermLogger instead if WriteLogger is not available
if let Ok(file) = File::create(path) {
WriteLogger::init(level, config, file)
} else {
let default_logger =
TermLogger::init(level, config, TerminalMode::Stderr, ColorChoice::Auto);
if default_logger.is_ok() {
log::warn!("failed to init WriteLogger, use TermLogger instead");
}
default_logger
}
}
pub struct Filters {
pub include: Option<Vec<String>>,
pub exclude: Option<Vec<String>>,
}
pub fn configure(
level: &str,
target: &str,
filters: Filters,
builder: &mut ConfigBuilder,
) -> (LevelFilter, LogTarget) {
let level = match Level::from_str(level) {
Ok(level) => level,
Err(_) => Level::Warn,
};
// Add allowed module filter
if let Some(include) = filters.include {
for filter in include {
builder.add_filter_allow(filter);
}
} else {
builder.add_filter_allow_str("nu");
}
// Add ignored module filter
if let Some(exclude) = filters.exclude {
for filter in exclude {
builder.add_filter_ignore(filter);
}
}
// Set level padding
builder.set_level_padding(LevelPadding::Right);
// Custom time format
builder.set_time_format_custom(format_description!(
"[year]-[month]-[day] [hour repr:12]:[minute]:[second].[subsecond digits:3] [period]"
));
// Show module path
builder.set_target_level(LevelFilter::Error);
// Don't show thread id
builder.set_thread_level(LevelFilter::Off);
let log_target = LogTarget::from(target);
// Only TermLogger supports color output
if matches!(
log_target,
LogTarget::Stdout | LogTarget::Stderr | LogTarget::Mixed
) {
Level::iter().for_each(|level| set_colored_level(builder, level));
}
(level.to_level_filter(), log_target)
}
fn set_colored_level(builder: &mut ConfigBuilder, level: Level) {
let color = match level {
Level::Trace => Color::Magenta,
Level::Debug => Color::Blue,
Level::Info => Color::Green,
Level::Warn => Color::Yellow,
Level::Error => Color::Red,
};
builder.set_level_color(level, Some(color));
}