postfix-log-parser 0.2.0

高性能模块化Postfix日志解析器,经3.2GB生产数据验证,SMTPD事件100%准确率
Documentation
//! Anvil连接计数器和统计模块
//!
//! 处理Postfix anvil守护进程的事件,包括连接统计、速率限制和配置警告

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

/// Anvil连接计数器事件
///
/// 记录Postfix anvil服务的连接统计和配置警告信息
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AnvilEvent {
    /// 事件发生时间戳(UTC时间)
    pub timestamp: DateTime<Utc>,

    /// 进程ID(可选)
    /// anvil进程的系统标识符,某些情况下可能为空
    pub pid: Option<u32>,

    /// 事件类型(配置警告或统计信息)
    pub event_type: AnvilEventType,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum AnvilEventType {
    ConfigWarning {
        file_path: String,
        line_number: u32,
        parameter_name: String,
        message: String,
    },
    Statistics {
        metric_type: StatisticType,
        value: u32,
        rate_window: Option<String>, // e.g., "/60s"
        service_client: String,
        timestamp: DateTime<Utc>,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum StatisticType {
    MaxConnectionRate,
    MaxConnectionCount,
    MaxMessageRate,
    MaxCacheSize,
}

impl AnvilEvent {
    pub fn new(timestamp: DateTime<Utc>, pid: Option<u32>, event_type: AnvilEventType) -> Self {
        Self {
            timestamp,
            pid,
            event_type,
        }
    }

    pub fn config_warning(
        timestamp: DateTime<Utc>,
        pid: Option<u32>,
        file_path: String,
        line_number: u32,
        parameter_name: String,
        message: String,
    ) -> Self {
        Self::new(
            timestamp,
            pid,
            AnvilEventType::ConfigWarning {
                file_path,
                line_number,
                parameter_name,
                message,
            },
        )
    }

    pub fn statistics(
        timestamp: DateTime<Utc>,
        pid: Option<u32>,
        metric_type: StatisticType,
        value: u32,
        rate_window: Option<String>,
        service_client: String,
        metric_timestamp: DateTime<Utc>,
    ) -> Self {
        Self::new(
            timestamp,
            pid,
            AnvilEventType::Statistics {
                metric_type,
                value,
                rate_window,
                service_client,
                timestamp: metric_timestamp,
            },
        )
    }

    /// Get a human-readable description of the event
    pub fn description(&self) -> String {
        match &self.event_type {
            AnvilEventType::ConfigWarning {
                file_path,
                line_number,
                parameter_name,
                message,
            } => {
                format!(
                    "Config warning in {}:{} for {}: {}",
                    file_path, line_number, parameter_name, message
                )
            }
            AnvilEventType::Statistics {
                metric_type,
                value,
                rate_window,
                service_client,
                ..
            } => {
                let metric_name = match metric_type {
                    StatisticType::MaxConnectionRate => "connection rate",
                    StatisticType::MaxConnectionCount => "connection count",
                    StatisticType::MaxMessageRate => "message rate",
                    StatisticType::MaxCacheSize => "cache size",
                };

                if let Some(window) = rate_window {
                    format!(
                        "Max {} {}{} for {}",
                        metric_name, value, window, service_client
                    )
                } else {
                    format!("Max {} {} for {}", metric_name, value, service_client)
                }
            }
        }
    }

    /// Get event severity for monitoring/alerting
    pub fn severity(&self) -> &'static str {
        match &self.event_type {
            AnvilEventType::ConfigWarning { .. } => "warning",
            AnvilEventType::Statistics { .. } => "info",
        }
    }
}