use super::state::{STARTED, TERM_LOCK, is_paused, pause, resume};
use crate::style;
use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError};
use std::io::Write;
pub struct ProgressLogger {
level: LevelFilter,
target_filter: Option<String>,
}
impl ProgressLogger {
pub fn new(level: LevelFilter) -> Self {
Self {
level,
target_filter: None,
}
}
pub fn with_target(level: LevelFilter, target: impl Into<String>) -> Self {
Self {
level,
target_filter: Some(target.into()),
}
}
pub fn init(self) -> Result<(), SetLoggerError> {
let level = self.level;
log::set_boxed_logger(Box::new(self))?;
log::set_max_level(level);
Ok(())
}
fn format_message(&self, record: &Record) -> String {
let level_str = match record.level() {
Level::Error => style::ered("ERROR").to_string(),
Level::Warn => style::eyellow("WARN").to_string(),
Level::Info => style::ecyan("INFO").to_string(),
Level::Debug => style::edim("DEBUG").to_string(),
Level::Trace => style::edim("TRACE").to_string(),
};
format!("{} {}", level_str, record.args())
}
}
impl Log for ProgressLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
if metadata.level() > self.level {
return false;
}
if let Some(ref filter) = self.target_filter {
metadata.target().starts_with(filter)
} else {
true
}
}
fn log(&self, record: &Record) {
if !self.enabled(record.metadata()) {
return;
}
let message = self.format_message(record);
let was_paused = is_paused();
let did_pause = if !was_paused && *STARTED.lock().unwrap() {
pause();
true
} else {
false
};
{
let _guard = TERM_LOCK.lock().unwrap();
let mut stderr = std::io::stderr().lock();
let _ = writeln!(stderr, "{}", message);
}
if did_pause {
resume();
}
}
fn flush(&self) {
let _ = std::io::stderr().flush();
}
}
pub fn init_log_integration() {
ProgressLogger::new(LevelFilter::Info)
.init()
.expect("Failed to initialize logger - another logger may already be set");
}
pub fn init_log_integration_with_level(level: LevelFilter) {
ProgressLogger::new(level)
.init()
.expect("Failed to initialize logger - another logger may already be set");
}
pub fn try_init_log_integration() -> Result<(), SetLoggerError> {
ProgressLogger::new(LevelFilter::Info).init()
}
pub fn try_init_log_integration_with_level(level: LevelFilter) -> Result<(), SetLoggerError> {
ProgressLogger::new(level).init()
}