diff --git a/src/main.rs b/src/main.rs index 9345f12..2b25120 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,14 @@ -use std::str::FromStr; - -use tokio_postgres::{Client, Config, NoTls, Statement}; - -use tokio::net::{TcpListener, TcpStream}; - -use std::net::SocketAddr; -use std::sync::Arc; - -use structopt::StructOpt; - -use std::collections::HashSet; - +use chrono::{DateTime, Local}; +use chrono::{Datelike, Month, NaiveDate, NaiveDateTime, NaiveTime, TimeZone}; use futures_util::FutureExt; use futures_util::StreamExt; +use std::collections::HashSet; +use std::net::SocketAddr; +use std::str::FromStr; +use std::sync::Arc; +use structopt::StructOpt; +use tokio::net::{TcpListener, TcpStream}; +use tokio_postgres::{Client, Config, NoTls, Statement}; type Error = Box; @@ -92,8 +88,6 @@ async fn main() -> Result<(), Error> { } } -use chrono::{DateTime, FixedOffset, Local}; - async fn handle_peer_and_error( stream: TcpStream, peer: SocketAddr, @@ -136,26 +130,38 @@ async fn handle_peer( Ok(()) } -/** parses a line, returning - * ( prio - * , time the log was recieved - * , time the log was written according to logger - * , name of the service that wrote the log - * , log entry - * ) - */ -fn parse_line( - line: &'_ str, -) -> Result< - ( - i16, - DateTime, - DateTime, - &'_ str, - &'_ str, - ), - Error, -> { +struct ParsedLine<'a> { + prio: i16, + rcvtime: DateTime, + logtime: DateTime, + // maybe this would be more correct, but i don't want to redo the database rn + //logtime: NaiveDateTime, + service: &'a str, + entry: &'a str, +} +#[test] +fn tst_timeparse() { + let input = "Jul 8 01:20:30"; + let year = 2022; + let parsed = parse_log_date(year, input).unwrap(); + assert_eq!( + parsed, + NaiveDateTime::parse_from_str("2022-07-08 01:20:30", "%Y-%m-%d %H:%M:%S").unwrap() + ) +} + +fn parse_log_date(year: i32, input: &'_ str) -> Result { + let mut parts = input.split(" ").map(|p| p.trim()).filter(|p| p.len() > 0); + let month = Month::from_str(parts.next().ok_or("no month")?) + .map_err(|e| format!("month parsing error: {:?}", e))?; + let day: u32 = parts.next().ok_or("no day")?.parse()?; + let date = + NaiveDate::from_ymd_opt(year, month.number_from_month(), day).ok_or("invalid day+moth")?; + let time = NaiveTime::parse_from_str(parts.next().ok_or("no time")?, "%H:%M:%S")?; + Ok(NaiveDateTime::new(date, time)) +} + +fn parse_line(line: &'_ str) -> Result, Error> { let mut prio_and_remainder = line.splitn(2, '>'); let prio = prio_and_remainder .next() @@ -170,13 +176,11 @@ fn parse_line( .expect("splitn should always return a second part"); let (date, line) = line.split_at(16); - // we need to prepend the current year and timezone, as that is not stated in the logfile - let now = chrono::Local::now(); - let mut base = format!("{}", now.format("%Y %z ")); - base.push_str(date); - - let date = DateTime::parse_from_str(&base, "%Y %z %b %e %H:%M:%S ") - .map_err(|e| format!("could not parse {}{} {}", date, line, e))?; + let rcvtime = chrono::Local::now(); + // we need to prepend the current year and add timezone, as that is not stated in the logfile + let logtime = parse_log_date(rcvtime.date_naive().year(), date) + .map_err(|e| format!("could not parse logtime {}{} {}", date, line, e))?; + let logtime = TimeZone::from_local_datetime(&Local, &logtime).unwrap(); let mut parts = line.splitn(2, ':'); @@ -187,6 +191,12 @@ fn parse_line( .ok_or("could not split pid from service")? .trim(); - let log = parts.next().ok_or("could not parse logfile")?.trim(); - Ok((prio, now, date, service, log)) + let entry = parts.next().ok_or("could not parse logfile")?.trim(); + Ok(ParsedLine { + prio, + rcvtime, + logtime, + service, + entry, + }) }