1use anyhow::{Result, anyhow};
3use smallvec::SmallVec;
4use std::{
5 io::{BufRead, BufReader, Read},
6 process::Child,
7 sync::{Arc, RwLock},
8 thread,
9 thread::JoinHandle,
10};
11
12const DEFAULT_LOGS_LIMIT: usize = 256;
13const BLOCK_INITIALIZATION: &str = "Imported #1";
14
15#[derive(Default)]
17pub struct Log {
18 handle: Option<JoinHandle<()>>,
20 pub logs: Arc<RwLock<SmallVec<[String; DEFAULT_LOGS_LIMIT]>>>,
22}
23
24impl Log {
25 pub fn new(limit: Option<usize>) -> Self {
27 let mut this = Log::default();
28 if let Some(limit) = limit {
29 this.resize(limit);
30 }
31
32 this
33 }
34
35 pub fn resize(&mut self, limit: usize) {
37 if let Ok(mut logs) = self.logs.write() {
38 if limit > DEFAULT_LOGS_LIMIT {
39 logs.grow(limit)
40 } else {
41 logs.reserve(limit)
42 }
43 }
44 }
45
46 pub fn spawn(&mut self, ps: &mut Child) -> Result<()> {
48 let Some(stderr) = ps.stderr.take() else {
49 return Err(anyhow!("Not stderr found"));
50 };
51
52 let mut reader = BufReader::new(stderr);
54 for line in reader.by_ref().lines().map_while(|result| result.ok()) {
55 if line.contains(BLOCK_INITIALIZATION) {
56 break;
57 }
58 }
59
60 let logs = Arc::clone(&self.logs);
62 let handle = thread::spawn(move || {
63 for line in reader.lines().map_while(|result| result.ok()) {
64 if let Ok(mut logs) = logs.write() {
65 logs.push(line);
66 }
67 }
68 });
69
70 self.handle = Some(handle);
71 Ok(())
72 }
73}