1
2 use chrono::prelude::*;
3 use syslog_loose::{parse_message,
4 parse_message_with_year,
5 IncompleteDate,
6 Message,
7 ProcId,
8 Protocol,
9 StructuredElement,
10 SyslogFacility,
11 SyslogSeverity};
12
with_year((month, _date, _hour, _min, _sec): IncompleteDate) -> i3213 fn with_year((month, _date, _hour, _min, _sec): IncompleteDate) -> i32 {
14 if month == 12 {
15 2019
16 } else {
17 2020
18 }
19 }
20
21 #[test]
parse_nginx()22 fn parse_nginx() {
23 // The nginx logs in 3164.
24 let msg = "<190>Dec 28 16:49:07 plertrood-thinkpad-x220 nginx: 127.0.0.1 - - [28/Dec/2019:16:49:07 +0000] \"GET / HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:71.0) Gecko/20100101 Firefox/71.0\"";
25
26 assert_eq!(
27 parse_message_with_year(msg, with_year),
28 Message {
29
30 facility: Some(SyslogFacility::LOG_LOCAL7),
31 severity: Some(SyslogSeverity::SEV_INFO),
32 timestamp: Some(FixedOffset::west(0).ymd(2019, 12, 28).and_hms(16, 49, 07)),
33 hostname: Some("plertrood-thinkpad-x220"),
34 appname: Some("nginx"),
35 procid: None,
36 msgid: None,
37 protocol: Protocol::RFC3164,
38 structured_data: vec![],
39 msg: "127.0.0.1 - - [28/Dec/2019:16:49:07 +0000] \"GET / HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:71.0) Gecko/20100101 Firefox/71.0\"",
40 }
41 );
42 }
43
44 #[test]
parse_rsyslog()45 fn parse_rsyslog() {
46 // rsyslog sends messages in 3164 with some structured data.
47 let msg = "<46>Jan 5 15:33:03 plertrood-ThinkPad-X220 rsyslogd: [origin software=\"rsyslogd\" swVersion=\"8.32.0\" x-pid=\"20506\" x-info=\"http://www.rsyslog.com\"] start";
48
49 assert_eq!(
50 parse_message_with_year(msg, with_year),
51 Message {
52 facility: Some(SyslogFacility::LOG_SYSLOG),
53 severity: Some(SyslogSeverity::SEV_INFO),
54 timestamp: Some(
55 FixedOffset::west(0)
56 .ymd(2020, 1, 5)
57 .and_hms_milli(15, 33, 3, 0)
58 ),
59 hostname: Some("plertrood-ThinkPad-X220"),
60 appname: Some("rsyslogd"),
61 procid: None,
62 msgid: None,
63 protocol: Protocol::RFC3164,
64 structured_data: vec![StructuredElement {
65 id: "origin",
66 params: vec![
67 ("software", "rsyslogd"),
68 ("swVersion", "8.32.0"),
69 ("x-pid", "20506"),
70 ("x-info", "http://www.rsyslog.com"),
71 ]
72 }],
73 msg: "start",
74 }
75 );
76 }
77
78 #[test]
parse_haproxy()79 fn parse_haproxy() {
80 // haproxy doesnt include the hostname.
81 let msg = "<133>Jan 13 16:33:35 haproxy[73411]: Proxy sticky-servers started.";
82 assert_eq!(
83 parse_message_with_year(msg, with_year),
84 Message {
85 facility: Some(SyslogFacility::LOG_LOCAL0),
86 severity: Some(SyslogSeverity::SEV_NOTICE),
87 timestamp: Some(
88 FixedOffset::west(0)
89 .ymd(2020, 1, 13)
90 .and_hms_milli(16, 33, 35, 0)
91 ),
92 hostname: None,
93 appname: Some("haproxy"),
94 procid: Some(ProcId::PID(73411)),
95 msgid: None,
96 protocol: Protocol::RFC3164,
97 structured_data: vec![],
98 msg: "Proxy sticky-servers started.",
99 }
100 );
101 }
102
103 #[test]
parse_5424_no_structured_data()104 fn parse_5424_no_structured_data() {
105 let msg = "<34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - BOM'su root' failed for lonvick on /dev/pts/8";
106
107 assert_eq!(
108 parse_message(msg),
109 Message {
110 facility: Some(SyslogFacility::LOG_AUTH),
111 severity: Some(SyslogSeverity::SEV_CRIT),
112 timestamp: Some(
113 FixedOffset::west(0)
114 .ymd(2003, 10, 11)
115 .and_hms_milli(22, 14, 15, 3)
116 ),
117 hostname: Some("mymachine.example.com"),
118 appname: Some("su"),
119 procid: None,
120 msgid: Some("ID47"),
121 protocol: Protocol::RFC5424(1),
122 structured_data: vec![],
123 msg: "BOM'su root' failed for lonvick on /dev/pts/8",
124 }
125 );
126 }
127
128 #[test]
parse_5424_structured_data()129 fn parse_5424_structured_data() {
130 let msg = "<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"] BOMAn application event log entry...";
131
132 assert_eq!(
133 parse_message(msg),
134 Message {
135 facility: Some(SyslogFacility::LOG_LOCAL4),
136 severity: Some(SyslogSeverity::SEV_NOTICE),
137 timestamp: Some(
138 FixedOffset::west(0)
139 .ymd(2003, 10, 11)
140 .and_hms_milli(22, 14, 15, 3)
141 ),
142 hostname: Some("mymachine.example.com"),
143 appname: Some("evntslog"),
144 procid: None,
145 msgid: Some("ID47"),
146 protocol: Protocol::RFC5424(1),
147 structured_data: vec![StructuredElement {
148 id: "exampleSDID@32473",
149 params: vec![
150 ("iut", "3"),
151 ("eventSource", "Application"),
152 ("eventID", "1011")
153 ]
154 },],
155 msg: "BOMAn application event log entry...",
156 }
157 );
158 }
159
160 #[test]
parse_5424_multiple_structured_data()161 fn parse_5424_multiple_structured_data() {
162 let msg = "<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut=\"3\" eventSource= \"Application\" eventID=\"1011\"][examplePriority@32473 class=\"high\"] BOMAn application event log entry...";
163
164 assert_eq!(
165 parse_message(msg),
166 Message {
167 facility: Some(SyslogFacility::LOG_LOCAL4),
168 severity: Some(SyslogSeverity::SEV_NOTICE),
169 timestamp: Some(
170 FixedOffset::west(0)
171 .ymd(2003, 10, 11)
172 .and_hms_milli(22, 14, 15, 3)
173 ),
174 hostname: Some("mymachine.example.com"),
175 appname: Some("evntslog"),
176 procid: None,
177 msgid: Some("ID47"),
178 protocol: Protocol::RFC5424(1),
179 structured_data: vec![
180 StructuredElement {
181 id: "exampleSDID@32473",
182 params: vec![
183 ("iut", "3"),
184 ("eventSource", "Application"),
185 ("eventID", "1011")
186 ]
187 },
188 StructuredElement {
189 id: "examplePriority@32473",
190 params: vec![("class", "high"),]
191 }
192 ],
193 msg: "BOMAn application event log entry...",
194 }
195 );
196 }
197
198 #[test]
parse_3164_invalid_structured_data()199 fn parse_3164_invalid_structured_data() {
200 // Can 3164 parse ok when there is something looking similar to structured data - but not quite.
201 // Remove the id from the rsyslog messages structured data. This should now go into the msg.
202 let msg = "<46>Jan 5 15:33:03 plertrood-ThinkPad-X220 rsyslogd: [software=\"rsyslogd\" swVersion=\"8.32.0\" x-pid=\"20506\" x-info=\"http://www.rsyslog.com\"] start";
203
204 assert_eq!(parse_message_with_year(msg, with_year),
205 Message {
206 facility: Some(SyslogFacility::LOG_SYSLOG),
207 severity: Some(SyslogSeverity::SEV_INFO),
208 timestamp: Some(
209 FixedOffset::west(0)
210 .ymd(2020, 1, 5)
211 .and_hms_milli(15, 33, 3, 0)
212 ),
213 hostname: Some("plertrood-ThinkPad-X220"),
214 appname: Some("rsyslogd"),
215 procid: None,
216 msgid: None,
217 protocol: Protocol::RFC3164,
218 structured_data: vec![],
219 msg: "start",
220 });
221 }
222
223 #[test]
parse_european_chars()224 fn parse_european_chars() {
225 let msg = "<46>Jan 5 10:01:00 Übergröße außerplanmäßig größenordnungsmäßig";
226
227 assert_eq!(
228 parse_message_with_year(msg, with_year),
229 Message {
230 facility: Some(SyslogFacility::LOG_SYSLOG),
231 severity: Some(SyslogSeverity::SEV_INFO),
232 timestamp: Some(
233 FixedOffset::west(0)
234 .ymd(2020, 1, 5)
235 .and_hms_milli(10, 1, 0, 0)
236 ),
237 hostname: Some("Übergröße"),
238 appname: Some("außerplanmäßig"),
239 procid: None,
240 msgid: None,
241 protocol: Protocol::RFC3164,
242 structured_data: vec![],
243 msg: "größenordnungsmäßig",
244 }
245 );
246 }
247
248 #[test]
parse_invalid_message()249 fn parse_invalid_message() {
250 let msg = "complete and utter gobbledegook";
251
252 assert_eq!(
253 parse_message_with_year(msg, with_year),
254 Message {
255 facility: None,
256 severity: None,
257 timestamp: None,
258 hostname: None,
259 appname: None,
260 procid: None,
261 msgid: None,
262 protocol: Protocol::RFC3164,
263 structured_data: vec![],
264 msg: "complete and utter gobbledegook",
265 }
266 );
267 }
268
269 #[test]
parse_blank_msg()270 fn parse_blank_msg() {
271 let ook = Message {
272 facility: Some(SyslogFacility::LOG_CRON),
273 severity: Some(SyslogSeverity::SEV_ERR),
274 timestamp: Some(
275 FixedOffset::west(0)
276 .ymd(1969, 12, 3)
277 .and_hms_milli(23, 58, 58, 0),
278 ),
279 hostname: None,
280 appname: None,
281 procid: None,
282 msgid: None,
283 protocol: Protocol::RFC5424(1),
284 structured_data: vec![],
285 msg: "",
286 };
287
288 println!("{}", ook);
289 let msg = format!("{}", ook);
290
291 assert_eq!(
292 parse_message(&msg),
293 Message {
294 facility: Some(SyslogFacility::LOG_CRON),
295 severity: Some(SyslogSeverity::SEV_ERR),
296 timestamp: Some(
297 FixedOffset::west(0)
298 .ymd(1969, 12, 3)
299 .and_hms_milli(23, 58, 58, 0),
300 ),
301 hostname: None,
302 appname: None,
303 procid: None,
304 msgid: None,
305 protocol: Protocol::RFC3164,
306 structured_data: vec![],
307 msg: "",
308 }
309 );
310 }
311
312
313
314 /*
315
316 The following tests have been taken from Vector (vector.dev)
317 https://github.com/timberio/vector/blob/fff92728c9490824ff9d0ae76669adc901bb5499/src/sources/syslog.rs
318
319 */
320
321 #[test]
syslog_ng_network_syslog_protocol()322 fn syslog_ng_network_syslog_protocol() {
323 let msg = "i am foobar";
324 let raw = format!(
325 r#"<13>1 2019-02-13T19:48:34+00:00 74794bfb6795 root 8449 - {}{} {}"#,
326 r#"[meta sequenceId="1" sysUpTime="37" language="EN"]"#,
327 r#"[origin ip="192.168.0.1" software="test"]"#,
328 msg
329 );
330
331 assert_eq!(
332 parse_message(&raw),
333 Message {
334 facility: Some(SyslogFacility::LOG_USER),
335 severity: Some(SyslogSeverity::SEV_NOTICE),
336 timestamp: Some(
337 FixedOffset::west(0)
338 .ymd(2019, 02, 13)
339 .and_hms_milli(19, 48, 34, 0)
340 ),
341 hostname: Some("74794bfb6795"),
342 appname: Some("root"),
343 procid: Some(ProcId::PID(8449)),
344 msgid: None,
345 protocol: Protocol::RFC5424(1),
346 structured_data: vec![
347 StructuredElement {
348 id: "meta",
349 params: vec![
350 ("sequenceId", "1"),
351 ("sysUpTime", "37"),
352 ("language", "EN")
353 ]
354 },
355 StructuredElement {
356 id: "origin",
357 params: vec![("ip", "192.168.0.1"),
358 ("software", "test"),
359 ]
360 }
361 ],
362 msg: "i am foobar",
363 }
364 )
365 }
366
367 #[test]
handles_incorrect_sd_element()368 fn handles_incorrect_sd_element() {
369 let msg = format!(
370 r#"<13>1 2019-02-13T19:48:34+00:00 74794bfb6795 root 8449 - {} qwerty"#,
371 r#"[incorrect x]"#
372 );
373
374 let should = Message {
375 facility: Some(SyslogFacility::LOG_USER),
376 severity: Some(SyslogSeverity::SEV_NOTICE),
377 timestamp: Some(
378 FixedOffset::west(0)
379 .ymd(2019, 02, 13)
380 .and_hms_milli(19, 48, 34, 0)
381 ),
382 hostname: Some("74794bfb6795"),
383 appname: Some("root"),
384 procid: Some(ProcId::PID(8449)),
385 msgid: None,
386 protocol: Protocol::RFC5424(1),
387 structured_data: vec![],
388 msg: "qwerty",
389 };
390
391 assert_eq!(
392 parse_message(&msg),
393 should
394 );
395
396 let msg = format!(
397 r#"<13>1 2019-02-13T19:48:34+00:00 74794bfb6795 root 8449 - {} qwerty"#,
398 r#"[incorrect x=]"#
399 );
400
401 assert_eq!(
402 parse_message(&msg),
403 should
404 );
405 }
406
407
408 #[test]
handles_empty_sd_element()409 fn handles_empty_sd_element() {
410 let msg = format!(
411 r#"<13>1 2019-02-13T19:48:34+00:00 74794bfb6795 root 8449 - {} qwerty"#,
412 r#"[empty]"#
413 );
414
415 assert_eq!(
416 parse_message(&msg),
417 Message {
418 facility: Some(SyslogFacility::LOG_USER),
419 severity: Some(SyslogSeverity::SEV_NOTICE),
420 timestamp: Some(
421 FixedOffset::west(0)
422 .ymd(2019, 02, 13)
423 .and_hms_milli(19, 48, 34, 0)
424 ),
425 hostname: Some("74794bfb6795"),
426 appname: Some("root"),
427 procid: Some(ProcId::PID(8449)),
428 msgid: None,
429 protocol: Protocol::RFC5424(1),
430 structured_data: vec![
431 StructuredElement {
432 id: "empty",
433 params: vec![]
434 }
435 ],
436 msg: "qwerty",
437 });
438
439 let msg = format!(
440 r#"<13>1 2019-02-13T19:48:34+00:00 74794bfb6795 root 8449 - {} qwerty"#,
441 r#"[non_empty x="1"][empty]"#
442 );
443
444 assert_eq!(
445 parse_message(&msg),
446 Message {
447 facility: Some(SyslogFacility::LOG_USER),
448 severity: Some(SyslogSeverity::SEV_NOTICE),
449 timestamp: Some(
450 FixedOffset::west(0)
451 .ymd(2019, 02, 13)
452 .and_hms_milli(19, 48, 34, 0)
453 ),
454 hostname: Some("74794bfb6795"),
455 appname: Some("root"),
456 procid: Some(ProcId::PID(8449)),
457 msgid: None,
458 protocol: Protocol::RFC5424(1),
459 structured_data: vec![
460 StructuredElement {
461 id: "non_empty",
462 params: vec![("x", "1")]
463 },
464 StructuredElement {
465 id: "empty",
466 params: vec![]
467 },
468 ],
469 msg: "qwerty",
470 });
471
472 let msg = format!(
473 r#"<13>1 2019-02-13T19:48:34+00:00 74794bfb6795 root 8449 - {} qwerty"#,
474 r#"[empty][non_empty x="1"]"#
475 );
476
477 assert_eq!(
478 parse_message(&msg),
479 Message {
480 facility: Some(SyslogFacility::LOG_USER),
481 severity: Some(SyslogSeverity::SEV_NOTICE),
482 timestamp: Some(
483 FixedOffset::west(0)
484 .ymd(2019, 02, 13)
485 .and_hms_milli(19, 48, 34, 0)
486 ),
487 hostname: Some("74794bfb6795"),
488 appname: Some("root"),
489 procid: Some(ProcId::PID(8449)),
490 msgid: None,
491 protocol: Protocol::RFC5424(1),
492 structured_data: vec![
493 StructuredElement {
494 id: "empty",
495 params: vec![]
496 },
497 StructuredElement {
498 id: "non_empty",
499 params: vec![("x", "1")]
500 },
501 ],
502 msg: "qwerty",
503 });
504
505 let msg = format!(
506 r#"<13>1 2019-02-13T19:48:34+00:00 74794bfb6795 root 8449 - {} qwerty"#,
507 r#"[empty not_really="testing the test"]"#
508 );
509
510 assert_eq!(
511 parse_message(&msg),
512 Message {
513 facility: Some(SyslogFacility::LOG_USER),
514 severity: Some(SyslogSeverity::SEV_NOTICE),
515 timestamp: Some(
516 FixedOffset::west(0)
517 .ymd(2019, 02, 13)
518 .and_hms_milli(19, 48, 34, 0)
519 ),
520 hostname: Some("74794bfb6795"),
521 appname: Some("root"),
522 procid: Some(ProcId::PID(8449)),
523 msgid: None,
524 protocol: Protocol::RFC5424(1),
525 structured_data: vec![
526 StructuredElement {
527 id: "empty",
528 params: vec![("not_really", "testing the test")]
529 },
530 ],
531 msg: "qwerty",
532 });
533
534 }
535
536 #[test]
handles_weird_whitespace()537 fn handles_weird_whitespace() {
538 // this should also match rsyslog omfwd with template=RSYSLOG_SyslogProtocol23Format
539 let raw = r#"
540 <13>1 2019-02-13T19:48:34+00:00 74794bfb6795 root 8449 - [meta sequenceId="1"] i am foobar
541 "#;
542 let cleaned = r#"<13>1 2019-02-13T19:48:34+00:00 74794bfb6795 root 8449 - [meta sequenceId="1"] i am foobar"#;
543
544 assert_eq!(
545 parse_message(&raw),
546 parse_message(&cleaned)
547 );
548 }
549
550
551 #[test]
syslog_ng_default_network()552 fn syslog_ng_default_network() {
553 let raw = r#"<13>Feb 13 20:07:26 74794bfb6795 root[8539]: i am foobar"#;
554
555 assert_eq!(
556 parse_message_with_year(&raw, with_year),
557 Message {
558 facility: Some(SyslogFacility::LOG_USER),
559 severity: Some(SyslogSeverity::SEV_NOTICE),
560 timestamp: Some(
561 FixedOffset::west(0)
562 .ymd(2020, 02, 13)
563 .and_hms(20, 07, 26)
564 ),
565 hostname: Some("74794bfb6795"),
566 appname: Some("root"),
567 procid: Some(ProcId::PID(8539)),
568 msgid: None,
569 protocol: Protocol::RFC3164,
570 structured_data: vec![],
571 msg: "i am foobar",
572 }
573 );
574 }
575
576 #[test]
rsyslog_omfwd_tcp_default()577 fn rsyslog_omfwd_tcp_default() {
578 let raw = r#"<190>Feb 13 21:31:56 74794bfb6795 liblogging-stdlog: [origin software="rsyslogd" swVersion="8.24.0" x-pid="8979" x-info="http://www.rsyslog.com"] start"#;
579
580 assert_eq!(
581 parse_message_with_year(&raw, with_year),
582 Message {
583 facility: Some(SyslogFacility::LOG_LOCAL7),
584 severity: Some(SyslogSeverity::SEV_INFO),
585 timestamp: Some(
586 FixedOffset::west(0)
587 .ymd(2020, 02, 13)
588 .and_hms(21, 31, 56)
589 ),
590 hostname: Some("74794bfb6795"),
591 appname: Some("liblogging-stdlog"),
592 procid: None,
593 msgid: None,
594 protocol: Protocol::RFC3164,
595 structured_data: vec![
596 StructuredElement {
597 id: "origin",
598 params: vec![("software", "rsyslogd"),
599 ("swVersion", "8.24.0"),
600 ("x-pid", "8979"),
601 ("x-info", "http://www.rsyslog.com")]
602 }],
603 msg: "start",
604 }
605 );
606 }
607
608 #[test]
rsyslog_omfwd_tcp_forward_format()609 fn rsyslog_omfwd_tcp_forward_format() {
610 let raw = r#"<190>2019-02-13T21:53:30.605850+00:00 74794bfb6795 liblogging-stdlog: [origin software="rsyslogd" swVersion="8.24.0" x-pid="9043" x-info="http://www.rsyslog.com"] start"#;
611
612 assert_eq!(
613 parse_message_with_year(&raw, with_year),
614 Message {
615 facility: Some(SyslogFacility::LOG_LOCAL7),
616 severity: Some(SyslogSeverity::SEV_INFO),
617 timestamp: Some(
618 FixedOffset::west(0)
619 .ymd(2019, 02, 13)
620 .and_hms_micro(21, 53, 30, 605_850)
621 ),
622 hostname: Some("74794bfb6795"),
623 appname: Some("liblogging-stdlog"),
624 procid: None,
625 msgid: None,
626 protocol: Protocol::RFC3164,
627 structured_data: vec![
628 StructuredElement {
629 id: "origin",
630 params: vec![("software", "rsyslogd"),
631 ("swVersion", "8.24.0"),
632 ("x-pid", "8979"),
633 ("x-info", "http://www.rsyslog.com")]
634 }],
635 msg: "start",
636 }
637 );
638 }
639
640 #[test]
logical_system_juniper_routers()641 fn logical_system_juniper_routers() {
642 let raw = r#"<28>1 2020-05-22T14:59:09.250-03:00 OX-XXX-MX204 OX-XXX-CONTEUDO:rpd 6589 - - bgp_listen_accept: %DAEMON-4: Connection attempt from unconfigured neighbor: 2001:XXX::219:166+57284"#;
643
644 assert_eq!(
645 parse_message_with_year(&raw, with_year),
646 Message {
647 facility: Some(SyslogFacility::LOG_DAEMON),
648 severity: Some(SyslogSeverity::SEV_WARNING),
649 timestamp: Some(
650 FixedOffset::west(1800 * 6)
651 .ymd(2020, 05, 22)
652 .and_hms_micro(14, 59, 09, 250000)
653 ),
654 hostname: Some("OX-XXX-MX204"),
655 appname: Some("OX-XXX-CONTEUDO:rpd"),
656 procid: Some(ProcId::PID(6589)),
657 msgid: None,
658 protocol: Protocol::RFC5424(1),
659 structured_data: vec![],
660 msg: "bgp_listen_accept: %DAEMON-4: Connection attempt from unconfigured neighbor: 2001:XXX::219:166+57284",
661 }
662 );
663 }
664