fail2ban_log_parser_core/lib.rs
1#![warn(clippy::pedantic)]
2
3pub use crate::parser::{Fail2BanEvent, Fail2BanHeaderType, Fail2BanLevel, Fail2BanStructuredLog};
4use std::fmt;
5
6mod parser;
7
8/// Error returned when a log line fails to parse.
9#[derive(Debug, Clone)]
10pub struct ParseError {
11 pub line_number: usize,
12 pub line: String,
13}
14
15impl fmt::Display for ParseError {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 write!(
18 f,
19 "failed to parse line {}: {}",
20 self.line_number, self.line
21 )
22 }
23}
24
25impl std::error::Error for ParseError {}
26
27/// Parse fail2ban log input. Returns a lazy iterator over parse results.
28///
29/// Each line yields `Ok(Fail2BanStructuredLog)` on success or `Err(ParseError)` on failure.
30///
31/// # Examples
32///
33/// Parse a single line:
34/// ```ignore
35/// let log = parse("2024-01-01 12:00:00,123 fail2ban.filter: INFO [sshd] ...").next();
36/// ```
37///
38/// Parse an entire file, skipping errors:
39/// ```ignore
40/// let content = std::fs::read_to_string("fail2ban.log").unwrap();
41/// for log in parse(&content).flatten() {
42/// println!("{:?}", log.jail());
43/// }
44/// ```
45///
46/// Collect all errors:
47/// ```ignore
48/// let content = std::fs::read_to_string("fail2ban.log").unwrap();
49/// let (ok, err): (Vec<_>, Vec<_>) = parse(&content).partition(Result::is_ok);
50/// ```
51pub fn parse(
52 input: &str,
53) -> impl Iterator<Item = Result<Fail2BanStructuredLog<'_>, ParseError>> + '_ {
54 input.lines().enumerate().map(|(i, line)| {
55 parser::parse_log_line(&mut &*line).map_err(|_| ParseError {
56 line_number: i + 1,
57 line: line.to_string(),
58 })
59 })
60}