use kameleoon_core::logging::{DefaultLogger, KameleoonLogger, LogLevel, Logger};
use rustler::{types::LocalPid, Atom, Error as NifError, NifResult};
use crate::client_ex::ok;
rustler::atoms! {
kameleoon_log,
none,
error,
warning,
info,
debug,
}
struct LoggerEx {
owner: LocalPid,
}
impl Logger for LoggerEx {
fn log(&self, log_level: LogLevel, message: &str) {
send_log(self.owner, log_level, message.to_owned());
}
}
#[rustler::nif]
fn logger_set_handler(owner: Option<LocalPid>) -> Atom {
match owner {
Some(owner) => KameleoonLogger::set_logger(Box::new(LoggerEx { owner })),
None => KameleoonLogger::set_logger(Box::new(DefaultLogger {})),
}
ok()
}
#[rustler::nif]
fn logger_set_log_level(level: u8) -> NifResult<Atom> {
let level = decode_log_level(level)?;
KameleoonLogger::set_log_level(level);
Ok(ok())
}
fn decode_log_level(level: u8) -> NifResult<LogLevel> {
if level <= LogLevel::Debug as u8 {
Ok(LogLevel::from(level))
} else {
Err(NifError::BadArg)
}
}
fn send_log(owner: LocalPid, log_level: LogLevel, message: String) {
let send = move || {
let mut env = rustler::OwnedEnv::new();
let _ = env.send_and_clear(&owner, |_env| (kameleoon_log(), encode_log_level(log_level), message));
};
if rustler::thread::is_scheduler_thread() {
// Prefer spawning on the existing Tokio runtime to avoid new thread overhead.
// Fall back to a plain thread only if no runtime is available.
match tokio::runtime::Handle::try_current() {
Ok(handle) => {
handle.spawn(async move {
send();
});
}
Err(_) => {
std::thread::spawn(send);
}
}
} else {
send();
}
}
fn encode_log_level(log_level: LogLevel) -> Atom {
match log_level {
LogLevel::None => none(),
LogLevel::Error => error(),
LogLevel::Warning => warning(),
LogLevel::Info => info(),
LogLevel::Debug => debug(),
}
}