log_analyzer/models/
log_line.rs

1use std::cmp::Ordering;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Default, Serialize, Deserialize, Clone, Debug)]
6#[serde(default)]
7/// This struct contains a formated log with its info clasified
8/// in several fields
9pub struct LogLine {
10    pub log: String,
11    pub index: String,
12    pub date: String,
13    pub timestamp: String,
14    pub app: String,
15    pub severity: String,
16    pub function: String,
17    pub payload: String,
18    pub color: Option<(u8, u8, u8)>,
19}
20
21impl LogLine {
22    /// Returns the available fields
23    pub fn columns() -> Vec<String> {
24        vec![
25            "Log".to_string(),
26            "Index".to_string(),
27            "Date".to_string(),
28            "Timestamp".to_string(),
29            "App".to_string(),
30            "Severity".to_string(),
31            "Function".to_string(),
32            "Payload".to_string(),
33        ]
34    }
35
36    /// Gets the field value with the `columns` returned key
37    pub fn get(&self, key: &str) -> Option<&String> {
38        match key {
39            "Log" => Some(&self.log),
40            "Index" => Some(&self.index),
41            "Date" => Some(&self.date),
42            "Timestamp" => Some(&self.timestamp),
43            "App" => Some(&self.app),
44            "Severity" => Some(&self.severity),
45            "Function" => Some(&self.function),
46            "Payload" => Some(&self.payload),
47            _ => None,
48        }
49    }
50
51    /// Gets a (key, value) like representation of some fields
52    pub fn values(&self) -> Vec<(&str, &String)> {
53        vec![
54            ("Log", &self.log),
55            ("Date", &self.date),
56            ("Timestamp", &self.timestamp),
57            ("App", &self.app),
58            ("Severity", &self.severity),
59            ("Function", &self.function),
60            ("Payload", &self.payload),
61        ]
62    }
63
64    /// Check if the content of the lines is formatted
65    pub fn is_formated(&self) -> bool {
66        self.into_iter()
67        .any(|field| serde_json::from_str::<Vec<(Option<&str>, &str)>>(field).is_ok())
68    }
69
70    /// Return a copy of this line with unformatted content
71    pub fn unformat(&self) -> Self {
72        let unformat = |field: &str| {
73            let groups = serde_json::from_str::<Vec<(Option<&str>, &str)>>(field);
74
75            match groups {
76                Ok(groups) => groups.into_iter().fold(String::new(), |acc, g| acc + g.1),
77                _ => field.to_string(),
78            }
79        };
80
81        LogLine {
82            log: unformat(&self.log),
83            index: unformat(&self.index),
84            date: unformat(&self.date),
85            timestamp: unformat(&self.timestamp),
86            app: unformat(&self.app),
87            severity: unformat(&self.severity),
88            function: unformat(&self.function),
89            payload: unformat(&self.payload),
90            color: self.color,
91        }
92    }
93}
94
95impl IntoIterator for LogLine {
96    type Item = String;
97    type IntoIter = std::array::IntoIter<String, 7>;
98
99    fn into_iter(self) -> Self::IntoIter {
100        IntoIterator::into_iter([
101            self.log,
102            self.date,
103            self.timestamp,
104            self.app,
105            self.severity,
106            self.function,
107            self.payload,
108        ])
109    }
110}
111
112impl<'a> IntoIterator for &'a LogLine {
113    type Item = &'a String;
114    type IntoIter = std::array::IntoIter<&'a String, 7>;
115
116    fn into_iter(self) -> Self::IntoIter {
117        IntoIterator::into_iter([
118            &self.log,
119            &self.date,
120            &self.timestamp,
121            &self.app,
122            &self.severity,
123            &self.function,
124            &self.payload,
125        ])
126    }
127}
128
129impl<'a> IntoIterator for &'a mut LogLine {
130    type Item = &'a String;
131    type IntoIter = std::array::IntoIter<&'a String, 7>;
132
133    fn into_iter(self) -> Self::IntoIter {
134        IntoIterator::into_iter([
135            &self.log,
136            &self.date,
137            &self.timestamp,
138            &self.app,
139            &self.severity,
140            &self.function,
141            &self.payload,
142        ])
143    }
144}
145
146impl<'a> IntoIterator for &'a &'a mut LogLine {
147    type Item = &'a String;
148    type IntoIter = std::array::IntoIter<&'a String, 7>;
149
150    fn into_iter(self) -> Self::IntoIter {
151        IntoIterator::into_iter([
152            &self.log,
153            &self.date,
154            &self.timestamp,
155            &self.app,
156            &self.severity,
157            &self.function,
158            &self.payload,
159        ])
160    }
161}
162impl<'a> IntoIterator for &'a &'a LogLine {
163    type Item = &'a String;
164    type IntoIter = std::array::IntoIter<&'a String, 7>;
165
166    fn into_iter(self) -> Self::IntoIter {
167        IntoIterator::into_iter([
168            &self.log,
169            &self.date,
170            &self.timestamp,
171            &self.app,
172            &self.severity,
173            &self.function,
174            &self.payload,
175        ])
176    }
177}
178
179impl Ord for LogLine {
180    fn cmp(&self, other: &Self) -> Ordering {
181        match (self.index.parse::<usize>(), other.index.parse::<usize>()) {
182            (Ok(index), Ok(other)) => match (index, other) {
183                (index, other) if index < other => Ordering::Less,
184                (index, other) if index == other => Ordering::Equal,
185                _ => Ordering::Greater,
186            },
187            _ => Ordering::Equal,
188        }
189    }
190}
191
192impl PartialOrd for LogLine {
193    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
194        match (self.index.parse::<usize>(), other.index.parse::<usize>()) {
195            (Ok(index), Ok(other)) => match (index, other) {
196                (index, other) if index < other => Some(Ordering::Less),
197                (index, other) if index == other => Some(Ordering::Equal),
198                _ => Some(Ordering::Greater),
199            },
200            _ => None,
201        }
202    }
203}
204
205impl PartialEq for LogLine {
206    fn eq(&self, other: &Self) -> bool {
207        self.index == other.index
208            && self.date == other.date
209            && self.timestamp == other.timestamp
210            && self.app == other.app
211            && self.severity == other.severity
212            && self.function == other.function
213            && self.payload == other.payload
214            && self.color == other.color
215    }
216}
217
218impl Eq for LogLine {}