第六步:报告生成
src/report/text.rs
rust
▶ Runuse 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
}
}第七步:CLI 入口
src/main.rs
rust
▶ Runuse 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(())
}运行效果
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
──────────────────────────────────────────────────小结
本项目涵盖:
- ✅ 多格式日志解析
- ✅ 正则表达式应用
- ✅ 时间处理
- ✅ 数据聚合统计
- ✅ 过滤器实现
- ✅ 报告生成