nom_syslog/
parser.rs

1use nom;
2use time;
3
4use std::str::FromStr;
5
6use nom::{digit, rest_s, space};
7
8fn parse_month(s: &str) -> Result<i32, nom::simple_errors::Err> {
9    match s {
10        "Jan" => Ok(1),
11        "Feb" => Ok(2),
12        "Mar" => Ok(3),
13        "Apr" => Ok(4),
14        "May" => Ok(5),
15        "Jun" => Ok(6),
16        "Jul" => Ok(7),
17        "Aug" => Ok(8),
18        "Sep" => Ok(9),
19        "Oct" => Ok(10),
20        "Nov" => Ok(11),
21        "Dec" => Ok(12),
22        _ => Err(error_position!(
23            nom::ErrorKind::OneOf,
24            "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"
25        )),
26    }
27}
28
29named!(ts<&str,time::Tm>,
30    do_parse! (
31        month: map_res!(take!(3), parse_month) >>
32        space >>
33        day: map_res!(digit, FromStr::from_str) >>
34        space >>
35        hour: map_res!(digit, FromStr::from_str) >>
36        tag_s!(":") >>
37        minute: digit >>
38        tag_s!(":") >>
39        second: digit >>
40        ({
41          let mut tm = time::empty_tm();
42          tm.tm_mon = month;
43          tm.tm_mday = day;
44          tm.tm_hour = hour;
45          tm.tm_year = 2017 - 1900;
46          tm
47        })
48    )
49  );
50
51#[derive(Debug)]
52pub struct Syslog3164Message<'a> {
53    pub pri: &'a str,
54    pub ts: time::Tm,
55    pub host: &'a str,
56    pub tag: Option<(&'a str, Option<&'a str>)>,
57    pub msg: &'a str,
58}
59
60fn tag_delim(ch: char) -> bool {
61    ch == ' ' || ch == ':'
62}
63
64named!(parse_tag<&str, (&str,Option<&str>)>,
65        alt!(
66            do_parse!(
67                tag: take_until_s!("[") >>
68                tag_s!("[") >>
69                pid: take_until_s!("]") >>
70                tag_s!("]:") >>
71                (
72                    (tag,Some(pid))
73                )
74            ) |
75            do_parse!(
76                tag: take_till_s!(tag_delim) >>
77                tag_s!(":") >>
78                ({
79                    (tag,None)
80                })
81            )
82        )
83);
84
85#[test]
86fn parse_cisco_variation_1() {
87    use nom::IResult;
88    let msg1 = r##"<189>Dec 26 23:33:18 10.4.104.208 3890188: Dec 26 2017 23:33:17.792 UTC: %ADJ-5-RESOLVE_REQ_FAIL: Adj resolve request failed for 192.168.57.182 on Vlan55"##;
89    let res: IResult<&str, Syslog3164Message> = parse_syslog(msg1);
90    assert!(res.is_done());
91
92    let (_leftover, parsed) = res.unwrap();
93    assert_eq!(
94        parsed.msg,
95        "%ADJ-5-RESOLVE_REQ_FAIL: Adj resolve request failed for 192.168.57.182 on Vlan55"
96    );
97    assert_eq!(parsed.tag, Some(("3890188", None)));
98    assert_eq!(parsed.host, "10.4.104.208");
99    assert_eq!(parsed.ts.to_utc().to_timespec().sec, 1517007600)
100}
101
102// Dec 26 2017 23:33:17.792
103named!(better_ts<&str, time::Tm>,
104        do_parse!(
105            month: map_res!(take_s!(3), parse_month) >>
106            tag_s!(" ") >>
107            day: map_res!(take_s!(2), FromStr::from_str) >>
108            tag_s!(" ") >>
109            year: map_res!(take_s!(4), FromStr::from_str) >>
110            tag_s!(" ") >>
111            hour: map_res!(take_s!(2), FromStr::from_str) >>
112            tag_s!(":") >>
113            minute: map_res!(take_s!(2), FromStr::from_str) >>
114            tag_s!(":") >>
115            seconds: map_res!(take_s!(2), FromStr::from_str) >>
116            tag_s!(".") >>
117            millis: map_res!(take_s!(3), FromStr::from_str) >>
118            tag_s!(" UTC: ") >>
119            ({
120                let mut tm = time::empty_tm();
121
122                tm.tm_year = year;
123                tm.tm_year = tm.tm_year - 1900;
124                tm.tm_mon = month;
125                tm.tm_mday = day;
126                tm.tm_hour = hour;
127                tm.tm_min = minute;
128                tm.tm_sec = seconds;
129                tm.tm_nsec = millis;
130                tm.tm_nsec = tm.tm_nsec * 1000000;
131
132                tm
133            })
134        )
135);
136
137named!(pub parse_syslog<&str, Syslog3164Message>,
138    do_parse!(
139      tag_s!("<") >>
140      pri: digit >>
141      tag_s!(">") >>
142      ts: ts >>
143      space >>
144      host: take_until_s!(" ") >>
145      space >>
146      tag: opt!(parse_tag) >>
147      space >>
148      better_ts: opt!(better_ts) >>
149      msg: rest_s >>
150      (Syslog3164Message{pri: pri.into(),
151         ts: ts,
152         host: host.into(),
153         tag: tag,
154         msg: msg.into()
155       })
156    )
157  );
158
159#[test]
160fn parse_nx_win_evt() {
161    use nom::IResult;
162    let msg1 = r##"<14>Dec 13 17:45:02 SANTA-CLAUS-W764.blerg.com nxWinEvt[123]: {"EventTime":"🐌017-12-19 17:45:02","Hostname":"fake-hostname","Keywords":-9214364837600034816,"EventType":"AUDIT_SUCCESS","SeverityValue":2,"Severity":"INFO","EventID":4656,"SourceName":"Microsoft-Windows-Security-Auditing","ProviderGuid":"{54849625-5478-4994-A5BA-3E3B0328C30D}","Version":1,"Task":12804,"OpcodeValue":0,"RecordNumber":7613465324,"ProcessID":892,"ThreadID":908,"Channel":"Security","AccessReason":"-","AccessMask":"0x2","PrivilegeList":"-","RestrictedSidCount":"0","ProcessName":"C:\\Windows\\System32\\svchost.exe","EventReceivedTime":"2017-12-19 17:52:27","SourceModuleName":"eventlog","SourceModuleType":"im_msvistalog"}"##;
163    let res: IResult<&str, Syslog3164Message> = parse_syslog(msg1);
164    assert!(res.is_done());
165
166    let (_leftover, parsed) = res.unwrap();
167    assert_eq!(parsed.msg, &msg1[62..]);
168    assert_eq!(parsed.ts.to_utc().to_timespec().sec, 1515862800)
169}
170
171#[test]
172fn parse_nx_win_evt_pid_variation_1() {
173    use nom::IResult;
174    let msg1 = r##"<14>Dec 13 17:45:02 SANTA-CLAUS-W764.blerg.com nxWinEvt: {"EventTime":"2017-12-19 17:45:02","Hostname":"fake-hostname","Keywords":-9214364837600034816,"EventType":"AUDIT_SUCCESS","SeverityValue":2,"Severity":"INFO","EventID":4656,"SourceName":"Microsoft-Windows-Security-Auditing","ProviderGuid":"{54849625-5478-4994-A5BA-3E3B0328C30D}","Version":1,"Task":12804,"OpcodeValue":0,"RecordNumber":7613465324,"ProcessID":892,"ThreadID":908,"Channel":"Security","AccessReason":"-","AccessMask":"0x2","PrivilegeList":"-","RestrictedSidCount":"0","ProcessName":"C:\\Windows\\System32\\svchost.exe","EventReceivedTime":"2017-12-19 17:52:27","SourceModuleName":"eventlog","SourceModuleType":"im_msvistalog"}"##;
175    let res: IResult<&str, Syslog3164Message> = parse_syslog(msg1);
176    assert!(res.is_done());
177
178    let (_leftover, parsed) = res.unwrap();
179    assert_eq!(parsed.msg, &msg1[57..]);
180    assert_eq!(parsed.ts.to_utc().to_timespec().sec, 1515862800)
181}