postfix-log-parser 0.2.0

高性能模块化Postfix日志解析器,经3.2GB生产数据验证,SMTPD事件100%准确率
Documentation
//! Cleanup邮件清理模块
//!
//! 处理Postfix cleanup守护进程的事件,包括邮件内容处理、头部重写和队列准备

use serde::{Deserialize, Serialize};

/// Cleanup组件事件
/// 基于896,788个真实生产数据分析,cleanup组件占4.5%的日志
/// cleanup主要负责邮件内容处理、重写和清理
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CleanupEvent {
    /// Message-ID处理 - 最常见的cleanup事件
    MessageId {
        queue_id: String,
        message_id: String,
    },

    /// 队列文件操作警告
    QueueFileWarning {
        operation: String,    // 如 "mail_queue_enter"
        file_path: String,    // 如 "incoming/635139.92"
        error_reason: String, // 如 "Permission denied"
    },

    /// 邮件内容重写
    /// cleanup可能会重写邮件头、地址等
    MessageRewrite {
        queue_id: String,
        rewrite_type: String, // 重写类型
        original: String,     // 原始内容
        rewritten: String,    // 重写后内容
    },

    /// 邮件大小信息
    /// cleanup处理邮件时会记录大小信息
    MessageSize {
        queue_id: String,
        size: u64, // 邮件大小(字节)
    },

    /// 邮件头处理
    /// cleanup处理各种邮件头
    HeaderProcessing {
        queue_id: String,
        header_name: String,  // 头字段名
        header_value: String, // 头字段值
        action: String,       // 动作 (add, remove, replace)
    },

    /// 邮件过滤器处理
    /// 与milter等过滤器交互的事件
    FilterAction {
        queue_id: String,
        filter_name: String,     // 过滤器名称
        action: String,          // 过滤器动作
        details: Option<String>, // 详细信息
    },

    /// 地址重写
    /// cleanup可能重写发件人或收件人地址
    AddressRewrite {
        queue_id: String,
        address_type: String, // "from" 或 "to"
        original_address: String,
        rewritten_address: String,
    },

    /// 邮件拒绝
    /// cleanup阶段的邮件拒绝
    MessageReject {
        queue_id: String,
        reason: String, // 拒绝原因
        action: String, // 拒绝动作
    },

    /// 资源限制警告
    /// 磁盘空间、内存等资源限制
    ResourceLimit {
        resource_type: String, // 资源类型
        limit_details: String, // 限制详情
        current_value: Option<u64>,
        limit_value: Option<u64>,
    },

    /// Milter交互
    /// 与邮件过滤器的交互事件
    MilterInteraction {
        queue_id: String,
        milter_name: String,      // milter名称
        command: String,          // milter命令
        response: Option<String>, // milter响应
    },

    /// 配置警告
    /// cleanup相关的配置问题
    ConfigurationWarning {
        warning_type: String, // 警告类型
        message: String,      // 警告消息
    },

    /// 统计信息
    /// cleanup处理统计
    Statistics {
        processed: Option<u32>, // 处理的邮件数
        rejected: Option<u32>,  // 拒绝的邮件数
        errors: Option<u32>,    // 错误数
    },

    /// Snowflake ID生成器初始化
    /// 记录唯一ID生成器的初始化配置
    SnowflakeInit {
        node_id: u32,   // 节点ID
        node_bits: u32, // 节点位数
        seq_bits: u32,  // 序列位数
    },

    /// 邮件隔离/保留事件
    /// 当邮件被隔离或保留时记录的事件
    MessageHold {
        queue_id: String,
        hold_reason: String, // 保留原因,如 "header X-Decision-Result: Quarantine"
        sender: Option<String>, // 发件人地址(统一命名)
        recipient: Option<String>, // 收件人地址(统一命名)
        client_ip: Option<String>, // 客户端IP地址
        client_hostname: Option<String>, // 客户端主机名
        client_port: Option<u16>, // 客户端端口
        protocol: Option<String>, // 协议信息
        helo: Option<String>, // HELO信息
        description: String, // 详细描述
    },

    /// 邮件丢弃事件
    /// 当邮件被丢弃时记录的事件
    MessageDiscard {
        queue_id: String,
        discard_reason: String, // 丢弃原因,如 "header X-Decision-Result: Discard"
        sender: Option<String>, // 发件人地址(统一命名)
        recipient: Option<String>, // 收件人地址(统一命名)
        client_ip: Option<String>, // 客户端IP地址
        client_hostname: Option<String>, // 客户端主机名
        client_port: Option<u16>, // 客户端端口
        protocol: Option<String>, // 协议信息
        helo: Option<String>,   // HELO信息
        description: String,    // 详细描述
    },

    /// 邮件移除事件
    /// 当邮件从队列中被移除时记录的事件
    MessageRemoved {
        queue_id: String,
        removal_reason: String, // 移除原因,如 "discarded", "bounced", "delivered"
        details: Option<String>, // 额外详细信息
    },

    /// 其他cleanup事件
    /// 用于处理暂时无法分类的cleanup事件
    Other {
        event_type: String,
        message: String,
        queue_id: Option<String>,
    },
}

impl CleanupEvent {
    pub fn event_type(&self) -> &'static str {
        match self {
            CleanupEvent::MessageId { .. } => "message_id",
            CleanupEvent::QueueFileWarning { .. } => "queue_file_warning",
            CleanupEvent::MessageRewrite { .. } => "message_rewrite",
            CleanupEvent::MessageSize { .. } => "message_size",
            CleanupEvent::HeaderProcessing { .. } => "header_processing",
            CleanupEvent::FilterAction { .. } => "filter_action",
            CleanupEvent::AddressRewrite { .. } => "address_rewrite",
            CleanupEvent::MessageReject { .. } => "message_reject",
            CleanupEvent::ResourceLimit { .. } => "resource_limit",
            CleanupEvent::MilterInteraction { .. } => "milter_interaction",
            CleanupEvent::ConfigurationWarning { .. } => "configuration_warning",
            CleanupEvent::Statistics { .. } => "statistics",
            CleanupEvent::SnowflakeInit { .. } => "snowflake_init",
            CleanupEvent::MessageHold { .. } => "message_hold",
            CleanupEvent::MessageDiscard { .. } => "message_discard",
            CleanupEvent::MessageRemoved { .. } => "message_removed",
            CleanupEvent::Other { .. } => "other",
        }
    }

    /// 获取队列ID(如果存在)
    pub fn queue_id(&self) -> Option<&str> {
        match self {
            CleanupEvent::MessageId { queue_id, .. } => Some(queue_id),
            CleanupEvent::MessageRewrite { queue_id, .. } => Some(queue_id),
            CleanupEvent::MessageSize { queue_id, .. } => Some(queue_id),
            CleanupEvent::HeaderProcessing { queue_id, .. } => Some(queue_id),
            CleanupEvent::FilterAction { queue_id, .. } => Some(queue_id),
            CleanupEvent::AddressRewrite { queue_id, .. } => Some(queue_id),
            CleanupEvent::MessageReject { queue_id, .. } => Some(queue_id),
            CleanupEvent::MilterInteraction { queue_id, .. } => Some(queue_id),
            CleanupEvent::MessageHold { queue_id, .. } => Some(queue_id),
            CleanupEvent::MessageDiscard { queue_id, .. } => Some(queue_id),
            CleanupEvent::MessageRemoved { queue_id, .. } => Some(queue_id),
            CleanupEvent::Other { queue_id, .. } => queue_id.as_deref(),
            _ => None,
        }
    }

    /// 检查是否为错误级别事件
    pub fn is_error_event(&self) -> bool {
        matches!(
            self,
            CleanupEvent::QueueFileWarning { .. }
                | CleanupEvent::MessageReject { .. }
                | CleanupEvent::ResourceLimit { .. }
        )
    }

    /// 检查是否为警告级别事件
    pub fn is_warning_event(&self) -> bool {
        matches!(
            self,
            CleanupEvent::QueueFileWarning { .. }
                | CleanupEvent::ConfigurationWarning { .. }
                | CleanupEvent::ResourceLimit { .. }
        )
    }

    /// 检查是否为正常处理事件
    pub fn is_normal_event(&self) -> bool {
        matches!(
            self,
            CleanupEvent::MessageId { .. }
                | CleanupEvent::MessageSize { .. }
                | CleanupEvent::HeaderProcessing { .. }
                | CleanupEvent::FilterAction { .. }
                | CleanupEvent::MessageDiscard { .. }
                | CleanupEvent::MessageRemoved { .. }
                | CleanupEvent::SnowflakeInit { .. }
        )
    }
}