use crate::components::ComponentParser;
use crate::error::ParseError;
use crate::events::error::{ErrorEvent, ErrorType};
use crate::events::ComponentEvent;
use crate::utils::queue_id::{create_queue_id_pattern, extract_queue_id};
use lazy_static::lazy_static;
use regex::Regex;
pub struct ErrorParser;
lazy_static! {
static ref DELIVERY_DEFERRED_REGEX: Regex = Regex::new(
&create_queue_id_pattern(r"^{QUEUE_ID}: to=<([^>]+)>, relay=([^,]+), delay=([\d.]+), delays=([\d./]+), dsn=([\d.]+), status=deferred \((.+)\)$")
).unwrap();
static ref DELIVERY_FAILED_REGEX: Regex = Regex::new(
&create_queue_id_pattern(r"^{QUEUE_ID}: to=<([^>]+)>, relay=([^,]+), delay=([\d.]+), delays=([\d./]+), dsn=([\d.]+), status=bounced \((.+)\)$")
).unwrap();
static ref CONNECTION_ERROR_REGEX: Regex = Regex::new(
&create_queue_id_pattern(r"^{QUEUE_ID}: (.+)$")
).unwrap();
static ref SYSTEM_ERROR_REGEX: Regex = Regex::new(
r"^(warning|error|fatal|panic):\s+(.+)$"
).unwrap();
static ref NO_QUEUE_ERROR_REGEX: Regex = Regex::new(
r"^(.+)$"
).unwrap();
}
impl ErrorParser {
pub fn new() -> Self {
Self
}
fn parse_delivery_deferred(&self, message: &str) -> Option<ErrorEvent> {
if let Some(captures) = DELIVERY_DEFERRED_REGEX.captures(message) {
let queue_id = captures.get(1)?.as_str().to_string();
let to = captures.get(2)?.as_str().to_string();
let relay = captures.get(3)?.as_str().to_string();
let delay = captures.get(4)?.as_str().parse::<f64>().ok()?;
let delays = captures.get(5)?.as_str().to_string();
let dsn = captures.get(6)?.as_str().to_string();
let reason = captures.get(7)?.as_str().to_string();
let error_type = ErrorType::from_reason(&reason);
return Some(ErrorEvent::DeliveryDeferred {
queue_id,
to,
relay,
delay,
delays,
dsn,
status: "deferred".to_string(),
reason,
error_type,
});
}
None
}
fn parse_delivery_failed(&self, message: &str) -> Option<ErrorEvent> {
if let Some(captures) = DELIVERY_FAILED_REGEX.captures(message) {
let queue_id = captures.get(1)?.as_str().to_string();
let to = captures.get(2)?.as_str().to_string();
let relay = captures.get(3)?.as_str().to_string();
let delay = captures.get(4)?.as_str().parse::<f64>().ok()?;
let delays = captures.get(5)?.as_str().to_string();
let dsn = captures.get(6)?.as_str().to_string();
let reason = captures.get(7)?.as_str().to_string();
let error_type = ErrorType::from_reason(&reason);
return Some(ErrorEvent::DeliveryFailed {
queue_id,
to,
relay,
delay,
delays,
dsn,
status: "bounced".to_string(),
reason,
error_type,
});
}
None
}
fn parse_connection_error(&self, message: &str) -> Option<ErrorEvent> {
if message.contains("status=deferred") || message.contains("status=bounced") {
return None;
}
if let Some(captures) = CONNECTION_ERROR_REGEX.captures(message) {
let queue_id = captures.get(1)?.as_str().to_string();
let error_message = captures.get(2)?.as_str().to_string();
if error_message.contains("connect to") || error_message.contains("lost connection") {
let error_type = ErrorType::from_reason(&error_message);
return Some(ErrorEvent::ConnectionError {
queue_id,
to: "".to_string(), relay: "".to_string(),
delay: 0.0,
delays: "".to_string(),
dsn: "".to_string(),
reason: error_message,
error_type,
});
}
}
None
}
fn parse_system_error(&self, message: &str) -> Option<ErrorEvent> {
if let Some(captures) = SYSTEM_ERROR_REGEX.captures(message) {
let _level = captures.get(1)?.as_str();
let error_message = captures.get(2)?.as_str().to_string();
let error_type = ErrorType::from_reason(&error_message);
return Some(ErrorEvent::SystemError {
queue_id: None,
error_type,
message: error_message,
});
}
None
}
fn parse_other_error(&self, message: &str) -> Option<ErrorEvent> {
let queue_id = extract_queue_id(message);
Some(ErrorEvent::Other {
queue_id,
error_type: "unclassified".to_string(),
message: message.to_string(),
})
}
}
impl ComponentParser for ErrorParser {
fn parse(&self, message: &str) -> Result<ComponentEvent, ParseError> {
if let Some(event) = self.parse_delivery_deferred(message) {
return Ok(ComponentEvent::Error(event));
}
if let Some(event) = self.parse_delivery_failed(message) {
return Ok(ComponentEvent::Error(event));
}
if let Some(event) = self.parse_connection_error(message) {
return Ok(ComponentEvent::Error(event));
}
if let Some(event) = self.parse_system_error(message) {
return Ok(ComponentEvent::Error(event));
}
if let Some(event) = self.parse_other_error(message) {
return Ok(ComponentEvent::Error(event));
}
Err(ParseError::ComponentParseError {
component: "error".to_string(),
reason: format!("无法解析消息: {}", message),
})
}
fn component_name(&self) -> &'static str {
"error"
}
}
impl Default for ErrorParser {
fn default() -> Self {
Self::new()
}
}