Improve rfc5424 parsing.
This commit is contained in:
parent
f9340fb8b2
commit
0752c0b6a6
|
@ -18,7 +18,8 @@ dependencies {
|
||||||
implementation 'org.slf4j:slf4j-simple:1.7.30'
|
implementation 'org.slf4j:slf4j-simple:1.7.30'
|
||||||
|
|
||||||
testImplementation('org.spockframework:spock-core:2.0-M4-groovy-3.0')
|
testImplementation('org.spockframework:spock-core:2.0-M4-groovy-3.0')
|
||||||
testImplementation("org.slf4j:slf4j-simple:1.7.30")
|
testImplementation 'org.slf4j:slf4j-api:1.7.30'
|
||||||
|
testRuntime("org.slf4j:slf4j-simple:1.7.30")
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
|
|
|
@ -4,7 +4,7 @@ Description=Simple Syslog Service
|
||||||
[Service]
|
[Service]
|
||||||
TimeoutStartSec=0
|
TimeoutStartSec=0
|
||||||
Restart=always
|
Restart=always
|
||||||
ExecStart=/opt/syslogd/bin/syslogd --no-stdout --forward localhost:1514
|
ExecStart=/opt/syslogd/bin/syslogd --no-stdout --forward=localhost:1514
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=default.target
|
WantedBy=default.target
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class Application implements Callable<Integer>, LogListener {
|
||||||
@CommandLine.Option(names = "--rfc5424", description = "Parse RFC-5424 messages [default: RFC-3164].", defaultValue = "false")
|
@CommandLine.Option(names = "--rfc5424", description = "Parse RFC-5424 messages [default: RFC-3164].", defaultValue = "false")
|
||||||
private boolean rfc5424;
|
private boolean rfc5424;
|
||||||
|
|
||||||
@CommandLine.Option(names = { "-f", "--forward"}, description = "Forward to UDP host[:port] (RFC-3164).", paramLabel = "<host>")
|
@CommandLine.Option(names = { "-f", "--forward"}, description = "Forward to UDP host[:port] (RFC-5424).", paramLabel = "<host>")
|
||||||
private String forward;
|
private String forward;
|
||||||
|
|
||||||
@CommandLine.Option(names = { "-d", "--debug" }, description = "Enable debugging [default: 'false'].")
|
@CommandLine.Option(names = { "-d", "--debug" }, description = "Enable debugging [default: 'false'].")
|
||||||
|
@ -131,7 +131,7 @@ public class Application implements Callable<Integer>, LogListener {
|
||||||
|
|
||||||
if(doForward) {
|
if(doForward) {
|
||||||
try {
|
try {
|
||||||
udpClient.send(SyslogPrinter.toRfc3164(msg));
|
udpClient.send(SyslogPrinter.toRfc5424(msg));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,16 +32,16 @@ public class SyslogMessage {
|
||||||
protected String hostname;
|
protected String hostname;
|
||||||
|
|
||||||
// The APP-NAME field SHOULD identify the device or application that originated the message.
|
// The APP-NAME field SHOULD identify the device or application that originated the message.
|
||||||
protected String application;
|
protected String application = "-";
|
||||||
|
|
||||||
// The PROCID field is often used to provide the process name or process ID associated with a syslog system.
|
// The PROCID field is often used to provide the process name or process ID associated with a syslog system.
|
||||||
protected String processId;
|
protected String processId = "-";
|
||||||
|
|
||||||
// The MSGID SHOULD identify the type of message.
|
// The MSGID SHOULD identify the type of message.
|
||||||
protected String messageId;
|
protected String messageId = "-";
|
||||||
|
|
||||||
// STRUCTURED-DATA provides a mechanism to express information in a well defined, easily parseable and interpretable data format.
|
// STRUCTURED-DATA provides a mechanism to express information in a well defined, easily parseable and interpretable data format.
|
||||||
protected String structuredData;
|
protected String structuredData = "-";
|
||||||
|
|
||||||
// The MSG part contains a free-form message that provides information about the event.
|
// The MSG part contains a free-form message that provides information about the event.
|
||||||
protected final String message;
|
protected final String message;
|
||||||
|
|
|
@ -18,9 +18,13 @@ package biz.nellemann.syslogd;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.*;
|
import java.time.*;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -82,11 +86,15 @@ public class SyslogParser {
|
||||||
*/
|
*/
|
||||||
public static SyslogMessage parseRfc5424(final String input) throws NumberFormatException {
|
public static SyslogMessage parseRfc5424(final String input) throws NumberFormatException {
|
||||||
|
|
||||||
Pattern pattern = Pattern.compile("^<(\\d{1,3})>(\\d+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\[.*\\])\\s+(\\S+)", Pattern.CASE_INSENSITIVE);
|
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);
|
||||||
Matcher matcher = pattern.matcher(input);
|
Matcher matcher = pattern.matcher(input);
|
||||||
boolean matchFound = matcher.find();
|
boolean matchFound = matcher.find();
|
||||||
if(!matchFound) {
|
if(!matchFound) {
|
||||||
//log.warn("parseRfc5424() - Match not found in: " + input);
|
log.debug("parseRfc5424() - Match not found in: " + input);
|
||||||
System.err.println("!" + input);
|
System.err.println("!" + input);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -116,6 +124,7 @@ public class SyslogParser {
|
||||||
syslogMessage.processId = procId;
|
syslogMessage.processId = procId;
|
||||||
if(msgId != null && !msgId.equals("-"))
|
if(msgId != null && !msgId.equals("-"))
|
||||||
syslogMessage.messageId = msgId;
|
syslogMessage.messageId = msgId;
|
||||||
|
if(data != null && !data.equals("-"))
|
||||||
syslogMessage.structuredData = data;
|
syslogMessage.structuredData = data;
|
||||||
|
|
||||||
return syslogMessage;
|
return syslogMessage;
|
||||||
|
@ -154,15 +163,40 @@ public class SyslogParser {
|
||||||
*/
|
*/
|
||||||
static protected Instant parseRfc5424Timestamp(String dateString) {
|
static protected Instant parseRfc5424Timestamp(String dateString) {
|
||||||
|
|
||||||
Instant instant = null;
|
/*
|
||||||
|
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) {}
|
||||||
|
}
|
||||||
|
/*
|
||||||
try {
|
try {
|
||||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
||||||
instant = Instant.from(dateTimeFormatter.parse(dateString));
|
instant = Instant.from(dateTimeFormatter.parse(dateString));
|
||||||
} catch(DateTimeParseException e) {
|
} catch(DateTimeParseException e) {
|
||||||
log.error("parseTimestamp()", e);
|
log.error("parseTimestamp()", e);
|
||||||
}
|
}
|
||||||
|
return instant;*/
|
||||||
return instant;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
package biz.nellemann.syslogd;
|
package biz.nellemann.syslogd;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class SyslogPrinter {
|
public class SyslogPrinter {
|
||||||
|
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(SyslogPrinter.class);
|
||||||
|
|
||||||
public static String toString(SyslogMessage msg) {
|
public static String toString(SyslogMessage msg) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(msg.timestamp.toString());
|
sb.append(msg.timestamp.toString());
|
||||||
|
@ -44,23 +49,28 @@ public class SyslogPrinter {
|
||||||
sb.append(" " + msg.application);
|
sb.append(" " + msg.application);
|
||||||
sb.append(": " + msg.message);
|
sb.append(": " + msg.message);
|
||||||
|
|
||||||
|
log.debug(sb.toString());
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// <13>1 2020-09-23T08:57:30.950699+02:00 xps13 mark - - [timeQuality tzKnown="1" isSynced="1" syncAccuracy="125500"] adfdfdf3432434565656
|
// <13>1 2020-09-23T08:57:30.950699+02:00 xps13 mark - - [timeQuality tzKnown="1" isSynced="1" syncAccuracy="125500"] adfdfdf3432434565656
|
||||||
|
// <34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - BOM'su root' failed for lonvick on /dev/pts/8
|
||||||
public static String toRfc5424(SyslogMessage msg) {
|
public static String toRfc5424(SyslogMessage msg) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(getPri(msg.facility, msg.severity));
|
sb.append(getPri(msg.facility, msg.severity)).append("1");
|
||||||
sb.append("1"); // Version
|
sb.append(" " + new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(new java.util.Date(msg.timestamp.toEpochMilli())));
|
||||||
sb.append(" " + new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new java.util.Date(msg.timestamp.toEpochMilli())));
|
|
||||||
sb.append(" " + msg.hostname);
|
sb.append(" " + msg.hostname);
|
||||||
sb.append(" " + msg.application);
|
sb.append(" " + msg.application);
|
||||||
sb.append(": " + msg.message);
|
sb.append(" " + msg.processId);
|
||||||
|
sb.append(" " + msg.messageId);
|
||||||
|
sb.append(" " + msg.structuredData);
|
||||||
|
sb.append(" " + msg.message);
|
||||||
|
log.debug(sb.toString());
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static private String getPri(Facility facility, Severity severity) {
|
static private String getPri(Facility facility, Severity severity) {
|
||||||
int prival = (facility.toNumber() * 8) + severity.toNumber();
|
int prival = (facility.toNumber() * 8) + severity.toNumber();
|
||||||
return String.format("<%d>", prival);
|
return String.format("<%d>", prival);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package biz.nellemann.syslogd
|
package biz.nellemann.syslogd
|
||||||
|
|
||||||
|
import spock.lang.Ignore
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
@ -9,15 +10,49 @@ class SyslogParserTest extends Specification {
|
||||||
void "test rfc5424 message"() {
|
void "test rfc5424 message"() {
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
def input = "<13>1 2020-09-23T08:57:30.950699+02:00 xps13 mark - - [timeQuality tzKnown=\"1\" isSynced=\"1\" syncAccuracy=\"125500\"] adfdfdf3432434565656"
|
def input = '<13>1 2020-09-23T08:57:30.950699+02:00 xps13 mark - - [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"] adfdfdf3432434565656'
|
||||||
|
|
||||||
when:
|
when:
|
||||||
SyslogMessage msg = SyslogParser.parseRfc5424(input)
|
SyslogMessage msg = SyslogParser.parseRfc5424(input)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
msg.message == "adfdfdf3432434565656"
|
msg.message == "adfdfdf3432434565656"
|
||||||
|
msg.processId == "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void "test rfc5424 example message"() {
|
||||||
|
|
||||||
|
setup:
|
||||||
|
def input = "<34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - BOM'su root' failed for lonvick on /dev/pts/8"
|
||||||
|
|
||||||
|
when:
|
||||||
|
SyslogMessage msg = SyslogParser.parseRfc5424(input)
|
||||||
|
|
||||||
|
then:
|
||||||
|
msg.hostname == "mymachine.example.com"
|
||||||
|
msg.application == "su"
|
||||||
|
msg.processId == "-"
|
||||||
|
msg.messageId == "ID47"
|
||||||
|
msg.structuredData == "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test rfc5424 example2 message"() {
|
||||||
|
|
||||||
|
setup:
|
||||||
|
def 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."
|
||||||
|
|
||||||
|
when:
|
||||||
|
SyslogMessage msg = SyslogParser.parseRfc5424(input)
|
||||||
|
|
||||||
|
then:
|
||||||
|
msg.hostname == "192.0.2.1"
|
||||||
|
msg.application == "myproc"
|
||||||
|
msg.processId == "8710"
|
||||||
|
msg.messageId == "-"
|
||||||
|
msg.structuredData == "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void "test rfc3164 aix/vios message"() {
|
void "test rfc3164 aix/vios message"() {
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
|
@ -109,6 +144,69 @@ class SyslogParserTest extends Specification {
|
||||||
inst.toString() == "${odt.getYear()}-09-12T20:50:13Z"
|
inst.toString() == "${odt.getYear()}-09-12T20:50:13Z"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void "test parseRfc5424Timestamp ex1"() {
|
||||||
|
setup:
|
||||||
|
String dateString = "1985-04-12T23:20:50.52Z"
|
||||||
|
|
||||||
|
when:
|
||||||
|
Instant inst = SyslogParser.parseRfc5424Timestamp(dateString)
|
||||||
|
|
||||||
|
then:
|
||||||
|
inst.toString() == "1985-04-12T21:20:50.052Z"
|
||||||
|
inst.toEpochMilli() == 482188850052
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test parseRfc5424Timestamp ex2"() {
|
||||||
|
setup:
|
||||||
|
String dateString = "1985-04-12T19:20:50.52-04:00"
|
||||||
|
|
||||||
|
when:
|
||||||
|
Instant inst = SyslogParser.parseRfc5424Timestamp(dateString)
|
||||||
|
|
||||||
|
then:
|
||||||
|
inst.toString() == "1985-04-12T23:20:50.052Z"
|
||||||
|
inst.toEpochMilli() == 482196050052
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test parseRfc5424Timestamp ex3"() {
|
||||||
|
setup:
|
||||||
|
String dateString = "2003-10-11T22:14:15.003Z"
|
||||||
|
|
||||||
|
when:
|
||||||
|
Instant inst = SyslogParser.parseRfc5424Timestamp(dateString)
|
||||||
|
|
||||||
|
then:
|
||||||
|
inst.toString() == "2003-10-11T20:14:15.003Z"
|
||||||
|
inst.toEpochMilli() == 1065903255003
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test parseRfc5424Timestamp ex4"() {
|
||||||
|
setup:
|
||||||
|
String dateString = "2003-08-24T05:14:15.000003-07:00"
|
||||||
|
|
||||||
|
when:
|
||||||
|
Instant inst = SyslogParser.parseRfc5424Timestamp(dateString)
|
||||||
|
|
||||||
|
then:
|
||||||
|
inst.toString() == "2003-08-24T12:14:15.003Z"
|
||||||
|
inst.toEpochMilli() == 1061727255003
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test parseRfc5424Timestamp ex5"() {
|
||||||
|
setup:
|
||||||
|
String dateString = "2003-08-24T05:14:15.000000003-07:00"
|
||||||
|
|
||||||
|
when:
|
||||||
|
Instant inst = SyslogParser.parseRfc5424Timestamp(dateString)
|
||||||
|
|
||||||
|
then:
|
||||||
|
inst.toString() == "2003-08-24T12:14:15.003Z"
|
||||||
|
inst.toEpochMilli() == 1061727255003
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Ignore
|
||||||
void "test parseRfc5424Timestamp"() {
|
void "test parseRfc5424Timestamp"() {
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
|
|
6
src/test/resources/simplelogger.properties
Normal file
6
src/test/resources/simplelogger.properties
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
org.slf4j.simpleLogger.logFile=System.err
|
||||||
|
org.slf4j.simpleLogger.showDateTime=false
|
||||||
|
org.slf4j.simpleLogger.showShortLogName=true
|
||||||
|
org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss.SSS
|
||||||
|
org.slf4j.simpleLogger.levelInBrackets=true
|
||||||
|
org.slf4j.simpleLogger.defaultLogLevel=debug
|
Loading…
Reference in a new issue