wrote a globally useable logging implementation
This commit is contained in:
parent
a715d5abc4
commit
64f42d5edd
3 changed files with 151 additions and 0 deletions
|
@ -16,6 +16,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||
serde_json = "1.0"
|
||||
ringbuf = "0.2.2"
|
||||
triple_buffer = "5.0.6"
|
||||
lazy_static = "1.4.0"
|
||||
#hexotk = { optional = true, git = "https://github.com/WeirdConstructor/HexoTK.git" }
|
||||
#hexotk = { optional = true, path = "../hexotk" }
|
||||
hound = "3.4.0"
|
||||
|
|
|
@ -260,7 +260,9 @@ pub mod monitor;
|
|||
pub mod matrix_repr;
|
||||
pub mod sample_lib;
|
||||
mod util;
|
||||
pub mod log;
|
||||
|
||||
pub use log::log;
|
||||
pub use nodes::{new_node_engine, NodeConfigurator, NodeExecutor};
|
||||
pub use cell_dir::CellDir;
|
||||
pub use matrix::{Matrix, Cell};
|
||||
|
|
148
src/log.rs
Normal file
148
src/log.rs
Normal file
|
@ -0,0 +1,148 @@
|
|||
use std::cell::RefCell;
|
||||
use ringbuf::{RingBuffer, Producer, Consumer};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
lazy_static! {
|
||||
static ref LOG_RECV: Arc<Mutex<LogReceiver>> = {
|
||||
Arc::new(Mutex::new(LogReceiver::new()))
|
||||
};
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
pub static LOG: RefCell<Option<Log>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
pub fn retrieve_log_messages(msgs: &mut Vec<String>) {
|
||||
if let Ok(mut lr) = LOG_RECV.lock() {
|
||||
lr.retrieve_messages(msgs);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_thread_logger() {
|
||||
if let Ok(mut lr) = LOG_RECV.lock() {
|
||||
lr.spawn_global_logger();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log<F: Fn(&mut std::io::BufWriter<&mut [u8]>)>(f: F) {
|
||||
use std::borrow::BorrowMut;
|
||||
|
||||
LOG.with(|l| {
|
||||
let mut lh = l.borrow_mut();
|
||||
if let Some(lh) = (*(*lh.borrow_mut())).as_mut() {
|
||||
lh.log(f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const MAX_LOG_BUFFER : usize = 4096;
|
||||
|
||||
pub struct LogReceiver {
|
||||
consumers: Vec<Consumer<u8>>,
|
||||
}
|
||||
|
||||
impl LogReceiver {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
consumers: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn retrieve_messages(&mut self, out: &mut Vec<String>) {
|
||||
for consumer in self.consumers.iter_mut() {
|
||||
let mut buf = [0; 1024];
|
||||
let mut oi = 0;
|
||||
|
||||
while let Some(byte) = consumer.pop() {
|
||||
if oi >= buf.len() || byte == 0xFF {
|
||||
out.push(
|
||||
std::str::from_utf8(&buf[0..oi])
|
||||
.unwrap()
|
||||
.to_string());
|
||||
oi = 0;
|
||||
} else {
|
||||
buf[oi] = byte;
|
||||
oi += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn_logger(&mut self) -> Log {
|
||||
let rb = RingBuffer::new(MAX_LOG_BUFFER);
|
||||
let (producer, con) = rb.split();
|
||||
|
||||
self.consumers.push(con);
|
||||
Log {
|
||||
producer,
|
||||
buf: [0; 512],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn_global_logger(&mut self) {
|
||||
let hdl = self.spawn_logger();
|
||||
LOG.with(move |f| {
|
||||
*f.borrow_mut() = Some(hdl);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Log {
|
||||
producer: Producer<u8>,
|
||||
buf: [u8; 512],
|
||||
}
|
||||
|
||||
impl Log {
|
||||
pub fn log_buf(&mut self, data: &[u8]) {
|
||||
self.producer.push_slice(data);
|
||||
let _ = self.producer.push(0xFF);
|
||||
}
|
||||
|
||||
pub fn log<F: Fn(&mut std::io::BufWriter<&mut [u8]>)>(&mut self, f: F) {
|
||||
self.buf.fill(0xFF);
|
||||
|
||||
let len = {
|
||||
let mut bw = std::io::BufWriter::new(&mut self.buf[..]);
|
||||
f(&mut bw);
|
||||
bw.buffer().len()
|
||||
};
|
||||
|
||||
if len < (self.buf.len() - 1) {
|
||||
// include one 0xFF!
|
||||
self.producer.push_slice(&self.buf[0..len + 1]);
|
||||
} else {
|
||||
self.producer.push_slice(&self.buf[0..len]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn check_threaded_logger() {
|
||||
std::thread::spawn(|| {
|
||||
use std::io::Write;
|
||||
init_thread_logger();
|
||||
log(|w| write!(w, "Test Log{}!", 1).unwrap());
|
||||
log(|w| write!(w, "Test Log{}!", 2).unwrap());
|
||||
});
|
||||
|
||||
let mut msgs = vec![];
|
||||
for _ in 0..100 {
|
||||
std::thread::sleep(
|
||||
std::time::Duration::from_millis(100));
|
||||
|
||||
retrieve_log_messages(&mut msgs);
|
||||
|
||||
if msgs.len() > 1 {
|
||||
assert_eq!(msgs[0], "Test Log1!");
|
||||
assert_eq!(msgs[1], "Test Log2!");
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue