2020-09-22 18:45:16 +00:00
/ *
Copyright 2020 mark . nellemann @gmail.com
Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an " AS IS " BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2020-09-22 18:33:22 +00:00
package biz.nellemann.syslogd ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2021-01-27 00:29:38 +00:00
import java.text.ParseException ;
import java.text.SimpleDateFormat ;
2020-09-22 18:33:22 +00:00
import java.time.* ;
import java.time.format.DateTimeFormatter ;
import java.time.format.DateTimeParseException ;
2021-01-27 00:29:38 +00:00
import java.util.Arrays ;
import java.util.List ;
2020-09-22 18:33:22 +00:00
import java.util.regex.Matcher ;
import java.util.regex.Pattern ;
public class SyslogParser {
private final static Logger log = LoggerFactory . getLogger ( SyslogParser . class ) ;
2020-10-07 09:53:16 +00:00
/ * *
* Parses [ rfc3164 ] ( https : //tools.ietf.org/html/rfc3164) syslog messages.
*
* @param input
* @return
* @throws NumberFormatException
* /
2020-10-05 08:40:42 +00:00
public static SyslogMessage parseRfc3164 ( final String input ) throws NumberFormatException {
2020-09-22 18:33:22 +00:00
2020-10-06 03:33:08 +00:00
Pattern pattern = Pattern . compile ( " ^<( \\ d{1,3})>( \\ D{3} \\ s+ \\ d{1,2} \\ d{2}: \\ d{2}: \\ d{2}) \\ s+(Message forwarded from \\ S+:| \\ S+) \\ s+([^ \\ s:]+):? \\ s+(.*) " , Pattern . CASE_INSENSITIVE ) ;
2020-09-22 18:33:22 +00:00
Matcher matcher = pattern . matcher ( input ) ;
boolean matchFound = matcher . find ( ) ;
if ( ! matchFound ) {
2020-10-06 03:10:19 +00:00
//log.warn("parseRfc3164() - Match not found in: ");
System . err . println ( " ! " + input ) ;
2020-09-22 18:33:22 +00:00
return null ;
}
2020-10-06 03:10:19 +00:00
String pri = matcher . group ( 1 ) ;
String date = matcher . group ( 2 ) ;
String hostname = matcher . group ( 3 ) ;
String application = matcher . group ( 4 ) ;
2020-10-07 09:53:16 +00:00
String msg = matcher . group ( 5 ) ;
2020-09-22 18:33:22 +00:00
2020-10-06 03:10:19 +00:00
if ( hostname . endsWith ( " : " ) ) {
String [ ] tmp = hostname . split ( " " ) ;
hostname = tmp [ tmp . length - 1 ] ;
hostname = hostname . substring ( 0 , hostname . length ( ) - 1 ) ;
}
2020-09-22 18:33:22 +00:00
2020-09-23 08:52:52 +00:00
Integer facility = getFacility ( pri ) ;
Integer severity = getSeverity ( pri ) ;
2020-09-22 18:33:22 +00:00
2020-10-07 09:53:16 +00:00
SyslogMessage syslogMessage = new SyslogMessage ( msg . trim ( ) ) ;
2020-09-23 08:52:52 +00:00
syslogMessage . facility = Facility . getByNumber ( facility ) ;
syslogMessage . severity = Severity . getByNumber ( severity ) ;
2020-09-22 18:33:22 +00:00
syslogMessage . timestamp = parseRfc3164Timestamp ( date ) ;
syslogMessage . hostname = hostname ;
syslogMessage . application = application ;
return syslogMessage ;
}
2020-10-07 09:53:16 +00:00
/ * *
* Parses [ rfc5424 ] ( https : //tools.ietf.org/html/rfc5424) syslog messages.
*
* @param input
* @return
* @throws NumberFormatException
* /
2020-10-05 08:40:42 +00:00
public static SyslogMessage parseRfc5424 ( final String input ) throws NumberFormatException {
2020-09-22 18:33:22 +00:00
2021-01-27 00:29:38 +00:00
log . warn ( " parseRfc5424() " + input ) ;
// "<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts."
// '<13>1 2020-09-23T08:57:30.950699+02:00 xps13 mark - - [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"] adfdfdf3432434565656'
Pattern pattern = Pattern . compile ( " ^<( \\ d{1,3})>( \\ d+) \\ s+( \\ S+) \\ s+( \\ S+) \\ s+( \\ S+) \\ s+( \\ S+) \\ s+( \\ S+) \\ s+( \\ [.* \\ ]|-) \\ s+( \\ S+) " , Pattern . CASE_INSENSITIVE ) ;
2020-09-22 18:33:22 +00:00
Matcher matcher = pattern . matcher ( input ) ;
boolean matchFound = matcher . find ( ) ;
if ( ! matchFound ) {
2021-01-27 00:29:38 +00:00
log . debug ( " parseRfc5424() - Match not found in: " + input ) ;
2020-10-06 03:10:19 +00:00
System . err . println ( " ! " + input ) ;
2020-09-22 18:33:22 +00:00
return null ;
}
2020-10-07 09:53:16 +00:00
String pri = matcher . group ( 1 ) ;
String ver = matcher . group ( 2 ) ;
String date = matcher . group ( 3 ) ;
String host = matcher . group ( 4 ) ;
String app = matcher . group ( 5 ) ;
String procId = matcher . group ( 6 ) ;
String msgId = matcher . group ( 7 ) ;
String data = matcher . group ( 8 ) ;
String msg = matcher . group ( 9 ) ;
2020-09-22 18:33:22 +00:00
2020-09-23 08:52:52 +00:00
Integer facility = getFacility ( pri ) ;
Integer severity = getSeverity ( pri ) ;
2020-09-22 18:33:22 +00:00
2020-10-05 15:59:31 +00:00
SyslogMessage syslogMessage = new SyslogMessage ( msg . trim ( ) ) ;
2020-09-23 08:52:52 +00:00
syslogMessage . facility = Facility . getByNumber ( facility ) ;
syslogMessage . severity = Severity . getByNumber ( severity ) ;
2020-09-22 18:33:22 +00:00
syslogMessage . version = Integer . parseInt ( ver ) ;
syslogMessage . timestamp = parseRfc5424Timestamp ( date ) ;
syslogMessage . hostname = host ;
if ( app ! = null & & ! app . equals ( " - " ) )
syslogMessage . application = app ;
if ( procId ! = null & & ! procId . equals ( " - " ) )
syslogMessage . processId = procId ;
if ( msgId ! = null & & ! msgId . equals ( " - " ) )
syslogMessage . messageId = msgId ;
2021-01-27 00:29:38 +00:00
if ( data ! = null & & ! data . equals ( " - " ) )
syslogMessage . structuredData = data ;
2020-09-22 18:33:22 +00:00
return syslogMessage ;
}
2020-10-07 09:53:16 +00:00
/ * *
* Parse rfc3164 TIMESTAMP field into Instant .
*
* @param dateString
* @return
* /
2020-09-22 18:33:22 +00:00
static protected Instant parseRfc3164Timestamp ( String dateString ) {
// We need to add year to parse date correctly
2020-09-23 05:01:55 +00:00
OffsetDateTime odt = OffsetDateTime . now ( ) ;
2020-09-22 18:33:22 +00:00
// Date: Mmm dd hh:mm:ss
Instant instant = null ;
try {
2020-10-05 15:59:31 +00:00
DateTimeFormatter dateTimeFormatter = DateTimeFormatter . ofPattern ( " yyyy MMM [ ]d HH:mm:ss " ) . withZone ( ZoneOffset . UTC ) ;
2020-09-23 05:01:55 +00:00
instant = Instant . from ( dateTimeFormatter . parse ( odt . getYear ( ) + " " + dateString ) ) ;
2020-09-22 18:33:22 +00:00
} catch ( DateTimeParseException e ) {
log . error ( " parseDate() " , e ) ;
}
return instant ;
}
2020-10-07 09:53:16 +00:00
/ * *
* Parse rfc5424 TIMESTAMP field into Instant .
*
* @param dateString
* @return
* /
2020-09-22 18:33:22 +00:00
static protected Instant parseRfc5424Timestamp ( String dateString ) {
2021-01-27 00:29:38 +00:00
/ *
https : //docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
ex1 : 1985 - 04 - 12T23 : 20 : 50 . 52Z
ex2 : 1985 - 04 - 12T19 : 20 : 50 . 52 - 04 : 00
ex3 : 2003 - 10 - 11T22 : 14 : 15 . 003Z
ex4 : 2003 - 08 - 24T05 : 14 : 15 . 000003 - 07 : 00
ex5 : 2003 - 08 - 24T05 : 14 : 15 . 000000003 - 07 : 00
* /
List < String > formatStrings = Arrays . asList (
" yyyy-MM-dd'T'HH:mm:ss.SS'Z' " ,
" yyyy-MM-dd'T'HH:mm:ss.SSXXX " ,
" yyyy-MM-dd'T'HH:mm:ss.SSS'Z' " ,
" yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX " ,
" yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX "
) ;
for ( String formatString : formatStrings )
{
try {
return new SimpleDateFormat ( formatString ) . parse ( dateString ) . toInstant ( ) ;
}
catch ( ParseException e ) { }
}
/ *
2020-09-22 18:33:22 +00:00
try {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter . ISO_OFFSET_DATE_TIME ;
instant = Instant . from ( dateTimeFormatter . parse ( dateString ) ) ;
} catch ( DateTimeParseException e ) {
log . error ( " parseTimestamp() " , e ) ;
}
2021-01-27 00:29:38 +00:00
return instant ; * /
return null ;
2020-09-22 18:33:22 +00:00
}
2020-09-23 08:52:52 +00:00
2020-10-07 09:53:16 +00:00
/ * *
* Converts syslog PRI field into Facility .
*
* @param pri
* @return
* /
static protected int getFacility ( String pri ) {
2020-09-23 08:52:52 +00:00
2020-10-07 09:53:16 +00:00
int priority = Integer . parseInt ( pri ) ;
2020-09-23 08:52:52 +00:00
int facility = priority > > 3 ;
2021-01-26 20:44:23 +00:00
//log.debug("getFacility() - " + pri + " => " + facility);
2020-09-23 08:52:52 +00:00
return facility ;
}
2020-10-07 09:53:16 +00:00
/ * *
* Converts syslog PRI field into Severity .
*
* @param pri
* @return
* /
static protected int getSeverity ( String pri ) {
int priority = Integer . parseInt ( pri ) ;
2020-09-23 08:52:52 +00:00
int severity = priority & 0x07 ;
2021-01-26 20:44:23 +00:00
//log.debug("getSeverity() - " + pri + " => " + severity);
2020-09-23 08:52:52 +00:00
return severity ;
}
2021-01-26 14:24:23 +00:00
2020-09-22 18:33:22 +00:00
}