Replace pretty_env_logger with simplelog (#6274)

Fixes #5963

Signed-off-by: nibon7 <nibon7@163.com>
This commit is contained in:
nibon7
2022-08-10 00:44:37 +08:00
committed by GitHub
parent e10ef4aaae
commit fc8512be39
4 changed files with 138 additions and 139 deletions

View File

@ -1,118 +1,117 @@
use chrono::{DateTime, Local};
use core::fmt;
use log::Level;
use log::LevelFilter;
use log::{Level, LevelFilter, SetLoggerError};
use nu_protocol::ShellError;
use pretty_env_logger::env_logger::fmt::Color;
use pretty_env_logger::env_logger::Builder;
use std::io::Write;
use std::sync::atomic::{AtomicUsize, Ordering};
use simplelog::{
format_description, Color, ColorChoice, Config, ConfigBuilder, LevelPadding, TermLogger,
TerminalMode, WriteLogger,
};
pub fn logger(f: impl FnOnce(&mut Builder) -> Result<(), ShellError>) -> Result<(), ShellError> {
let mut builder = my_formatted_timed_builder();
f(&mut builder)?;
let _ = builder.try_init();
Ok(())
use std::{fs::File, path::Path, str::FromStr};
pub enum LogTarget {
Stdout,
Stderr,
Mixed,
File,
}
pub fn my_formatted_timed_builder() -> Builder {
let mut builder = Builder::new();
builder.format(|f, record| {
let target = record.target();
let max_width = max_target_width(target);
let mut style = f.style();
let level = colored_level(&mut style, record.level());
let mut style = f.style();
let target = style.set_bold(true).value(Padded {
value: target,
width: max_width,
});
let dt = match DateTime::parse_from_rfc3339(&f.timestamp_millis().to_string()) {
Ok(d) => d.with_timezone(&Local),
Err(_) => Local::now(),
};
let time = dt.format("%Y-%m-%d %I:%M:%S%.3f %p");
writeln!(f, "{}|{}|{}|{}", time, level, target, record.args(),)
});
builder
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 configure(level: &str, logger: &mut Builder) -> Result<(), ShellError> {
let level = match level {
"error" => LevelFilter::Error,
"warn" => LevelFilter::Warn,
"info" => LevelFilter::Info,
"debug" => LevelFilter::Debug,
"trace" => LevelFilter::Trace,
_ => LevelFilter::Warn,
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-{}.log", pid));
set_write_logger(level, config, &path)
}
_ => TermLogger::init(level, config, TerminalMode::Stderr, ColorChoice::Auto),
};
logger.filter_module("nu", level);
if let Ok(s) = std::env::var("RUST_LOG") {
logger.parse_filters(&s);
}
Ok(())
}
// pub fn trace_filters(app: &App, logger: &mut Builder) -> Result<(), ShellError> {
// if let Some(filters) = app.develop() {
// filters.into_iter().filter_map(Result::ok).for_each(|name| {
// logger.filter_module(&name, LevelFilter::Trace);
// })
// }
fn set_write_logger(level: LevelFilter, config: Config, path: &Path) -> Result<(), SetLoggerError> {
// Use TermLogger instead if WriteLogger is not available
match File::create(path) {
Ok(file) => WriteLogger::init(level, config, file),
Err(_) => {
let default_logger =
TermLogger::init(level, config, TerminalMode::Stderr, ColorChoice::Auto);
// Ok(())
// }
if default_logger.is_ok() {
log::warn!("failed to init WriteLogger, use TermLogger instead");
}
// pub fn debug_filters(app: &App, logger: &mut Builder) -> Result<(), ShellError> {
// if let Some(filters) = app.debug() {
// filters.into_iter().filter_map(Result::ok).for_each(|name| {
// logger.filter_module(&name, LevelFilter::Debug);
// })
// }
// Ok(())
// }
fn colored_level<'a>(
style: &'a mut pretty_env_logger::env_logger::fmt::Style,
level: Level,
) -> pretty_env_logger::env_logger::fmt::StyledValue<'a, &'static str> {
match level {
Level::Trace => style.set_color(Color::Magenta).value("TRACE"),
Level::Debug => style.set_color(Color::Blue).value("DEBUG"),
Level::Info => style.set_color(Color::Green).value("INFO "),
Level::Warn => style.set_color(Color::Yellow).value("WARN "),
Level::Error => style.set_color(Color::Red).value("ERROR"),
default_logger
}
}
}
static MAX_MODULE_WIDTH: AtomicUsize = AtomicUsize::new(0);
pub fn configure(
level: &str,
target: &str,
builder: &mut ConfigBuilder,
) -> (LevelFilter, LogTarget) {
let level = match Level::from_str(level) {
Ok(level) => level,
Err(_) => Level::Warn,
};
fn max_target_width(target: &str) -> usize {
let max_width = MAX_MODULE_WIDTH.load(Ordering::Relaxed);
if max_width < target.len() {
MAX_MODULE_WIDTH.store(target.len(), Ordering::Relaxed);
target.len()
} else {
max_width
// Add allowed module filter
builder.add_filter_allow_str("nu");
// 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::File) {
set_colored_level(builder, level);
}
(level.to_level_filter(), log_target)
}
struct Padded<T> {
value: T,
width: usize,
}
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,
};
impl<T: fmt::Display> fmt::Display for Padded<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{: <width$}", self.value, width = self.width)
}
builder.set_level_color(level, Some(color));
}

View File

@ -107,7 +107,7 @@ fn main() -> Result<()> {
"--config" | "--env-config" => args.next().map(|a| escape_quote_string(&a)),
#[cfg(feature = "plugin")]
"--plugin-config" => args.next().map(|a| escape_quote_string(&a)),
"--log-level" | "--testbin" | "--threads" | "-t" => args.next(),
"--log-level" | "--log-target" | "--testbin" | "--threads" | "-t" => args.next(),
_ => None,
};
@ -157,10 +157,12 @@ fn main() -> Result<()> {
.map(|level| level.item)
.unwrap_or_else(|| "info".to_string());
logger(|builder| {
configure(level.as_str(), builder)?;
Ok(())
})?;
let target = binary_args
.log_target
.map(|target| target.item)
.unwrap_or_else(|| "stderr".to_string());
logger(|builder| configure(level.as_str(), target.as_str(), builder))?;
info!("start logging {}:{}:{}", file!(), line!(), column!());
}
@ -435,6 +437,7 @@ fn parse_commandline_args(
let config_file: Option<Expression> = call.get_flag_expr("config");
let env_file: Option<Expression> = call.get_flag_expr("env-config");
let log_level: Option<Expression> = call.get_flag_expr("log-level");
let log_target: Option<Expression> = call.get_flag_expr("log-target");
let threads: Option<Value> = call.get_flag(engine_state, &mut stack, "threads")?;
let table_mode: Option<Value> =
call.get_flag(engine_state, &mut stack, "table-mode")?;
@ -464,6 +467,7 @@ fn parse_commandline_args(
let config_file = extract_contents(config_file)?;
let env_file = extract_contents(env_file)?;
let log_level = extract_contents(log_level)?;
let log_target = extract_contents(log_target)?;
let help = call.has_flag("help");
@ -496,6 +500,7 @@ fn parse_commandline_args(
config_file,
env_file,
log_level,
log_target,
perf,
threads,
table_mode,
@ -521,6 +526,7 @@ struct NushellCliArgs {
config_file: Option<Spanned<String>>,
env_file: Option<Spanned<String>>,
log_level: Option<Spanned<String>>,
log_target: Option<Spanned<String>>,
perf: bool,
threads: Option<Value>,
table_mode: Option<Value>,
@ -576,6 +582,12 @@ impl Command for Nu {
"log level for performance logs",
None,
)
.named(
"log-target",
SyntaxShape::String,
"set the target for the log to output. stdout, stderr(default), mixed or file",
None,
)
.named(
"threads",
SyntaxShape::Int,