1use std::{
3 sync::{Arc, Mutex},
4 thread::{self, JoinHandle},
5};
6
7pub enum LoggerMessage {
11 Message(String),
13 Complete,
15 Abort,
17}
18
19#[derive(Clone)]
23pub struct Logger {
24 tx: crossbeam_channel::Sender<LoggerMessage>,
25 handle: Arc<Mutex<Option<JoinHandle<()>>>>,
26}
27
28impl Logger {
29 pub fn new(
31 channel: (
32 crossbeam_channel::Sender<LoggerMessage>,
33 crossbeam_channel::Receiver<LoggerMessage>,
34 ),
35 ) -> Logger {
36 let (tx, rx) = channel;
37 let handle = thread::spawn(move || {
38 loop {
39 let msg = if let Ok(msg) = rx.recv() {
40 match msg {
41 LoggerMessage::Message(msg) => msg,
42 LoggerMessage::Complete => continue,
43 LoggerMessage::Abort => break,
44 }
45 } else {
46 continue;
47 };
48 println!("{}", msg);
49 }
50 });
51 Logger {
52 tx,
53 handle: Arc::new(Mutex::new(Some(handle))),
54 }
55 }
56 pub fn new_without_logging_thread(sender: crossbeam_channel::Sender<LoggerMessage>) -> Logger {
58 Logger {
59 tx: sender,
60 handle: Arc::new(Mutex::new(None)),
61 }
62 }
63 pub fn log_message(&self, item: String) {
65 self.send_raw_message(LoggerMessage::Message(item));
66 }
67 pub fn send_raw_message(&self, msg: LoggerMessage) {
69 self.tx.send(msg).unwrap()
70 }
71 pub fn finish(self) -> std::thread::Result<()> {
73 self.tx.send(LoggerMessage::Abort).unwrap();
75 let mut lock = self.handle.lock().unwrap();
76 let handle = lock.take().unwrap();
77 handle.join()
78 }
79}
80impl log::Log for Logger {
81 fn enabled(&self, metadata: &log::Metadata) -> bool {
82 if metadata.target() == "c2pdf" {
83 metadata.level() <= log::Level::Trace
84 } else {
85 false
86 }
87 }
88 fn log(&self, record: &log::Record) {
89 if self.enabled(record.metadata()) {
90 self.log_message(record.args().to_string());
91 }
92 }
93
94 fn flush(&self) {}
95}
96#[cfg(test)]
97mod tests {
98 use log::info;
99
100 use super::*;
101 #[test]
102 fn it_works() {
103 let logger = Logger::new(crossbeam_channel::unbounded());
104 info!("Hello world!!");
105 _ = logger.finish();
106 }
107}