Skip to main content

jam_tooling/
log.rs

1use env_logger::{
2	fmt::{Color, Formatter},
3	Builder as LogBuilder,
4};
5use log::LevelFilter;
6use std::io::{IsTerminal, Write};
7
8#[derive(Debug, PartialEq, Clone)]
9pub struct Config {
10	pub mode: Option<String>,
11	pub color: bool,
12	pub file: Option<String>,
13}
14
15impl Default for Config {
16	fn default() -> Self {
17		Config { mode: None, color: !cfg!(windows), file: None }
18	}
19}
20
21pub static LOG_ENABLED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
22
23pub fn setup_log(config: &Config) {
24	let mut levels = String::new();
25	let mut builder = LogBuilder::new();
26
27	builder.filter(None, LevelFilter::Info);
28
29	if let Ok(lvl) = std::env::var("RUST_LOG") {
30		levels.push_str(&lvl);
31		levels.push(',');
32		builder.parse_filters(&lvl);
33	}
34
35	if let Some(ref s) = config.mode {
36		levels.push_str(s);
37		builder.parse_filters(s);
38	}
39
40	let isatty = std::io::stderr().is_terminal();
41	let enable_color = config.color && isatty;
42
43	let format = move |buf: &mut Formatter, record: &log::Record| {
44		let mut bold = buf.style();
45		bold.set_bold(true);
46		let mut blue_bold = buf.style();
47		blue_bold.set_color(Color::Blue).set_bold(true);
48
49		let dt = chrono::Local::now();
50		let timestamp = dt.format("%Y-%m-%d %H:%M:%S%.6f");
51
52		let with_color = if enable_color && log::max_level() <= LevelFilter::Info {
53			format!("{} {}", bold.value(timestamp), record.args(),)
54		} else {
55			let id = std::thread::current().id();
56			format!(
57				"{} {:?} {} {}  {}",
58				bold.value(timestamp),
59				id,
60				record.level(),
61				record.target(),
62				record.args()
63			)
64		};
65
66		if !isatty && record.level() <= log::Level::Info && std::io::stdout().is_terminal() {
67			// duplicate INFO/WARN output to console
68			println!("{with_color}");
69		}
70
71		if LOG_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
72			writeln!(buf, "{with_color}")?;
73		}
74		Ok(())
75	};
76
77	builder.format(format);
78	let _ = builder.try_init();
79}