use std::{fs::File, sync::Once};
use chrono::Local;
use r3bl_simple_logger::*;
use time::UtcOffset;
use crate::*;
pub static mut LOG_LEVEL: LevelFilter = LevelFilter::Off;
pub static mut FILE_PATH: &str = "log.txt";
static mut FILE_LOGGER_INIT_OK: bool = false;
static FILE_LOGGER_INIT_FN: Once = Once::new();
const ENABLE_MULTITHREADED_LOG_WRITING: bool = false;
pub fn try_to_set_log_level(level: LevelFilter) -> CommonResult<String> {
unsafe {
match FILE_LOGGER_INIT_OK {
true => CommonError::new(
CommonErrorType::InvalidState,
"Logger already initialized, can't set log level",
),
false => {
LOG_LEVEL = level;
Ok(level.to_string())
}
}
}
}
pub fn try_to_set_log_file_path(path: &'static str) -> CommonResult<String> {
unsafe {
match FILE_LOGGER_INIT_OK {
true => CommonError::new(
CommonErrorType::InvalidState,
"Logger already initialized, can't set log file path",
),
false => {
FILE_PATH = path;
Ok(path.to_string())
}
}
}
}
pub fn log_info(arg: String) {
if init_file_logger_once().is_err() {
eprintln!(
"Error initializing file logger due to {}",
init_file_logger_once().unwrap_err()
);
} else {
match ENABLE_MULTITHREADED_LOG_WRITING {
true => {
std::thread::spawn(move || {
log::info!("{}", arg);
});
}
false => {
log::info!("{}", arg);
}
}
}
}
pub fn log_debug(arg: String) {
if init_file_logger_once().is_err() {
eprintln!(
"Error initializing file logger due to {}",
init_file_logger_once().unwrap_err()
);
} else {
match ENABLE_MULTITHREADED_LOG_WRITING {
true => {
std::thread::spawn(move || {
log::debug!("{}", arg);
});
}
false => {
log::debug!("{}", arg);
}
}
}
}
pub fn log_warn(arg: String) {
if init_file_logger_once().is_err() {
eprintln!(
"Error initializing file logger due to {}",
init_file_logger_once().unwrap_err()
);
} else {
match ENABLE_MULTITHREADED_LOG_WRITING {
true => {
std::thread::spawn(move || {
log::warn!("{}", arg);
});
}
false => {
log::warn!("{}", arg);
}
}
}
}
pub fn log_trace(arg: String) {
if init_file_logger_once().is_err() {
eprintln!(
"Error initializing file logger due to {}",
init_file_logger_once().unwrap_err()
);
} else {
match ENABLE_MULTITHREADED_LOG_WRITING {
true => {
std::thread::spawn(move || {
log::trace!("{}", arg);
});
}
false => {
log::trace!("{}", arg);
}
}
}
}
pub fn log_error(arg: String) {
if init_file_logger_once().is_err() {
eprintln!(
"Error initializing file logger due to {}",
init_file_logger_once().unwrap_err()
);
} else {
match ENABLE_MULTITHREADED_LOG_WRITING {
true => {
std::thread::spawn(move || {
log::error!("{}", arg);
});
}
false => {
log::error!("{}", arg);
}
}
}
}
fn init_file_logger_once() -> CommonResult<()> {
unsafe {
if LOG_LEVEL == LevelFilter::Off {
FILE_LOGGER_INIT_OK = true;
return Ok(());
}
}
FILE_LOGGER_INIT_FN.call_once(actually_init_file_logger);
unsafe {
return match FILE_LOGGER_INIT_OK {
true => Ok(()),
false => {
let msg = format!("Failed to initialize file logger {FILE_PATH}");
return CommonError::new(CommonErrorType::IOError, &msg);
}
};
}
fn actually_init_file_logger() {
unsafe {
let maybe_new_file = File::create(FILE_PATH);
if let Ok(new_file) = maybe_new_file {
let config = new_config();
let level = LOG_LEVEL;
let file_logger = WriteLogger::new(level, config, new_file);
let maybe_logger_init_err = CombinedLogger::init(vec![file_logger]);
if let Err(e) = maybe_logger_init_err {
eprintln!("Failed to initialize file logger {FILE_PATH} due to {e}");
} else {
FILE_LOGGER_INIT_OK = true
}
}
}
}
fn new_config() -> Config {
let mut builder = ConfigBuilder::new();
let offset_in_sec = Local::now().offset().local_minus_utc();
let utc_offset_result = UtcOffset::from_whole_seconds(offset_in_sec);
if let Ok(utc_offset) = utc_offset_result {
builder.set_time_offset(utc_offset);
}
builder.set_time_format_custom(format_description!(
"[hour repr:12]:[minute] [period]"
));
builder.build()
}
}