use std::{
sync::{Arc, Mutex},
thread::{self, JoinHandle},
};
pub enum LoggerMessage {
Message(String),
Complete,
Abort,
}
#[derive(Clone)]
pub struct Logger {
tx: crossbeam_channel::Sender<LoggerMessage>,
handle: Arc<Mutex<Option<JoinHandle<()>>>>,
}
impl Logger {
pub fn new(
channel: (
crossbeam_channel::Sender<LoggerMessage>,
crossbeam_channel::Receiver<LoggerMessage>,
),
) -> Logger {
let (tx, rx) = channel;
let handle = thread::spawn(move || {
loop {
let msg = if let Ok(msg) = rx.recv() {
match msg {
LoggerMessage::Message(msg) => msg,
LoggerMessage::Complete => continue,
LoggerMessage::Abort => break,
}
} else {
continue;
};
println!("{}", msg);
}
});
Logger {
tx,
handle: Arc::new(Mutex::new(Some(handle))),
}
}
pub fn new_without_logging_thread(sender: crossbeam_channel::Sender<LoggerMessage>) -> Logger {
Logger {
tx: sender,
handle: Arc::new(Mutex::new(None)),
}
}
pub fn log_message(&self, item: String) {
self.send_raw_message(LoggerMessage::Message(item));
}
pub fn send_raw_message(&self, msg: LoggerMessage) {
self.tx.send(msg).unwrap()
}
pub fn finish(self) -> std::thread::Result<()> {
self.tx.send(LoggerMessage::Abort).unwrap();
let mut lock = self.handle.lock().unwrap();
let handle = lock.take().unwrap();
handle.join()
}
}
impl log::Log for Logger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
if metadata.target() == "c2pdf" {
metadata.level() <= log::Level::Trace
} else {
false
}
}
fn log(&self, record: &log::Record) {
if self.enabled(record.metadata()) {
self.log_message(record.args().to_string());
}
}
fn flush(&self) {}
}
#[cfg(test)]
mod tests {
use log::info;
use super::*;
#[test]
fn it_works() {
let logger = Logger::new(crossbeam_channel::unbounded());
info!("Hello world!!");
_ = logger.finish();
}
}