60 lines
1.9 KiB
Rust
60 lines
1.9 KiB
Rust
use std::io::Write;
|
|
|
|
use log::{Level, LevelFilter, Log, Metadata, Record};
|
|
|
|
/// Reads one level name from `RUST_LOG` -- `off`, `error`, `warn`,
|
|
/// `info`, `debug`, `trace`, case-insensitively. **Not env_logger's
|
|
/// per-module filter syntax**: anything else is ignored and the default
|
|
/// stands, rather than being silently read as "off", since a typo that
|
|
/// turned logging off would be indistinguishable from a quiet program.
|
|
fn level_from_env(default: LevelFilter) -> LevelFilter {
|
|
match std::env::var("RUST_LOG") {
|
|
Ok(text) => text.trim().parse().unwrap_or(default),
|
|
Err(_) => default,
|
|
}
|
|
}
|
|
|
|
struct StderrLogger {
|
|
level: LevelFilter,
|
|
}
|
|
|
|
impl Log for StderrLogger {
|
|
fn enabled(&self, metadata: &Metadata) -> bool {
|
|
metadata.level() <= self.level
|
|
}
|
|
|
|
fn log(&self, record: &Record) {
|
|
if !self.enabled(record.metadata()) {
|
|
return;
|
|
}
|
|
// One write, not a `writeln!` per part: two threads logging at
|
|
// once interleave otherwise, and the frame and input traces are
|
|
// both written from whichever thread produced them.
|
|
let line = format!(
|
|
"{level:<5} {target}: {args}\n",
|
|
level = match record.level() {
|
|
Level::Error => "ERROR",
|
|
Level::Warn => "WARN",
|
|
Level::Info => "INFO",
|
|
Level::Debug => "DEBUG",
|
|
Level::Trace => "TRACE",
|
|
},
|
|
target = record.target(),
|
|
args = record.args(),
|
|
);
|
|
let _ = std::io::stderr().write_all(line.as_bytes());
|
|
}
|
|
|
|
fn flush(&self) {
|
|
let _ = std::io::stderr().flush();
|
|
}
|
|
}
|
|
|
|
pub fn install(default: LevelFilter) {
|
|
let level = level_from_env(default);
|
|
let logger = Box::leak(Box::new(StderrLogger { level }));
|
|
if log::set_logger(logger).is_ok() {
|
|
log::set_max_level(level);
|
|
}
|
|
}
|