use std::sync::mpsc::SyncSender;
use log::{LevelFilter, Log, Metadata, Record};
pub const CAPTURE_LOG_CHANNEL_SIZE: usize = 128;
pub const CAPTURE_LOG_MAX_LEVEL: LevelFilter = LevelFilter::Debug;
pub struct CoreHandlerLogWrapper {
log: Box<dyn Log>,
core_handler_logs_tx: SyncSender<String>,
level: LevelFilter,
}
impl CoreHandlerLogWrapper {
pub fn new(
log: Box<dyn Log>,
core_handler_logs_tx: SyncSender<String>,
level: LevelFilter,
) -> Self {
Self {
log,
core_handler_logs_tx,
level,
}
}
}
impl Log for CoreHandlerLogWrapper {
fn enabled(&self, metadata: &Metadata) -> bool {
self.log.enabled(metadata)
}
fn log(&self, record: &Record) {
if record.level() <= CAPTURE_LOG_MAX_LEVEL {
let entry = build_log_string(record);
let _ = self.core_handler_logs_tx.try_send(entry);
}
if record.level() <= self.level {
self.log.log(record)
}
}
fn flush(&self) {
self.log.flush()
}
}
fn build_log_string(record: &Record) -> String {
match record.line() {
Some(line) => format!(
"{} {}:{} - {}",
record.level(),
record.target(),
line,
record.args()
),
None => format!("{} {} - {}", record.level(), record.target(), record.args()),
}
}
#[cfg(test)]
mod test {
use super::*;
use std::sync::mpsc::sync_channel;
use insta::assert_json_snapshot;
use log::Level;
#[test]
fn test_log_saving() {
let mut logger = stderrlog::new();
logger.module("memfaultd").verbosity(10);
let (capture_logs_tx, capture_logs_rx) = sync_channel(5);
let wrapper =
CoreHandlerLogWrapper::new(Box::new(logger), capture_logs_tx, CAPTURE_LOG_MAX_LEVEL);
let error_record = build_log_record(Level::Error);
let warn_record = build_log_record(Level::Warn);
let info_record = build_log_record(Level::Info);
let debug_record = build_log_record(Level::Debug);
let trace_record = build_log_record(Level::Trace);
wrapper.log(&error_record);
wrapper.log(&warn_record);
wrapper.log(&info_record);
wrapper.log(&debug_record);
wrapper.log(&trace_record);
let errors: Vec<String> = capture_logs_rx.try_iter().collect();
assert_json_snapshot!(errors);
}
fn build_log_record(level: Level) -> Record<'static> {
Record::builder()
.args(format_args!("Test message"))
.level(level)
.target("test")
.file(Some("log_wrapper.rs"))
.line(Some(71))
.module_path(Some("core_handler"))
.build()
}
}