#![cfg_attr(docsrs, feature(doc_cfg))]
use log::Metadata;
use log::Record;
use logforth_core::Logger;
use logforth_core::default_logger;
use logforth_core::kv::Key;
use logforth_core::kv::Value;
use logforth_core::record::FilterCriteria;
fn level_to_level(level: log::Level) -> logforth_core::record::Level {
match level {
log::Level::Error => logforth_core::record::Level::Error,
log::Level::Warn => logforth_core::record::Level::Warn,
log::Level::Info => logforth_core::record::Level::Info,
log::Level::Debug => logforth_core::record::Level::Debug,
log::Level::Trace => logforth_core::record::Level::Trace,
}
}
struct LogCrateLogger(());
impl log::Log for LogCrateLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
forward_enabled(default_logger(), metadata)
}
fn log(&self, record: &Record) {
forward_log(default_logger(), record);
}
fn flush(&self) {
default_logger().flush();
}
}
pub struct LogProxy<'a>(&'a Logger);
impl<'a> LogProxy<'a> {
pub fn new(logger: &'a Logger) -> Self {
Self(logger)
}
}
impl<'a> log::Log for LogProxy<'a> {
fn enabled(&self, metadata: &Metadata) -> bool {
forward_enabled(self.0, metadata)
}
fn log(&self, record: &Record) {
forward_log(self.0, record);
}
fn flush(&self) {
self.0.flush();
}
}
pub struct OwnedLogProxy(Logger);
impl OwnedLogProxy {
pub fn new(logger: Logger) -> Self {
Self(logger)
}
}
impl log::Log for OwnedLogProxy {
fn enabled(&self, metadata: &Metadata) -> bool {
forward_enabled(&self.0, metadata)
}
fn log(&self, record: &Record) {
forward_log(&self.0, record);
}
fn flush(&self) {
self.0.flush();
}
}
fn forward_enabled(logger: &Logger, metadata: &Metadata) -> bool {
let criteria = FilterCriteria::builder()
.target(metadata.target())
.level(level_to_level(metadata.level()))
.build();
Logger::enabled(logger, &criteria)
}
fn forward_log(logger: &Logger, record: &Record) {
if !forward_enabled(logger, record.metadata()) {
return;
}
let mut builder = logforth_core::record::Record::builder()
.level(level_to_level(record.level()))
.target(record.target())
.line(record.line());
builder = if let Some(module_path) = record.module_path_static() {
builder.module_path_static(module_path)
} else {
builder.module_path(record.module_path())
};
builder = if let Some(file) = record.file_static() {
builder.file_static(file)
} else {
builder.file(record.file())
};
builder = if let Some(payload) = record.args().as_str() {
builder.payload(payload)
} else {
builder.payload(record.args().to_string())
};
let mut kvs = Vec::new();
struct KeyValueVisitor<'a, 'b> {
kvs: &'b mut Vec<(log::kv::Key<'a>, log::kv::Value<'a>)>,
}
impl<'a, 'b> log::kv::VisitSource<'a> for KeyValueVisitor<'a, 'b> {
fn visit_pair(
&mut self,
key: log::kv::Key<'a>,
value: log::kv::Value<'a>,
) -> Result<(), log::kv::Error> {
self.kvs.push((key, value));
Ok(())
}
}
let mut visitor = KeyValueVisitor { kvs: &mut kvs };
record.key_values().visit(&mut visitor).unwrap();
let mut new_kvs = Vec::with_capacity(kvs.len());
for (k, v) in kvs.iter() {
new_kvs.push((Key::new_ref(k.as_str()), Value::from_sval2(v)));
}
builder = builder.key_values(new_kvs.as_slice());
Logger::log(logger, &builder.build());
}
pub fn try_setup() -> Result<(), log::SetLoggerError> {
static LOGGER: LogCrateLogger = LogCrateLogger(());
log::set_logger(&LOGGER)?;
log::set_max_level(log::LevelFilter::Trace);
Ok(())
}
pub fn setup() {
try_setup().expect(
"logforth_bridge_log::setup must be called before the log crate global logger initialized",
)
}