Skip to content

第六步:报告生成

src/report/text.rs

rust
use colored::Colorize;
use crate::models::{LogStats, LogLevel};

/// 文本报告生成器
pub struct TextReport;

impl TextReport {
    pub fn generate(stats: &LogStats) -> String {
        let mut report = String::new();
        
        report.push_str(&format!("\n{}\n", "日志分析报告".bold()));
        report.push_str(&format!("{}\n\n", "─".repeat(50)));
        
        // 基本信息
        report.push_str(&format!("总条数: {}\n", stats.total));
        report.push_str(&format!(
            "时间范围: {} - {}\n",
            stats.time_range.0.format("%Y-%m-%d %H:%M:%S"),
            stats.time_range.1.format("%Y-%m-%d %H:%M:%S")
        ));
        
        // 级别统计
        report.push_str(&format!("\n{}\n", "按级别统计".bold()));
        for level in [LogLevel::Debug, LogLevel::Info, LogLevel::Warn, LogLevel::Error, LogLevel::Fatal] {
            let count = stats.by_level.get(&level).unwrap_or(&0);
            let colored_count = match level {
                LogLevel::Debug => count.to_string().dimmed(),
                LogLevel::Info => count.to_string().green(),
                LogLevel::Warn => count.to_string().yellow(),
                LogLevel::Error => count.to_string().red(),
                LogLevel::Fatal => count.to_string().red().bold(),
            };
            report.push_str(&format!("  {}: {}\n", level, colored_count));
        }
        
        // 来源统计
        report.push_str(&format!("\n{}\n", "按来源统计".bold()));
        for (source, count) in &stats.by_source {
            report.push_str(&format!("  {}: {}\n", source.blue(), count));
        }
        
        // 错误列表
        if !stats.errors.is_empty() {
            report.push_str(&format!("\n{}\n", "错误详情".bold().red()));
            for error in &stats.errors {
                report.push_str(&format!(
                    "  [{}] {}: {}\n",
                    error.timestamp.format("%H:%M:%S"),
                    error.source,
                    error.message.red()
                ));
            }
        }
        
        report.push_str(&format!("\n{}\n", "─".repeat(50)));
        
        report
    }
}
▶ Run

第七步:CLI 入口

src/main.rs

rust
use clap::Parser;
use anyhow::Result;
use std::fs;
use chrono::{DateTime, Utc};

mod models;
mod parser;
mod analyzer;
mod report;

#[derive(Parser, Debug)]
#[command(name = "log-analyzer")]
#[command(about = "日志分析工具")]
struct Args {
    /// 日志文件路径
    #[arg(short, long)]
    file: String,
    
    /// 日志格式 (common, nginx, json)
    #[arg(short, long, default_value = "common")]
    format: String,
    
    /// 过滤级别
    #[arg(short = 'l', long)]
    level: Option<String>,
    
    /// 过滤关键词
    #[arg(short = 'k', long)]
    keyword: Option<String>,
    
    /// 输出报告文件
    #[arg(short, long)]
    output: Option<String>,
}

fn main() -> Result<()> {
    let args = Args::parse();
    
    // 读取文件
    let content = fs::read_to_string(&args.file)?;
    
    // 解析日志
    let entries = match args.format.as_str() {
        "common" => parser::common::CommonLogParser::new().parse_file(&content),
        "nginx" => parser::nginx::NginxLogParser::new().parse_file(&content),
        "json" => content.lines()
            .filter_map(|line| parser::json::JsonLogParser.parse_line(line))
            .collect(),
        _ => return Err(anyhow::anyhow!("不支持的格式: {}", args.format)),
    };
    
    // 应用过滤
    let filter = analyzer::filter::Filter::new();
    let filtered = filter.apply(&entries);
    
    // 统计分析
    let stats = analyzer::stats::StatsAnalyzer::analyze(&filtered);
    
    // 生成报告
    let report = report::text::TextReport::generate(&stats);
    
    // 输出
    if let Some(output_path) = args.output {
        fs::write(&output_path, &report)?;
        println!("报告已保存到: {}", output_path);
    } else {
        println!("{}", report);
    }
    
    Ok(())
}
▶ Run

运行效果

bash
# 分析通用格式日志
log-analyzer -f app.log --format common

# 分析 Nginx 日志
log-analyzer -f nginx.log --format nginx

# 过滤错误级别
log-analyzer -f app.log -l error

# 搜索关键词
log-analyzer -f app.log -k "timeout"

# 输出到文件
log-analyzer -f app.log -o report.txt

输出示例

日志分析报告
──────────────────────────────────────────────────

总条数: 10000
时间范围: 2024-01-15 00:00:00 - 2024-01-15 23:59:59

按级别统计
  DEBUG: 500
  INFO: 8000
  WARN: 1000
  ERROR: 450
  FATAL: 50

按来源统计
  api: 3000
  web: 2500
  db: 2000
  auth: 1500
  cache: 1000

错误详情
  [10:30:00] api: Connection timeout
  [11:45:00] db: Query failed: deadlock
  [14:20:00] auth: Token validation failed

──────────────────────────────────────────────────

小结

本项目涵盖:

  • ✅ 多格式日志解析
  • ✅ 正则表达式应用
  • ✅ 时间处理
  • ✅ 数据聚合统计
  • ✅ 过滤器实现
  • ✅ 报告生成