1use anyhow::Result;
2use chrono::NaiveTime;
3
4#[derive(Debug, Clone)]
5pub enum LogKind {
6 Out,
7 Err
8}
9
10#[derive(Debug, Clone)]
11pub struct Log {
12 pub log_line: usize,
13 pub kind: LogKind,
14 pub time: Option<NaiveTime>,
15 pub thread: String,
16 pub executor: String,
17 pub data: Vec<String>
18}
19
20pub fn parse(line: usize, log: &str) -> Result<Log> {
21 use regex::Regex;
22
23 let log = log.trim();
24 if log.is_empty() {
25 anyhow::bail!("Пустая строка лога");
26 }
27
28 let kind = if log.starts_with("[OUT]") {
29 LogKind::Out
30 } else if log.starts_with("[ERR]") {
31 LogKind::Err
32 } else {
33 anyhow::bail!("Неизвестный тип лога");
34 };
35
36 let content = log
38 .strip_prefix("[OUT]")
39 .or_else(|| log.strip_prefix("[ERR]"))
40 .unwrap()
41 .trim();
42
43 if content.is_empty() {
45 return Ok(Log {
46 log_line: line,
47 kind,
48 time: None,
49 thread: String::new(),
50 executor: String::new(),
51 data: vec![],
52 });
53 }
54
55 let re_full = Regex::new(r"^\[(\d{2}:\d{2}:\d{2})] \[([^\]]+)] \[([^\]]+)]\:?\s?(.*)$")?;
56 let re_simple = Regex::new(r"^\[([^\]]+)] \[([^\]]+)] (.+)$")?;
57
58 if let Some(caps) = re_full.captures(content) {
59 let time = Some(NaiveTime::parse_from_str(caps.get(1).unwrap().as_str(), "%H:%M:%S")?);
60 let thread = caps.get(2).unwrap().as_str().to_string();
61 let executor = caps.get(3).unwrap().as_str().to_string();
62 let data_str = caps.get(4).map(|m| m.as_str().trim()).unwrap_or("").to_string();
63 let data = if data_str.is_empty() { vec![] } else { vec![data_str] };
64
65 Ok(Log {
66 log_line: line,
67 kind,
68 time,
69 thread,
70 executor,
71 data,
72 })
73 } else if let Some(caps) = re_simple.captures(content) {
74 let thread = caps.get(1).unwrap().as_str().to_string();
75 let executor = caps.get(2).unwrap().as_str().to_string();
76 let data_str = caps.get(3).unwrap().as_str().to_string();
77
78 Ok(Log {
79 log_line: line,
80 kind,
81 time: None,
82 thread,
83 executor,
84 data: vec![data_str],
85 })
86 } else {
87 Ok(Log {
89 log_line: line,
90 kind,
91 time: None,
92 thread: String::new(),
93 executor: String::new(),
94 data: vec![content.to_string()],
95 })
96 }
97}