postfix-log-parser 0.2.0

高性能模块化Postfix日志解析器,经3.2GB生产数据验证,SMTPD事件100%准确率
Documentation
use crate::formatters::{json::JsonFormatter, LogFormatter};
use crate::parse_log_line;
use std::error::Error;
use std::fs;
use std::io::{BufRead, BufReader};

/// 文件处理器
///
/// 用于批量处理日志文件,支持单文件和多文件处理
pub struct FileProcessor {
    /// 输出格式化器
    /// 负责将解析结果转换为指定格式(如JSON)
    formatter: Box<dyn LogFormatter>,
}

impl FileProcessor {
    /// 创建新的文件处理器
    pub fn new() -> Self {
        Self {
            formatter: Box::new(JsonFormatter::new()),
        }
    }

    /// 处理单个日志文件
    pub fn process_file(&self, file_path: &str) -> Result<String, Box<dyn Error>> {
        let file = fs::File::open(file_path)?;
        let reader = BufReader::new(file);

        let mut results = Vec::new();
        let mut line_number = 0;

        for line in reader.lines() {
            let line = line?;
            line_number += 1;

            // 跳过空行
            if line.trim().is_empty() {
                continue;
            }

            // 解析单行日志
            let parse_result = parse_log_line(&line);
            results.push((line_number, line, parse_result));
        }

        // 使用格式化器输出结果
        self.formatter.format_multiple(results)
    }

    /// 处理多个文件(未来功能)
    pub fn process_files(&self, file_paths: &[String]) -> Result<String, Box<dyn Error>> {
        let mut all_results = Vec::new();

        for file_path in file_paths {
            let file = fs::File::open(file_path)?;
            let reader = BufReader::new(file);
            let mut line_number = 0;

            for line in reader.lines() {
                let line = line?;
                line_number += 1;

                if line.trim().is_empty() {
                    continue;
                }

                let parse_result = parse_log_line(&line);
                all_results.push((line_number, line, parse_result));
            }
        }

        self.formatter.format_multiple(all_results)
    }

    /// 处理单行日志(用于交互式使用)
    pub fn process_line(&self, line: &str, line_number: usize) -> Result<String, Box<dyn Error>> {
        let parse_result = parse_log_line(line);
        self.formatter
            .format_single(line_number, line, &parse_result)
    }
}

impl Default for FileProcessor {
    fn default() -> Self {
        Self::new()
    }
}