postfix_log_parser/events/
anvil.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
5pub struct AnvilEvent {
6    pub timestamp: DateTime<Utc>,
7    pub pid: Option<u32>,
8    pub event_type: AnvilEventType,
9}
10
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
12pub enum AnvilEventType {
13    ConfigWarning {
14        file_path: String,
15        line_number: u32,
16        parameter_name: String,
17        message: String,
18    },
19    Statistics {
20        metric_type: StatisticType,
21        value: u32,
22        rate_window: Option<String>, // e.g., "/60s"
23        service_client: String,
24        timestamp: DateTime<Utc>,
25    },
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
29pub enum StatisticType {
30    MaxConnectionRate,
31    MaxConnectionCount,
32    MaxMessageRate,
33    MaxCacheSize,
34}
35
36impl AnvilEvent {
37    pub fn new(timestamp: DateTime<Utc>, pid: Option<u32>, event_type: AnvilEventType) -> Self {
38        Self {
39            timestamp,
40            pid,
41            event_type,
42        }
43    }
44
45    pub fn config_warning(
46        timestamp: DateTime<Utc>,
47        pid: Option<u32>,
48        file_path: String,
49        line_number: u32,
50        parameter_name: String,
51        message: String,
52    ) -> Self {
53        Self::new(
54            timestamp,
55            pid,
56            AnvilEventType::ConfigWarning {
57                file_path,
58                line_number,
59                parameter_name,
60                message,
61            },
62        )
63    }
64
65    pub fn statistics(
66        timestamp: DateTime<Utc>,
67        pid: Option<u32>,
68        metric_type: StatisticType,
69        value: u32,
70        rate_window: Option<String>,
71        service_client: String,
72        metric_timestamp: DateTime<Utc>,
73    ) -> Self {
74        Self::new(
75            timestamp,
76            pid,
77            AnvilEventType::Statistics {
78                metric_type,
79                value,
80                rate_window,
81                service_client,
82                timestamp: metric_timestamp,
83            },
84        )
85    }
86
87    /// Get a human-readable description of the event
88    pub fn description(&self) -> String {
89        match &self.event_type {
90            AnvilEventType::ConfigWarning {
91                file_path,
92                line_number,
93                parameter_name,
94                message,
95            } => {
96                format!(
97                    "Config warning in {}:{} for {}: {}",
98                    file_path, line_number, parameter_name, message
99                )
100            }
101            AnvilEventType::Statistics {
102                metric_type,
103                value,
104                rate_window,
105                service_client,
106                ..
107            } => {
108                let metric_name = match metric_type {
109                    StatisticType::MaxConnectionRate => "connection rate",
110                    StatisticType::MaxConnectionCount => "connection count",
111                    StatisticType::MaxMessageRate => "message rate",
112                    StatisticType::MaxCacheSize => "cache size",
113                };
114
115                if let Some(window) = rate_window {
116                    format!(
117                        "Max {} {}{} for {}",
118                        metric_name, value, window, service_client
119                    )
120                } else {
121                    format!("Max {} {} for {}", metric_name, value, service_client)
122                }
123            }
124        }
125    }
126
127    /// Get event severity for monitoring/alerting
128    pub fn severity(&self) -> &'static str {
129        match &self.event_type {
130            AnvilEventType::ConfigWarning { .. } => "warning",
131            AnvilEventType::Statistics { .. } => "info",
132        }
133    }
134}