use std::fs::{self, File};
use std::io::{self, BufRead, BufReader, Write};
pub struct LogSplit {
pub source: String,
pub target: String,
pub level: String,
}
impl LogSplit {
pub fn new(source: &str, target: &str) -> Self {
LogSplit {
source: source.to_string(),
target: target.to_string(),
level: "ERROR".to_string(),
}
}
pub fn with_level(mut self, level: &str) -> Self {
self.level = level.to_string();
self
}
pub fn split(&self) -> io::Result<usize> {
let source_file = File::open(&self.source)?;
let reader = BufReader::new(source_file);
let pattern = format!("[{}]", self.level.to_uppercase());
let matched: Vec<String> = reader
.lines()
.filter_map(|l| l.ok())
.filter(|l| l.contains(&pattern))
.collect();
let count = matched.len();
if count > 0 {
let mut target_file = File::create(&self.target)?;
for line in &matched {
writeln!(target_file, "{}", line)?;
}
}
Ok(count)
}
pub fn split_append(&self) -> io::Result<usize> {
let source_file = File::open(&self.source)?;
let reader = BufReader::new(source_file);
let pattern = format!("[{}]", self.level.to_uppercase());
let matched: Vec<String> = reader
.lines()
.filter_map(|l| l.ok())
.filter(|l| l.contains(&pattern))
.collect();
let count = matched.len();
if count > 0 {
let mut target_file = fs::OpenOptions::new()
.create(true)
.append(true)
.open(&self.target)?;
for line in &matched {
writeln!(target_file, "{}", line)?;
}
}
Ok(count)
}
}
pub fn split_errors_from_dir(log_dir: &str, error_file: &str) -> io::Result<usize> {
let mut total = 0;
if let Ok(entries) = fs::read_dir(log_dir) {
for entry in entries.flatten() {
let path = entry.path();
if path.is_file() && path.extension().map_or(false, |e| e == "log") {
let splitter = LogSplit::new(path.to_str().unwrap_or(""), error_file);
if let Ok(count) = splitter.split_append() {
total += count;
}
}
}
}
Ok(total)
}
pub fn split_all_levels(source: &str, out_dir: &str) -> io::Result<(usize, usize, usize)> {
let source_file = File::open(source)?;
let reader = BufReader::new(source_file);
let mut info_lines = Vec::new();
let mut error_lines = Vec::new();
let mut debug_lines = Vec::new();
for line in reader.lines().flatten() {
if line.contains("[ERROR]") {
error_lines.push(line);
} else if line.contains("[DEBUG]") {
debug_lines.push(line);
} else if line.contains("[INFO]") {
info_lines.push(line);
}
}
let (ic, ec, dc) = (info_lines.len(), error_lines.len(), debug_lines.len());
if ic > 0 {
let mut f = File::create(format!("{}/app-info.log", out_dir))?;
for l in &info_lines { writeln!(f, "{}", l)?; }
}
if ec > 0 {
let mut f = File::create(format!("{}/app-error.log", out_dir))?;
for l in &error_lines { writeln!(f, "{}", l)?; }
}
if dc > 0 {
let mut f = File::create(format!("{}/app-db.log", out_dir))?;
for l in &debug_lines { writeln!(f, "{}", l)?; }
}
Ok((ic, ec, dc))
}