use std::sync::atomic::{AtomicU8, Ordering};
const LEVEL_TRACE: u8 = 5;
const LEVEL_DEBUG: u8 = 10;
const LEVEL_INFO: u8 = 20;
const LEVEL_WARNING: u8 = 30;
const LEVEL_ERROR: u8 = 40;
static LOG_LEVEL: AtomicU8 = AtomicU8::new(LEVEL_WARNING);
pub fn configure(default_level: u8) {
let level = match std::env::var("BIOLIB_LOG") {
Ok(val) if !val.is_empty() => match val.to_uppercase().as_str() {
"TRACE" => LEVEL_TRACE,
"DEBUG" => LEVEL_DEBUG,
"INFO" => LEVEL_INFO,
"WARNING" | "WARN" => LEVEL_WARNING,
"ERROR" => LEVEL_ERROR,
_ => {
eprintln!("Unknown log level \"{val}\", using default");
default_level
}
},
_ => default_level,
};
LOG_LEVEL.store(level, Ordering::Relaxed);
}
pub fn level() -> u8 {
LOG_LEVEL.load(Ordering::Relaxed)
}
pub fn is_enabled(msg_level: u8) -> bool {
msg_level >= LOG_LEVEL.load(Ordering::Relaxed)
}
fn timestamp() -> String {
let dur = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default();
let secs = dur.as_secs();
let days = secs / 86400;
let time_secs = secs % 86400;
let hours = time_secs / 3600;
let minutes = (time_secs % 3600) / 60;
let seconds = time_secs % 60;
let millis = dur.subsec_millis();
let mut y = 1970i64;
let mut remaining = days as i64;
loop {
let year_days = if is_leap(y) { 366 } else { 365 };
if remaining < year_days {
break;
}
remaining -= year_days;
y += 1;
}
let leap = is_leap(y);
let month_days: [i64; 12] = [
31,
if leap { 29 } else { 28 },
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
];
let mut m = 0;
for &md in &month_days {
if remaining < md {
break;
}
remaining -= md;
m += 1;
}
let d = remaining + 1;
format!(
"{y:04}-{:02}-{d:02} {hours:02}:{minutes:02}:{seconds:02},{millis:03}",
m + 1
)
}
fn is_leap(y: i64) -> bool {
y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)
}
fn log_msg(level_name: &str, level_val: u8, msg: &str) {
if is_enabled(level_val) {
eprintln!("{} | {} : {}", timestamp(), level_name, msg);
}
}
pub fn trace(msg: &str) {
log_msg("TRACE", LEVEL_TRACE, msg);
}
pub fn debug(msg: &str) {
log_msg("DEBUG", LEVEL_DEBUG, msg);
}
pub fn info(msg: &str) {
log_msg("INFO", LEVEL_INFO, msg);
}
pub fn warning(msg: &str) {
log_msg("WARNING", LEVEL_WARNING, msg);
}
pub fn error(msg: &str) {
log_msg("ERROR", LEVEL_ERROR, msg);
}