postfix_log_parser/events/
base.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use super::{
5    anvil::AnvilEvent, bounce::BounceEvent, discard::DiscardEvent, master::MasterEvent,
6    pickup::PickupEvent, postfix_script::PostfixScriptEvent, postmap::PostmapEvent,
7    relay::RelayEvent, trivial_rewrite::TrivialRewriteEvent, CleanupEvent, ErrorEvent, LocalEvent,
8    QmgrEvent, SmtpEvent, SmtpdEvent, VirtualEvent,
9};
10
11/// 基础事件信息
12/// 包含所有Postfix事件的通用字段
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub struct BaseEvent {
15    /// 日志时间戳
16    pub timestamp: DateTime<Utc>,
17    /// 主机名
18    pub hostname: String,
19    /// 组件名称
20    pub component: String,
21    /// 进程ID
22    pub process_id: u32,
23    /// 日志等级
24    pub log_level: PostfixLogLevel,
25    /// 原始消息
26    pub raw_message: String,
27}
28
29/// 统一的Postfix日志事件结构
30///
31/// 这是解析后的日志事件的完整表示,包含所有基础字段和具体的事件数据
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct PostfixLogEvent {
34    /// 原始日志行(完整的原始日志字符串)
35    /// 用途:审计、调试、追溯原始数据
36    /// 示例:"Jun 05 15:40:52 m01 postfix/smtpd[89]: connect from localhost[127.0.0.1]"
37    pub raw_log: String,
38
39    /// 日志时间戳(UTC时间)
40    /// 从日志行提取的时间信息,自动转换为UTC格式
41    /// 格式:ISO 8601标准时间格式
42    pub timestamp: DateTime<Utc>,
43
44    /// 主机名(产生日志的服务器主机名)
45    /// 从日志行中的第二个字段提取
46    /// 示例:"m01", "mail.example.com"
47    pub hostname: String,
48
49    /// Postfix组件名称(产生此日志的Postfix组件)
50    /// 可能的值:smtpd, qmgr, smtp, cleanup, local, virtual等
51    /// 对应Postfix架构中的不同功能模块
52    pub component: String,
53
54    /// 进程ID(产生日志的进程标识符)
55    /// 从日志行中方括号内提取的数字
56    /// 用于区分同一组件的不同进程实例
57    pub process_id: u32,
58
59    /// 日志等级(日志的重要性和严重程度)
60    /// 基于Postfix源码中的msg_*函数分类
61    /// 影响日志的过滤和告警策略
62    pub log_level: PostfixLogLevel,
63
64    /// 具体的业务事件数据(解析后的结构化事件信息)
65    /// 根据不同组件类型包含不同的事件结构
66    /// 这是日志解析的核心价值所在
67    pub event: ComponentEvent,
68
69    /// 队列ID(邮件在Postfix队列系统中的唯一标识符)
70    /// 用于跟踪单个邮件在系统中的完整生命周期
71    /// 格式:通常为十六进制字符串,如"5BC302B027ED"
72    pub queue_id: Option<String>,
73}
74
75impl PostfixLogEvent {
76    /// 创建新的日志事件
77    pub fn new(
78        raw_log: String,
79        timestamp: DateTime<Utc>,
80        hostname: String,
81        component: String,
82        process_id: u32,
83        log_level: PostfixLogLevel,
84        event: ComponentEvent,
85        queue_id: Option<String>,
86    ) -> Self {
87        Self {
88            raw_log,
89            timestamp,
90            hostname,
91            component,
92            process_id,
93            log_level,
94            event,
95            queue_id,
96        }
97    }
98
99    /// 获取事件类型描述
100    pub fn event_type(&self) -> &'static str {
101        self.event.event_type()
102    }
103
104    /// 检查是否为错误级别的日志
105    pub fn is_error_level(&self) -> bool {
106        self.log_level.is_error_level()
107    }
108
109    /// 检查是否为警告级别的日志
110    pub fn is_warning_level(&self) -> bool {
111        self.log_level.is_warning_level()
112    }
113
114    /// 检查是否为调试级别的日志
115    pub fn is_debug_level(&self) -> bool {
116        self.log_level.is_debug_level()
117    }
118
119    /// 获取日志等级的严重程度数值
120    pub fn severity_level(&self) -> u8 {
121        self.log_level.severity_level()
122    }
123}
124
125/// 组件事件枚举
126///
127/// 每个Postfix组件都有对应的事件类型
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub enum ComponentEvent {
130    /// SMTPD组件事件
131    Smtpd(SmtpdEvent),
132    /// 队列管理器组件事件
133    Qmgr(QmgrEvent),
134    /// SMTP投递组件事件
135    Smtp(SmtpEvent),
136    /// 清理组件事件
137    Cleanup(CleanupEvent),
138    /// 错误处理组件事件
139    Error(ErrorEvent),
140    /// 中继组件事件
141    Relay(RelayEvent),
142    /// 丢弃组件事件
143    Discard(DiscardEvent),
144    /// 退信处理组件事件
145    Bounce(BounceEvent),
146    /// Postfix脚本组件事件
147    PostfixScript(PostfixScriptEvent),
148    /// Master守护进程组件事件
149    Master(MasterEvent),
150    /// 本地投递组件事件
151    Local(LocalEvent),
152    /// 邮件拾取组件事件
153    Pickup(PickupEvent),
154    /// Postmap工具组件事件
155    Postmap(PostmapEvent),
156    /// Anvil连接计数组件事件
157    Anvil(AnvilEvent),
158    /// 地址重写和解析组件事件
159    TrivialRewrite(TrivialRewriteEvent),
160    /// 虚拟投递组件事件
161    Virtual(VirtualEvent),
162    /// Postlogd组件事件
163    Postlogd(crate::events::postlogd::PostlogdEvent),
164    /// Proxymap组件事件  
165    Proxymap(crate::events::proxymap::ProxymapEvent),
166    Sendmail(crate::events::sendmail::SendmailEvent),
167    /// 未知或不支持的组件事件
168    Unknown(UnknownEvent),
169}
170
171impl ComponentEvent {
172    /// 获取事件类型描述
173    pub fn event_type(&self) -> &'static str {
174        match self {
175            ComponentEvent::Smtpd(event) => event.event_type(),
176            ComponentEvent::Qmgr(event) => event.event_type(),
177            ComponentEvent::Smtp(event) => event.event_type(),
178            ComponentEvent::Cleanup(event) => event.event_type(),
179            ComponentEvent::Error(event) => event.event_type(),
180            ComponentEvent::Relay(_) => "relay",
181            ComponentEvent::Discard(_) => "discard",
182            ComponentEvent::Bounce(event) => event.event_type(),
183            ComponentEvent::PostfixScript(_) => "postfix-script",
184            ComponentEvent::Master(event) => event.event_type(),
185            ComponentEvent::Local(event) => event.event_type(),
186            ComponentEvent::Pickup(_) => "pickup",
187            ComponentEvent::Postmap(_) => "postmap",
188            ComponentEvent::Anvil(_) => "anvil",
189            ComponentEvent::TrivialRewrite(_) => "trivial-rewrite",
190            ComponentEvent::Virtual(event) => event.event_type(),
191            ComponentEvent::Postlogd(_) => "postlogd",
192            ComponentEvent::Proxymap(_) => "proxymap",
193            ComponentEvent::Sendmail(_) => "sendmail",
194            ComponentEvent::Unknown(_) => "unknown",
195        }
196    }
197}
198
199/// 未知组件事件(无法识别的组件产生的事件)
200/// 当遇到未知组件或解析失败时使用此结构
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct UnknownEvent {
203    /// 组件名称(即使未知也保留原始组件名)
204    pub component: String,
205    /// 消息内容(去除前缀后的原始消息内容)
206    pub message: String,
207}
208
209/// Postfix日志等级,对应Postfix源码中的msg_*函数
210/// 基于Postfix源码:msg_debug, msg_info, msg_warn, msg_error, msg_fatal, msg_panic
211#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
212pub enum PostfixLogLevel {
213    /// msg_debug() - 调试信息(默认关闭)
214    Debug,
215    /// msg_info() - 正常业务操作(最常见,默认等级)
216    Info,
217    /// msg_warn() - 警告,可恢复问题
218    Warning,
219    /// msg_error() - 错误,操作失败但系统可继续
220    Error,
221    /// msg_fatal() - 致命错误,导致进程退出
222    Fatal,
223    /// msg_panic() - 系统崩溃级别
224    Panic,
225}
226
227impl PostfixLogLevel {
228    /// 获取日志等级的严重程度数值(1-6,数值越高越严重)
229    pub fn severity_level(&self) -> u8 {
230        match self {
231            PostfixLogLevel::Debug => 1,
232            PostfixLogLevel::Info => 2,
233            PostfixLogLevel::Warning => 3,
234            PostfixLogLevel::Error => 4,
235            PostfixLogLevel::Fatal => 5,
236            PostfixLogLevel::Panic => 6,
237        }
238    }
239
240    /// 检查是否为错误级别(Error/Fatal/Panic)
241    pub fn is_error_level(&self) -> bool {
242        matches!(
243            self,
244            PostfixLogLevel::Error | PostfixLogLevel::Fatal | PostfixLogLevel::Panic
245        )
246    }
247
248    /// 检查是否为警告级别
249    pub fn is_warning_level(&self) -> bool {
250        matches!(self, PostfixLogLevel::Warning)
251    }
252
253    /// 检查是否为调试级别
254    pub fn is_debug_level(&self) -> bool {
255        matches!(self, PostfixLogLevel::Debug)
256    }
257
258    /// 获取日志等级的字符串表示
259    pub fn as_str(&self) -> &'static str {
260        match self {
261            PostfixLogLevel::Debug => "debug",
262            PostfixLogLevel::Info => "info",
263            PostfixLogLevel::Warning => "warning",
264            PostfixLogLevel::Error => "error",
265            PostfixLogLevel::Fatal => "fatal",
266            PostfixLogLevel::Panic => "panic",
267        }
268    }
269
270    /// 从字符串解析日志等级(用于解析日志中的等级前缀)
271    pub fn from_prefix(prefix: &str) -> Option<Self> {
272        match prefix.to_lowercase().as_str() {
273            "debug:" => Some(PostfixLogLevel::Debug),
274            "warning:" => Some(PostfixLogLevel::Warning),
275            "error:" => Some(PostfixLogLevel::Error),
276            "fatal:" => Some(PostfixLogLevel::Fatal),
277            "panic:" => Some(PostfixLogLevel::Panic),
278            _ => None,
279        }
280    }
281}
282
283impl Default for PostfixLogLevel {
284    /// 默认为Info级别(Postfix大部分日志都是Info级别)
285    fn default() -> Self {
286        PostfixLogLevel::Info
287    }
288}
289
290impl std::fmt::Display for PostfixLogLevel {
291    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292        write!(f, "{}", self.as_str())
293    }
294}