log_analyzer/stores/
log_store.rs1use log_source::source::log_source::LogSource;
2use parking_lot::RwLock;
3use rustc_hash::FxHashMap as HashMap;
4use std::{iter::Iterator, ops::Range, sync::Arc};
5
6pub trait LogStore {
10 fn add_log(
12 &self,
13 log_id: &str,
14 log_source: Arc<Box<dyn LogSource + Send + Sync>>,
15 format: Option<&String>,
16 enabled: bool,
17 );
18 fn add_line(&self, log_id: &str, line: &str);
20 fn add_lines(&self, log_id: &str, lines: &[String]) -> Range<usize>;
22 fn get_format(&self, log_id: &str) -> Option<String>;
24 fn get_logs(&self) -> Vec<(bool, String, Option<String>)>;
26 fn get_source(&self, id: &str) -> Option<Arc<Box<dyn LogSource + Send + Sync>>>;
28 fn get_lines(&self, log_id: &str) -> Vec<String>;
30 fn extract_lines(&self, log_id: &str) -> Vec<String>;
32 fn get_total_lines(&self) -> usize;
34 fn toggle_log(&self, log_id: &str);
36}
37
38pub struct InMemmoryLogStore {
39 raw_lines: RwLock<Vec<(String, Vec<String>)>>,
41 format: RwLock<HashMap<String, String>>,
43 enabled: RwLock<HashMap<String, bool>>,
45 source: RwLock<HashMap<String, Arc<Box<dyn LogSource + Send + Sync>>>>,
47}
48
49impl InMemmoryLogStore {
50 pub fn new() -> Self {
51 Self {
52 raw_lines: RwLock::new(Vec::default()),
53 format: RwLock::new(HashMap::default()),
54 enabled: RwLock::new(HashMap::default()),
55 source: RwLock::new(HashMap::default()),
56 }
57 }
58}
59
60impl Default for InMemmoryLogStore {
61 fn default() -> Self {
62 Self::new()
63 }
64}
65
66impl LogStore for InMemmoryLogStore {
67 fn add_log(
68 &self,
69 log_id: &str,
70 log_source: Arc<Box<dyn LogSource + Send + Sync>>,
71 format: Option<&String>,
72 enabled: bool,
73 ) {
74 let (mut source_lock, mut format_lock, mut enabled_lock) = (
75 self.source.write(),
76 self.format.write(),
77 self.enabled.write(),
78 );
79
80 source_lock.insert(log_id.to_string(), log_source);
81 enabled_lock.insert(log_id.to_string(), enabled);
82
83 if let Some(format) = format {
84 format_lock.insert(log_id.to_string(), format.clone());
85 }
86 }
87
88 fn add_line(&self, log_id: &str, line: &str) {
89 let mut raw_lines_lock = self.raw_lines.write();
90
91 if !raw_lines_lock.iter().any(|(id, _)| log_id == id) {
92 raw_lines_lock.push((log_id.to_string(), Vec::new()));
93 }
94 let raw_lines = raw_lines_lock.iter_mut().find(|(id, _)| log_id == id).unwrap();
95 raw_lines.1.push(line.to_string());
96 }
97
98 fn add_lines(&self, log_id: &str, lines: &[String]) -> Range<usize> {
99 let mut raw_lines_lock = self.raw_lines.write();
100
101 if !raw_lines_lock.iter().any(|(id, _)| log_id == id) {
102 raw_lines_lock.push((log_id.to_string(), Vec::new()));
103 }
104 let (_, raw_lines) = raw_lines_lock.iter_mut().find(|(id, _)| log_id == id).unwrap();
105 let current_len = raw_lines.len();
106 raw_lines.append(&mut lines.to_vec());
107
108 let new_len = raw_lines.len();
109 current_len..new_len
110 }
111
112 fn get_lines(&self, log_id: &str) -> Vec<String> {
113 match self.raw_lines.read().iter().find(|(id, _)| log_id == id) {
114 Some((_, lines)) => lines.clone(),
115 _ => Vec::new(),
116 }
117 }
118
119 fn extract_lines(&self, log_id: &str) -> Vec<String> {
120 let mut w = self.raw_lines.write();
121 let (_, lines) = std::mem::take(w.iter_mut().find(|(id, _)| log_id == id).unwrap());
122
123 lines
124 }
125
126 fn get_logs(&self) -> Vec<(bool, String, Option<String>)> {
127 let (format_lock, enabled_lock) = (self.format.read(), self.enabled.read());
128
129 let logs: Vec<(bool, String, Option<String>)> = enabled_lock
130 .iter()
131 .map(|(path, enabled)| (*enabled, path.clone(), format_lock.get(path).cloned()))
132 .collect();
133 logs
134 }
135
136 fn get_format(&self, log_id: &str) -> Option<String> {
137 let format_lock = self.format.read();
138 format_lock.get(log_id).cloned()
139 }
140
141 fn get_total_lines(&self) -> usize {
142 self.raw_lines
143 .read()
144 .iter()
145 .fold(0, |acc, (_, v)| acc + v.len())
146 }
147
148 fn get_source(&self, id: &str) -> Option<Arc<Box<dyn LogSource + Send + Sync>>> {
149 if let Some((_id, source)) = self
150 .source
151 .read()
152 .iter()
153 .find(|(log_id, _source)| *id == **log_id)
154 {
155 Some(source.clone())
156 } else {
157 None
158 }
159 }
160
161 fn toggle_log(&self, log_id: &str) {
162 if let Some(e) = self.enabled.write().get_mut(log_id) {
163 *e = !*e;
164 }
165 }
166}