use super::LOG_TARGET;
use sp_core::{LogLevelFilter, RuntimeInterfaceLogLevel};
use sp_runtime_interface::{
pass_by::{PassAs, PassFatPointerAndRead, ReturnAs},
runtime_interface,
};
use std::cell::OnceCell;
thread_local! {
pub static RUNTIME_LOG: OnceCell<env_filter::Filter> = OnceCell::new();
}
pub fn init(arg: Option<String>) {
let filter_str = arg.unwrap_or_else(|| {
if let Ok(env) = std::env::var("RUNTIME_LOG") {
env
} else {
log::max_level().to_string()
}
});
let filter = env_filter::Builder::new()
.try_parse(&filter_str)
.expect("Invalid runtime log filter")
.build();
RUNTIME_LOG.with(|cell| {
cell.set(filter).expect("Can be set by host");
log::info!(target: LOG_TARGET, "Initialized runtime log filter to '{}'", filter_str);
});
}
#[runtime_interface]
pub trait Logging {
#[allow(dead_code)]
fn log(
level: PassAs<RuntimeInterfaceLogLevel, u8>,
target: PassFatPointerAndRead<&str>,
message: PassFatPointerAndRead<&[u8]>,
) {
let Ok(message) = core::str::from_utf8(message) else {
log::error!(target: LOG_TARGET, "Runtime tried to log invalid UTF-8 data");
return;
};
let level = log::Level::from(level);
let metadata = log::MetadataBuilder::new().level(level).target(target).build();
if RUNTIME_LOG.with(|filter| filter.get().expect("Must be set by host").enabled(&metadata))
{
log::log!(target: target, level, "{}", message);
}
}
#[allow(dead_code)]
fn max_level() -> ReturnAs<LogLevelFilter, u8> {
RUNTIME_LOG
.with(|filter| filter.get().expect("Must be set by host").filter())
.into()
}
}