diff --git a/ezlog-core/src/decode.rs b/ezlog-core/src/decode.rs index 04ae4bd..bf8d53a 100644 --- a/ezlog-core/src/decode.rs +++ b/ezlog-core/src/decode.rs @@ -3,6 +3,8 @@ use std::{ self, BufRead, Cursor, + Read, + Seek, Write, }, str::FromStr, @@ -16,8 +18,6 @@ use byteorder::{ }; use integer_encoding::VarIntReader; use log::error; -use once_cell::sync::OnceCell; -use regex::Regex; use time::{ format_description::well_known::Rfc3339, OffsetDateTime, @@ -37,68 +37,68 @@ use crate::{ }; pub fn decode_record(vec: &[u8]) -> Result { - static RE: OnceCell> = OnceCell::new(); - let regex = RE.get_or_init(|| Regex::new(r"\[(.*?)\]")); - let record_str = - String::from_utf8(vec.to_vec()).map_err(|e| LogError::Parse(format!("{}", e)))?; let mut record_builder = EZRecord::builder(); - if let Ok(regex) = regex { - // Search for the first match - if let Some(caps) = regex.captures(&record_str) { - if let Some(matched) = caps.get(1) { - let header = matched.as_str(); - let split: Vec<&str> = header.split_whitespace().collect(); - - let time = split - .first() - .map(|x| { - OffsetDateTime::parse(x, &Rfc3339).unwrap_or(OffsetDateTime::now_utc()) - }) - .unwrap_or(OffsetDateTime::now_utc()); - record_builder.time(time); - - let level = split - .get(1) - .and_then(|x| Level::from_str(x).ok()) - .unwrap_or(Level::Trace); - record_builder.level(level); - - let target = split.get(2).unwrap_or(&"").to_string(); - record_builder.target(target); - - let thread_str = split.get(3).unwrap_or(&""); - let mut thread_info: Vec<&str> = thread_str.split(':').collect(); - if !thread_info.is_empty() { - let thread_id = thread_info.last().unwrap_or(&"").to_string(); - record_builder.thread_id(thread_id.parse::().unwrap_or(0)); - thread_info.pop(); - let thread_name = thread_info.join(":"); - record_builder.thread_name(thread_name); - } + let mut cursor = Cursor::new(vec); + let mut buf = vec![]; + cursor + .read_until(b'[', &mut buf) + .map_err(|_| LogError::Parse("not found [".to_string()))?; + buf.clear(); + cursor + .read_until(b']', &mut buf) + .map_err(|_| LogError::Parse("not found ]".to_string()))?; + buf.pop(); + + let header_buf = String::from_utf8_lossy(&buf); + let mut header_split = header_buf.split_whitespace(); + let time = header_split + .next() + .map(|x| OffsetDateTime::parse(x, &Rfc3339).unwrap_or(OffsetDateTime::now_utc())) + .unwrap_or(OffsetDateTime::now_utc()); + record_builder.time(time); + + let level = header_split + .next() + .and_then(|x| Level::from_str(x).ok()) + .unwrap_or(Level::Trace); + record_builder.level(level); + + let target = header_split.next().unwrap_or(""); + record_builder.target(target.to_string()); + + if let Some(thread_str) = header_split.next() { + let mut thread_info: Vec<&str> = thread_str.split(':').collect(); + if !thread_info.is_empty() { + let thread_id = thread_info.pop().unwrap_or(""); + let thread_name: String = thread_info.join(":"); + record_builder.thread_id(thread_id.parse::().unwrap_or(0)); + record_builder.thread_name(thread_name); + } + } - #[cfg(feature = "log")] - { - if split.len() == 5 { - let file_info: Vec<&str> = split.last().unwrap_or(&"").split(':').collect(); - if !file_info.is_empty() { - let file_name = file_info.first().unwrap_or(&""); - let line = file_info.get(1).unwrap_or(&""); - - record_builder.file(file_name); - record_builder.line(line.parse::().unwrap_or(0)); - } - }; - } - // header not contains square brackets - // two square brackets and one space - if record_str.len() > header.len() + 3 { - let content = &record_str[header.len() + 3..]; - record_builder.content(content.to_string()); - } + #[cfg(feature = "log")] + { + let file_str = header_split.next().unwrap_or(""); + if !file_str.is_empty() { + let file_info: Vec<&str> = file_str.split(':').collect(); + if !file_info.is_empty() { + let file_name = file_info.first().unwrap_or(&""); + let line = file_info.get(1).unwrap_or(&""); + + record_builder.file(file_name); + record_builder.line(line.parse::().unwrap_or(0)); } } - } + }; + let mut content_buf = vec![]; + // skip whitespace + cursor.seek(io::SeekFrom::Current(1)).unwrap_or(0); + cursor + .read_to_end(&mut content_buf) + .map_err(|e| LogError::Parse(format!("parse content: {}", e)))?; + let content = String::from_utf8_lossy(&content_buf); + record_builder.content(content.to_string()); Ok(record_builder.build()) }