tarpit-log-parser 0.2.1

library to parse tarpit log files
Documentation
use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use nom::branch::alt;
use nom::bytes::complete::{tag, take_until};
use nom::character::complete::{char, i32, not_line_ending, space1, u16, u32, u8};
use nom::combinator::{map, map_parser};
use nom::multi::separated_list1;
use nom::sequence::{delimited, preceded, separated_pair, tuple};
use nom::IResult;
use std::net::{Ipv4Addr, SocketAddrV4};

use crate::{Action, LogLevel, TarpitLogEntry};

pub(crate) fn parse_date(input: &str) -> IResult<&str, NaiveDate> {
    map(
        tuple((i32, char('-'), u32, char('-'), u32)),
        |(year, _, month, _, day)| NaiveDate::from_ymd_opt(year, month, day).expect("invalid date"),
    )(input)
}

pub(crate) fn parse_timestamp(input: &str) -> IResult<&str, NaiveTime> {
    map(
        tuple((u32, char(':'), u32, char(':'), u32)),
        |(hour, _, minute, _, second)| {
            NaiveTime::from_hms_opt(hour, minute, second).expect("invalid timestamp.")
        },
    )(input)
}

pub(crate) fn parse_datetime(input: &str) -> IResult<&str, NaiveDateTime> {
    map(
        separated_pair(parse_date, space1, parse_timestamp),
        |(date, time)| NaiveDateTime::new(date, time),
    )(input)
}

pub(crate) fn parse_log_level(input: &str) -> IResult<&str, LogLevel> {
    alt((
        map(tag("TRACE"), |_| LogLevel::Trace),
        map(tag("DEBUG"), |_| LogLevel::Debug),
        map(tag("INFO"), |_| LogLevel::Info),
        map(tag("WARN"), |_| LogLevel::Warn),
        map(tag("ERROR"), |_| LogLevel::Error),
    ))(input)
}

pub(crate) fn parse_ipv4(input: &str) -> IResult<&str, Ipv4Addr> {
    map(
        tuple((u8, char('.'), u8, char('.'), u8, char('.'), u8)),
        |(u1, _, u2, _, u3, _, u4)| Ipv4Addr::new(u1, u2, u3, u4),
    )(input)
}

pub(crate) fn parse_port(input: &str) -> IResult<&str, u16> {
    u16(input)
}

pub(crate) fn parse_socket_addr(input: &str) -> IResult<&str, SocketAddrV4> {
    map(
        delimited(
            tag("('"),
            separated_pair(parse_ipv4, tag("', "), parse_port),
            char(')'),
        ),
        |(addr, port)| SocketAddrV4::new(addr, port),
    )(input)
}

pub(crate) fn parse_action(input: &str) -> IResult<&str, Action> {
    alt((
        map(tag("disconnected"), |_| Action::Disconnect),
        map(tag("connected"), |_| Action::Connect),
    ))(input)
}

pub(crate) fn parse_log_message(input: &str) -> IResult<&str, (String, String)> {
    map(
        separated_pair(
            take_until(":"),
            tag(": "),
            separated_list1(space1, not_line_ending),
        ),
        |(issuer, message): (&str, Vec<&str>)| (issuer.to_owned(), message.join(" ")),
    )(input)
}

pub(crate) fn parse_log_line(input: &str) -> IResult<&str, TarpitLogEntry> {
    let (rest, (timestamp, log_level)) =
        separated_pair(parse_datetime, space1, parse_log_level)(input)?;
    let (rest, _) = space1(rest)?;
    alt((
        map(
            preceded(
                take_until("("),
                separated_pair(parse_socket_addr, space1, parse_action),
            ),
            move |(ip, action)| TarpitLogEntry::Event {
                timestamp,
                ip,
                action,
                log_level,
            },
        ),
        map(
            map_parser(not_line_ending, parse_log_message),
            move |(issuer, message)| TarpitLogEntry::Message {
                timestamp,
                log_level,
                issuer: issuer.to_owned(),
                message: message.to_owned(),
            },
        ),
    ))(rest)
}