use crate::Error;
use log::{Level, LevelFilter, Log, Metadata, Record};
#[derive(Clone, Copy, Debug, uniffi::Enum)]
pub enum LogLevel {
Error,
Warn,
Info,
Debug,
Trace,
}
impl From<Level> for LogLevel {
fn from(level: Level) -> Self {
match level {
Level::Error => LogLevel::Error,
Level::Warn => LogLevel::Warn,
Level::Info => LogLevel::Info,
Level::Debug => LogLevel::Debug,
Level::Trace => LogLevel::Trace,
}
}
}
impl From<LogLevel> for LevelFilter {
fn from(level: LogLevel) -> Self {
match level {
LogLevel::Error => LevelFilter::Error,
LogLevel::Warn => LevelFilter::Warn,
LogLevel::Info => LevelFilter::Info,
LogLevel::Debug => LevelFilter::Debug,
LogLevel::Trace => LevelFilter::Trace,
}
}
}
#[derive(Clone, Debug, uniffi::Record)]
pub struct LogEntry {
pub level: LogLevel,
pub message: String,
pub target: String,
pub file: Option<String>,
pub line: Option<u32>,
}
#[uniffi::export(callback_interface)]
pub trait LogListener: Send + Sync {
fn on_log(&self, entry: LogEntry);
}
struct SdkLogger {
listener: Box<dyn LogListener>,
}
impl Log for SdkLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= log::max_level()
}
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
self.listener.on_log(LogEntry {
level: record.level().into(),
message: record.args().to_string(),
target: record.target().to_string(),
file: record.file().map(|s| s.to_string()),
line: record.line(),
});
}
}
fn flush(&self) {}
}
pub fn set_logger(level: LogLevel, listener: Box<dyn LogListener>) -> Result<(), Error> {
let filter: LevelFilter = level.into();
log::set_boxed_logger(Box::new(SdkLogger { listener })).map_err(|e| {
Error::other(format!("a `log` logger is already installed: {e}"))
})?;
log::set_max_level(filter);
Ok(())
}
pub fn set_log_level(level: LogLevel) {
log::set_max_level(level.into());
}