Skip to main content

gear_node_wrapper/
log.rs

1// Copyright (C) Gear Technologies Inc.
2// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
3
4//! Log filter for the node
5use 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/// Log filter for the node
19#[derive(Default)]
20pub struct Log {
21    /// Join handle of logs
22    handle: Option<JoinHandle<()>>,
23    /// Filtered logs from the node output
24    pub logs: Arc<RwLock<SmallVec<[String; DEFAULT_LOGS_LIMIT]>>>,
25}
26
27impl Log {
28    /// New log with holding limits
29    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    /// Resize the limit logs that this instance holds
39    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    /// Spawn logs from the child process
50    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        // Blocking after initialization.
56        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        // Mapping logs to memory
64        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}