use anyhow::{anyhow, Result};
use smallvec::SmallVec;
use std::{
io::{BufRead, BufReader, Read},
process::Child,
sync::{Arc, RwLock},
thread,
thread::JoinHandle,
};
const DEFAULT_LOGS_LIMIT: usize = 256;
const BLOCK_INITIALIZATION: &str = "Imported #1";
#[derive(Default)]
pub struct Log {
handle: Option<JoinHandle<()>>,
pub logs: Arc<RwLock<SmallVec<[String; DEFAULT_LOGS_LIMIT]>>>,
}
impl Log {
pub fn new(limit: Option<usize>) -> Self {
let mut this = Log::default();
if let Some(limit) = limit {
this.resize(limit);
}
this
}
pub fn resize(&mut self, limit: usize) {
if let Ok(mut logs) = self.logs.write() {
if limit > DEFAULT_LOGS_LIMIT {
logs.grow(limit)
} else {
logs.reserve(limit)
}
}
}
pub fn spawn(&mut self, ps: &mut Child) -> Result<()> {
let Some(stderr) = ps.stderr.take() else {
return Err(anyhow!("Not stderr found"));
};
let mut reader = BufReader::new(stderr);
for line in reader.by_ref().lines().map_while(|result| result.ok()) {
if line.contains(BLOCK_INITIALIZATION) {
break;
}
}
let logs = Arc::clone(&self.logs);
let handle = thread::spawn(move || {
for line in reader.lines().map_while(|result| result.ok()) {
if let Ok(mut logs) = logs.write() {
logs.push(line);
}
}
});
self.handle = Some(handle);
Ok(())
}
}