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