Skip to content

Commit c5ca87c

Browse files
committedFeb 18, 2025
增加日志信息控制
1 parent 7ef67dc commit c5ca87c

File tree

5 files changed

+58
-11
lines changed

5 files changed

+58
-11
lines changed
 

‎README.md

+5
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,18 @@ docker run --rm -v /path/to/emails:/data rsendmail --smtp-server <smtp_server> -
4848
- `--processes`: Number of processes, "auto" for CPU core count or specify a number (default: auto)
4949
- `--batch-size`: Number of emails to send in a single SMTP session (default: 1)
5050
- `--smtp-timeout`: SMTP session timeout in seconds (default: 30)
51+
- `--log-level`: Log level (error/warn/info/debug/trace) (default: info)
5152

5253
## Example
5354

5455
```bash
5556
# Local example
57+
# Normal logging (info level)
5658
rsendmail --smtp-server 192.168.1.100 --port 25 --from sender@example.com --to recipient@example.com --dir ./emails --processes 10 --batch-size 5
5759

60+
# Detailed debug logging
61+
rsendmail --smtp-server 192.168.1.100 --port 25 --from sender@example.com --to recipient@example.com --dir ./emails --processes 10 --batch-size 5 --log-level debug
62+
5863
# Docker example
5964
docker run --rm -v $(pwd)/emails:/data rsendmail --smtp-server 192.168.1.100 --port 25 --from sender@example.com --to recipient@example.com --dir /data --processes 10 --batch-size 5
6065
```

‎rsendmail/src/config.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use clap::Parser;
2+
use log::LevelFilter;
23

34
/// A high-performance bulk email sending CLI tool
45
#[derive(Parser, Debug, Clone)]
@@ -39,6 +40,10 @@ pub struct Config {
3940
/// SMTP会话超时时间(秒)
4041
#[arg(long, default_value_t = 30)]
4142
pub smtp_timeout: u64,
43+
44+
/// 日志级别 (error/warn/info/debug/trace)
45+
#[arg(long, default_value = "info")]
46+
pub log_level: String,
4247
}
4348

4449
#[derive(Debug, PartialEq)]
@@ -48,6 +53,17 @@ pub enum ProcessMode {
4853
}
4954

5055
impl Config {
56+
pub fn get_log_level(&self) -> LevelFilter {
57+
match self.log_level.to_lowercase().as_str() {
58+
"error" => LevelFilter::Error,
59+
"warn" => LevelFilter::Warn,
60+
"info" => LevelFilter::Info,
61+
"debug" => LevelFilter::Debug,
62+
"trace" => LevelFilter::Trace,
63+
_ => LevelFilter::Info,
64+
}
65+
}
66+
5167
pub fn process_mode(&self) -> ProcessMode {
5268
if self.processes == "auto" {
5369
ProcessMode::Auto

‎rsendmail/src/mailer.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,19 @@ impl Mailer {
7272
group_stats.2 += send_duration;
7373
}
7474
Err(e) => {
75-
error!("进程组 {} 文件 {} 发送失败: {}", i + 1, j + 1, e);
76-
group_stats.3.push((e.to_string(), file.clone()));
75+
let error_type = if e.to_string().contains("parse") {
76+
"解析错误"
77+
} else if e.to_string().contains("timeout") {
78+
"连接超时"
79+
} else if e.to_string().contains("authentication") {
80+
"认证失败"
81+
} else if e.to_string().contains("connection refused") {
82+
"连接被拒绝"
83+
} else {
84+
"其他错误"
85+
};
86+
error!("进程组 {} 文件 {} 发送失败 - {}: {}", i + 1, j + 1, error_type, e);
87+
group_stats.3.push((error_type.to_string(), file.clone()));
7788
}
7889
}
7990
}

‎rsendmail/src/main.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,14 @@ use std::process;
1313

1414
#[tokio::main]
1515
async fn main() -> anyhow::Result<()> {
16+
// 解析命令行参数
17+
let config = Config::parse();
18+
1619
// 初始化日志
17-
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
20+
env_logger::Builder::from_env(Env::default())
21+
.filter_level(config.get_log_level())
22+
.format_timestamp_millis()
23+
.init();
1824

1925
// 创建一个原子布尔值用于控制程序退出
2026
let running = Arc::new(AtomicBool::new(true));
@@ -26,8 +32,7 @@ async fn main() -> anyhow::Result<()> {
2632
r.store(false, Ordering::SeqCst);
2733
})?;
2834

29-
// 解析命令行参数
30-
let config = Config::parse();
35+
// 配置已在上面解析
3136

3237
// 创建邮件发送器
3338
let mailer = Mailer::new(config);

‎rsendmail/src/stats.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,28 @@ impl Stats {
7171

7272
impl fmt::Display for Stats {
7373
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74+
writeln!(f, "邮件发送统计报告")?;
75+
writeln!(f, "===================")?;
76+
writeln!(f, "1. 基本统计")?;
7477
writeln!(f, " 总计处理: {} 封邮件", self.email_count)?;
7578
writeln!(f, " 成功发送: {} 封", self.email_count - self.send_errors - self.parse_errors)?;
76-
writeln!(f, " 解析失败: {} 封", self.parse_errors)?;
77-
writeln!(f, " 发送失败: {} 封", self.send_errors)?;
79+
writeln!(f, " 总计失败: {} 封", self.send_errors + self.parse_errors)?;
7880

7981
if !self.error_details.is_empty() {
80-
writeln!(f, " 发送失败详情:")?;
81-
for (error_type, count) in &self.error_details {
82-
writeln!(f, " {}: {} 封", error_type, count)?;
82+
writeln!(f, "\n2. 错误分类统计")?;
83+
let mut sorted_errors: Vec<_> = self.error_details.iter().collect();
84+
sorted_errors.sort_by(|a, b| b.1.cmp(a.1));
85+
86+
for (error_type, count) in sorted_errors {
87+
writeln!(f, " {} - {} 封 ({:.1}%)",
88+
error_type,
89+
count,
90+
(*count as f64 / self.email_count as f64) * 100.0
91+
)?;
8392
if let Some(files) = self.failed_files.get(error_type) {
93+
writeln!(f, " 失败文件列表:")?;
8494
for file in files {
85-
writeln!(f, " - {}", file)?;
95+
writeln!(f, " - {}", file)?;
8696
}
8797
}
8898
}

0 commit comments

Comments
 (0)
Failed to load comments.