sirlog/backend/
memory.rs

1use std::{collections::VecDeque, sync::Arc};
2
3use async_trait::async_trait;
4use tokio::sync::Mutex;
5
6use crate::{backend::Backend, Log};
7
8/// A memory-based log message backend. This is for use cases where you want to review the last X log messages.
9#[derive(Debug)]
10pub struct Memory {
11    /// The maximum number of entries to keep in memory
12    pub max_entries: usize,
13    /// The storage for the backend. Locking this will block log entries from arriving, so you should only acquire the mutex lock for short operations.
14    pub entries: Arc<Mutex<VecDeque<Log>>>,
15}
16
17impl Memory {
18    /// Create a new instance
19    #[must_use]
20    pub fn new(max_entries: usize) -> Self {
21        Self {
22            max_entries,
23            entries: Arc::default(),
24        }
25    }
26}
27
28#[async_trait]
29impl Backend for Memory {
30    async fn process_log(&mut self, log: &Log) -> anyhow::Result<()> {
31        let mut entries = self.entries.lock().await;
32
33        entries.push_front(log.clone());
34
35        while entries.len() > self.max_entries {
36            entries.pop_back();
37        }
38
39        Ok(())
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use std::time::Duration;
46
47    use crate::{Configuration, Manager};
48
49    use super::*;
50
51    #[tokio::test]
52    async fn send_test() -> anyhow::Result<()> {
53        let test_backend = Memory::new(2);
54        let entries = test_backend.entries.clone();
55        let sender = Manager::default()
56            .with_backend(test_backend)
57            .launch(|task| {
58                tokio::spawn(task);
59            });
60
61        Configuration::named("send_test", sender)
62            .run(async {
63                Log::info("A").submit();
64                Log::info("B").submit();
65                Log::info("A").submit();
66            })
67            .await;
68
69        tokio::time::sleep(Duration::from_millis(1)).await;
70        {
71            let entries = entries.lock().await;
72            assert_eq!(entries.len(), 2);
73            assert_eq!(entries[0].message, "A");
74            assert_eq!(entries[1].message, "B");
75        }
76
77        Ok(())
78    }
79}