commit
0909298bbc
|
@ -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
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
id = syslogd
|
id = syslogd
|
||||||
group = biz.nellemann.syslogd
|
group = biz.nellemann.syslogd
|
||||||
version = 1.0.9
|
version = 1.0.10
|
||||||
|
|
|
@ -15,6 +15,13 @@
|
||||||
*/
|
*/
|
||||||
package biz.nellemann.syslogd;
|
package biz.nellemann.syslogd;
|
||||||
|
|
||||||
|
import biz.nellemann.syslogd.msg.SyslogMessage;
|
||||||
|
import biz.nellemann.syslogd.net.TcpServer;
|
||||||
|
import biz.nellemann.syslogd.net.UdpClient;
|
||||||
|
import biz.nellemann.syslogd.net.UdpServer;
|
||||||
|
import biz.nellemann.syslogd.parser.SyslogParser;
|
||||||
|
import biz.nellemann.syslogd.parser.SyslogParserRfc3164;
|
||||||
|
import biz.nellemann.syslogd.parser.SyslogParserRfc5424;
|
||||||
import org.slf4j.impl.SimpleLogger;
|
import org.slf4j.impl.SimpleLogger;
|
||||||
|
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
|
@ -32,6 +39,7 @@ import java.util.regex.Pattern;
|
||||||
public class Application implements Callable<Integer>, LogListener {
|
public class Application implements Callable<Integer>, LogListener {
|
||||||
|
|
||||||
private boolean doForward = false;
|
private boolean doForward = false;
|
||||||
|
private SyslogParser syslogParser;
|
||||||
private UdpClient udpClient;
|
private UdpClient udpClient;
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +61,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'].")
|
||||||
|
@ -67,6 +75,12 @@ public class Application implements Callable<Integer>, LogListener {
|
||||||
System.setProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "DEBUG");
|
System.setProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "DEBUG");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(rfc5424) {
|
||||||
|
syslogParser = new SyslogParserRfc5424();
|
||||||
|
} else {
|
||||||
|
syslogParser = new SyslogParserRfc3164();
|
||||||
|
}
|
||||||
|
|
||||||
if(forward != null && !forward.isEmpty()) {
|
if(forward != null && !forward.isEmpty()) {
|
||||||
String fHost, fPort;
|
String fHost, fPort;
|
||||||
Pattern pattern = Pattern.compile("^([^:]+)(?::([0-9]+))?$", Pattern.CASE_INSENSITIVE);
|
Pattern pattern = Pattern.compile("^([^:]+)(?::([0-9]+))?$", Pattern.CASE_INSENSITIVE);
|
||||||
|
@ -110,11 +124,7 @@ public class Application implements Callable<Integer>, LogListener {
|
||||||
String message = event.getMessage();
|
String message = event.getMessage();
|
||||||
SyslogMessage msg = null;
|
SyslogMessage msg = null;
|
||||||
try {
|
try {
|
||||||
if(rfc5424) {
|
msg = syslogParser.parse(message);
|
||||||
msg = SyslogParser.parseRfc5424(message);
|
|
||||||
} else {
|
|
||||||
msg = SyslogParser.parseRfc3164(message);
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -131,7 +141,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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,5 +16,5 @@
|
||||||
package biz.nellemann.syslogd;
|
package biz.nellemann.syslogd;
|
||||||
|
|
||||||
public interface LogListener {
|
public interface LogListener {
|
||||||
void onLogEvent(LogEvent event);
|
public void onLogEvent(LogEvent event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,201 +0,0 @@
|
||||||
/*
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
package biz.nellemann.syslogd;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.time.*;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.time.format.DateTimeParseException;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class SyslogParser {
|
|
||||||
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(SyslogParser.class);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses [rfc3164](https://tools.ietf.org/html/rfc3164) syslog messages.
|
|
||||||
*
|
|
||||||
* @param input
|
|
||||||
* @return
|
|
||||||
* @throws NumberFormatException
|
|
||||||
*/
|
|
||||||
public static SyslogMessage parseRfc3164(final String input) throws NumberFormatException {
|
|
||||||
|
|
||||||
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);
|
|
||||||
Matcher matcher = pattern.matcher(input);
|
|
||||||
boolean matchFound = matcher.find();
|
|
||||||
if(!matchFound) {
|
|
||||||
//log.warn("parseRfc3164() - Match not found in: ");
|
|
||||||
System.err.println("!" + input);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String pri = matcher.group(1);
|
|
||||||
String date = matcher.group(2);
|
|
||||||
String hostname = matcher.group(3);
|
|
||||||
String application = matcher.group(4);
|
|
||||||
String msg = matcher.group(5);
|
|
||||||
|
|
||||||
if(hostname.endsWith(":")) {
|
|
||||||
String[] tmp = hostname.split(" ");
|
|
||||||
hostname = tmp[tmp.length-1];
|
|
||||||
hostname = hostname.substring(0, hostname.length()-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer facility = getFacility(pri);
|
|
||||||
Integer severity = getSeverity(pri);
|
|
||||||
|
|
||||||
SyslogMessage syslogMessage = new SyslogMessage(msg.trim());
|
|
||||||
syslogMessage.facility = Facility.getByNumber(facility);
|
|
||||||
syslogMessage.severity = Severity.getByNumber(severity);
|
|
||||||
syslogMessage.timestamp = parseRfc3164Timestamp(date);
|
|
||||||
syslogMessage.hostname = hostname;
|
|
||||||
syslogMessage.application = application;
|
|
||||||
|
|
||||||
return syslogMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses [rfc5424](https://tools.ietf.org/html/rfc5424) syslog messages.
|
|
||||||
*
|
|
||||||
* @param input
|
|
||||||
* @return
|
|
||||||
* @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);
|
|
||||||
Matcher matcher = pattern.matcher(input);
|
|
||||||
boolean matchFound = matcher.find();
|
|
||||||
if(!matchFound) {
|
|
||||||
//log.warn("parseRfc5424() - Match not found in: " + input);
|
|
||||||
System.err.println("!" + input);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
Integer facility = getFacility(pri);
|
|
||||||
Integer severity = getSeverity(pri);
|
|
||||||
|
|
||||||
SyslogMessage syslogMessage = new SyslogMessage(msg.trim());
|
|
||||||
syslogMessage.facility = Facility.getByNumber(facility);
|
|
||||||
syslogMessage.severity = Severity.getByNumber(severity);
|
|
||||||
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;
|
|
||||||
syslogMessage.structuredData = data;
|
|
||||||
|
|
||||||
return syslogMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse rfc3164 TIMESTAMP field into Instant.
|
|
||||||
*
|
|
||||||
* @param dateString
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static protected Instant parseRfc3164Timestamp(String dateString) {
|
|
||||||
|
|
||||||
// We need to add year to parse date correctly
|
|
||||||
OffsetDateTime odt = OffsetDateTime.now();
|
|
||||||
|
|
||||||
// Date: Mmm dd hh:mm:ss
|
|
||||||
Instant instant = null;
|
|
||||||
try {
|
|
||||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy MMM [ ]d HH:mm:ss").withZone(ZoneOffset.UTC);
|
|
||||||
instant = Instant.from(dateTimeFormatter.parse(odt.getYear() + " " + dateString));
|
|
||||||
} catch(DateTimeParseException e) {
|
|
||||||
log.error("parseDate()", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return instant;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse rfc5424 TIMESTAMP field into Instant.
|
|
||||||
*
|
|
||||||
* @param dateString
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static protected Instant parseRfc5424Timestamp(String dateString) {
|
|
||||||
|
|
||||||
Instant instant = null;
|
|
||||||
try {
|
|
||||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
|
||||||
instant = Instant.from(dateTimeFormatter.parse(dateString));
|
|
||||||
} catch(DateTimeParseException e) {
|
|
||||||
log.error("parseTimestamp()", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return instant;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts syslog PRI field into Facility.
|
|
||||||
*
|
|
||||||
* @param pri
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static protected int getFacility(String pri) {
|
|
||||||
|
|
||||||
int priority = Integer.parseInt(pri);
|
|
||||||
int facility = priority >> 3;
|
|
||||||
|
|
||||||
//log.debug("getFacility() - " + pri + " => " + facility);
|
|
||||||
return facility;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts syslog PRI field into Severity.
|
|
||||||
*
|
|
||||||
* @param pri
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static protected int getSeverity(String pri) {
|
|
||||||
|
|
||||||
int priority = Integer.parseInt(pri);
|
|
||||||
int severity = priority & 0x07;
|
|
||||||
|
|
||||||
//log.debug("getSeverity() - " + pri + " => " + severity);
|
|
||||||
return severity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,10 +1,19 @@
|
||||||
package biz.nellemann.syslogd;
|
package biz.nellemann.syslogd;
|
||||||
|
|
||||||
|
import biz.nellemann.syslogd.msg.Facility;
|
||||||
|
import biz.nellemann.syslogd.msg.Severity;
|
||||||
|
import biz.nellemann.syslogd.msg.SyslogMessage;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class SyslogPrinter {
|
public class SyslogPrinter {
|
||||||
|
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(SyslogPrinter.class);
|
||||||
|
|
||||||
|
private final static char SPACE = ' ';
|
||||||
|
|
||||||
public static String toString(SyslogMessage msg) {
|
public static String toString(SyslogMessage msg) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder(msg.timestamp.toString());
|
||||||
sb.append(msg.timestamp.toString());
|
|
||||||
sb.append(String.format(" [%8.8s.%-6.6s] ", msg.facility, msg.severity));
|
sb.append(String.format(" [%8.8s.%-6.6s] ", msg.facility, msg.severity));
|
||||||
sb.append(String.format(" %-16.16s ", msg.hostname));
|
sb.append(String.format(" %-16.16s ", msg.hostname));
|
||||||
sb.append(String.format(" %-32.32s ", msg.application));
|
sb.append(String.format(" %-32.32s ", msg.application));
|
||||||
|
@ -14,9 +23,7 @@ public class SyslogPrinter {
|
||||||
|
|
||||||
|
|
||||||
public static String toAnsiString(SyslogMessage msg) {
|
public static String toAnsiString(SyslogMessage msg) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder(msg.timestamp.toString());
|
||||||
|
|
||||||
sb.append(msg.timestamp.toString());
|
|
||||||
|
|
||||||
if (msg.severity.toNumber() < 3) {
|
if (msg.severity.toNumber() < 3) {
|
||||||
sb.append(Ansi.RED);
|
sb.append(Ansi.RED);
|
||||||
|
@ -40,30 +47,34 @@ public class SyslogPrinter {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(getPri(msg.facility, msg.severity));
|
sb.append(getPri(msg.facility, msg.severity));
|
||||||
sb.append(new java.text.SimpleDateFormat("MMM dd HH:mm:ss").format(new java.util.Date(msg.timestamp.toEpochMilli())));
|
sb.append(new java.text.SimpleDateFormat("MMM dd HH:mm:ss").format(new java.util.Date(msg.timestamp.toEpochMilli())));
|
||||||
sb.append(" " + msg.hostname);
|
sb.append(SPACE).append(msg.hostname);
|
||||||
sb.append(" " + msg.application);
|
sb.append(SPACE).append(msg.application);
|
||||||
sb.append(": " + msg.message);
|
sb.append(":").append(SPACE).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(SPACE).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(SPACE).append(msg.hostname);
|
||||||
sb.append(" " + msg.hostname);
|
sb.append(SPACE).append(msg.application);
|
||||||
sb.append(" " + msg.application);
|
sb.append(SPACE).append(msg.processId);
|
||||||
sb.append(": " + msg.message);
|
sb.append(SPACE).append(msg.messageId);
|
||||||
|
sb.append(SPACE).append(msg.structuredData);
|
||||||
|
sb.append(SPACE).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 pri = (facility.toNumber() * 8) + severity.toNumber();
|
||||||
return String.format("<%d>", prival);
|
return String.format("%c%d%c", '<', pri, '>');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
package biz.nellemann.syslogd;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.*;
|
|
||||||
|
|
||||||
public class UdpClient {
|
|
||||||
|
|
||||||
private DatagramSocket socket;
|
|
||||||
private InetAddress address;
|
|
||||||
private Integer port;
|
|
||||||
|
|
||||||
private byte[] buf;
|
|
||||||
|
|
||||||
public UdpClient(String host, Integer port) throws UnknownHostException, SocketException {
|
|
||||||
socket = new DatagramSocket();
|
|
||||||
address = InetAddress.getByName(host);
|
|
||||||
this.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void send(String msg) throws IOException {
|
|
||||||
buf = msg.getBytes();
|
|
||||||
DatagramPacket packet
|
|
||||||
= new DatagramPacket(buf, buf.length, address, port);
|
|
||||||
socket.send(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package biz.nellemann.syslogd;
|
package biz.nellemann.syslogd.msg;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
|
@ -1,4 +1,4 @@
|
||||||
package biz.nellemann.syslogd;
|
package biz.nellemann.syslogd.msg;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
|
@ -13,40 +13,40 @@
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
package biz.nellemann.syslogd;
|
package biz.nellemann.syslogd.msg;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
public class SyslogMessage {
|
public class SyslogMessage {
|
||||||
|
|
||||||
protected Facility facility;
|
public Facility facility;
|
||||||
protected Severity severity;
|
public Severity severity;
|
||||||
|
|
||||||
// The VERSION field denotes the version of the syslog protocol specification.
|
// The VERSION field denotes the version of the syslog protocol specification.
|
||||||
protected Integer version;
|
public Integer version;
|
||||||
|
|
||||||
// The TIMESTAMP field is a formalized timestamp derived from [RFC3339].
|
// The TIMESTAMP field is a formalized timestamp derived from [RFC3339].
|
||||||
protected Instant timestamp;
|
public Instant timestamp;
|
||||||
|
|
||||||
// The HOSTNAME field identifies the machine that originally sent the syslog message.
|
// The HOSTNAME field identifies the machine that originally sent the syslog message.
|
||||||
protected String hostname;
|
public 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;
|
public 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;
|
public String processId = "-";
|
||||||
|
|
||||||
// The MSGID SHOULD identify the type of message.
|
// The MSGID SHOULD identify the type of message.
|
||||||
protected String messageId;
|
public 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;
|
public 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;
|
public final String message;
|
||||||
|
|
||||||
SyslogMessage(final String message) {
|
public SyslogMessage(final String message) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,26 +13,29 @@
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
package biz.nellemann.syslogd;
|
package biz.nellemann.syslogd.net;
|
||||||
|
|
||||||
|
import biz.nellemann.syslogd.LogEvent;
|
||||||
|
import biz.nellemann.syslogd.LogListener;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class TcpServer {
|
public class TcpServer {
|
||||||
|
|
||||||
private final int port;
|
private final int port;
|
||||||
private ServerSocket serverSocket;
|
private ServerSocket serverSocket;
|
||||||
|
|
||||||
TcpServer() {
|
public TcpServer() {
|
||||||
this(514);
|
this(514);
|
||||||
}
|
}
|
||||||
|
|
||||||
TcpServer(int port) {
|
public TcpServer(int port) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
|
50
src/main/java/biz/nellemann/syslogd/net/UdpClient.java
Normal file
50
src/main/java/biz/nellemann/syslogd/net/UdpClient.java
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package biz.nellemann.syslogd.net;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class UdpClient {
|
||||||
|
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(UdpClient.class);
|
||||||
|
|
||||||
|
private DatagramSocket socket;
|
||||||
|
private InetAddress address;
|
||||||
|
private final Integer port;
|
||||||
|
|
||||||
|
public UdpClient(String host, Integer port) throws UnknownHostException, SocketException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.address = InetAddress.getByName(host);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
log.error("UdpClient() - UnknownHostException: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.socket = new DatagramSocket();
|
||||||
|
} catch (SocketException e) {
|
||||||
|
log.error("UdpClient() - Could not instantiate DatagramSocket: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(String msg) {
|
||||||
|
byte[] buf = msg.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port);
|
||||||
|
if(this.socket != null) {
|
||||||
|
try {
|
||||||
|
socket.send(packet);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("send() - Could not send packet: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,11 @@
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
package biz.nellemann.syslogd;
|
package biz.nellemann.syslogd.net;
|
||||||
|
|
||||||
|
import biz.nellemann.syslogd.Application;
|
||||||
|
import biz.nellemann.syslogd.LogEvent;
|
||||||
|
import biz.nellemann.syslogd.LogListener;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramPacket;
|
||||||
|
@ -68,7 +72,7 @@ public class UdpServer extends Thread {
|
||||||
|
|
||||||
protected List<LogListener> eventListeners = new ArrayList<>();
|
protected List<LogListener> eventListeners = new ArrayList<>();
|
||||||
|
|
||||||
public synchronized void addEventListener( LogListener l ) {
|
public synchronized void addEventListener(Application l ) {
|
||||||
eventListeners.add( l );
|
eventListeners.add( l );
|
||||||
}
|
}
|
||||||
|
|
66
src/main/java/biz/nellemann/syslogd/parser/SyslogParser.java
Normal file
66
src/main/java/biz/nellemann/syslogd/parser/SyslogParser.java
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package biz.nellemann.syslogd.parser;
|
||||||
|
|
||||||
|
import biz.nellemann.syslogd.msg.SyslogMessage;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public abstract class SyslogParser {
|
||||||
|
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(SyslogParser.class);
|
||||||
|
|
||||||
|
|
||||||
|
public abstract SyslogMessage parse(final String input);
|
||||||
|
|
||||||
|
abstract Instant parseTimestamp(final String dateString);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts syslog PRI field into Facility.
|
||||||
|
*
|
||||||
|
* @param pri
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getFacility(String pri) {
|
||||||
|
|
||||||
|
int priority = Integer.parseInt(pri);
|
||||||
|
int facility = priority >> 3;
|
||||||
|
|
||||||
|
//log.debug("getFacility() - " + pri + " => " + facility);
|
||||||
|
return facility;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts syslog PRI field into Severity.
|
||||||
|
*
|
||||||
|
* @param pri
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getSeverity(String pri) {
|
||||||
|
|
||||||
|
int priority = Integer.parseInt(pri);
|
||||||
|
int severity = priority & 0x07;
|
||||||
|
|
||||||
|
//log.debug("getSeverity() - " + pri + " => " + severity);
|
||||||
|
return severity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package biz.nellemann.syslogd.parser;
|
||||||
|
|
||||||
|
import biz.nellemann.syslogd.msg.Facility;
|
||||||
|
import biz.nellemann.syslogd.msg.Severity;
|
||||||
|
import biz.nellemann.syslogd.msg.SyslogMessage;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.time.*;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class SyslogParserRfc3164 extends SyslogParser {
|
||||||
|
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(SyslogParserRfc3164.class);
|
||||||
|
|
||||||
|
private final 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);
|
||||||
|
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy MMM [ ]d HH:mm:ss").withZone(ZoneId.systemDefault()); //.withZone(ZoneOffset.UTC);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses [rfc3164](https://tools.ietf.org/html/rfc3164) syslog messages.
|
||||||
|
*
|
||||||
|
* @param input
|
||||||
|
* @return
|
||||||
|
* @throws NumberFormatException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public SyslogMessage parse(final String input) throws NumberFormatException {
|
||||||
|
|
||||||
|
log.debug("parseRfc3164() " + input);
|
||||||
|
|
||||||
|
Matcher matcher = pattern.matcher(input);
|
||||||
|
if(!matcher.find()) {
|
||||||
|
System.err.println("!" + input);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String pri = matcher.group(1);
|
||||||
|
String date = matcher.group(2);
|
||||||
|
String hostname = matcher.group(3);
|
||||||
|
String application = matcher.group(4);
|
||||||
|
String msg = matcher.group(5);
|
||||||
|
|
||||||
|
if(hostname.endsWith(":")) {
|
||||||
|
String[] tmp = hostname.split(" ");
|
||||||
|
hostname = tmp[tmp.length-1];
|
||||||
|
hostname = hostname.substring(0, hostname.length()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer facility = getFacility(pri);
|
||||||
|
Integer severity = getSeverity(pri);
|
||||||
|
|
||||||
|
SyslogMessage syslogMessage = new SyslogMessage(msg.trim());
|
||||||
|
syslogMessage.facility = Facility.getByNumber(facility);
|
||||||
|
syslogMessage.severity = Severity.getByNumber(severity);
|
||||||
|
syslogMessage.timestamp = parseTimestamp(date);
|
||||||
|
syslogMessage.hostname = hostname;
|
||||||
|
syslogMessage.application = application;
|
||||||
|
|
||||||
|
return syslogMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse rfc3164 TIMESTAMP field into Instant.
|
||||||
|
*
|
||||||
|
* @param dateString
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected Instant parseTimestamp(String dateString) {
|
||||||
|
|
||||||
|
// We need to add year to parse date correctly
|
||||||
|
OffsetDateTime odt = OffsetDateTime.now();
|
||||||
|
|
||||||
|
// Date: Mmm dd hh:mm:ss
|
||||||
|
Instant instant = null;
|
||||||
|
try {
|
||||||
|
instant = Instant.from(dateTimeFormatter.parse(odt.getYear() + " " + dateString));
|
||||||
|
} catch(DateTimeParseException e) {
|
||||||
|
log.error("parseDate()", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return instant;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package biz.nellemann.syslogd.parser;
|
||||||
|
|
||||||
|
import biz.nellemann.syslogd.msg.Severity;
|
||||||
|
import biz.nellemann.syslogd.msg.Facility;
|
||||||
|
import biz.nellemann.syslogd.msg.SyslogMessage;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class SyslogParserRfc5424 extends SyslogParser {
|
||||||
|
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(SyslogParserRfc5424.class);
|
||||||
|
|
||||||
|
private final Pattern pattern = Pattern.compile("^<(\\d{1,3})>(\\d+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\[.*\\]|-)\\s+(\\S+)", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses [rfc5424](https://tools.ietf.org/html/rfc5424) syslog messages.
|
||||||
|
*
|
||||||
|
* @param input
|
||||||
|
* @return
|
||||||
|
* @throws NumberFormatException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public SyslogMessage parse(final String input) throws NumberFormatException {
|
||||||
|
|
||||||
|
log.debug("parseRfc5424() " + input);
|
||||||
|
|
||||||
|
Matcher matcher = pattern.matcher(input);
|
||||||
|
boolean matchFound = matcher.find();
|
||||||
|
if(!matchFound) {
|
||||||
|
log.debug("parseRfc5424() - Match not found in: " + input);
|
||||||
|
System.err.println("!" + input);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
Integer facility = getFacility(pri);
|
||||||
|
Integer severity = getSeverity(pri);
|
||||||
|
|
||||||
|
SyslogMessage syslogMessage = new SyslogMessage(msg.trim());
|
||||||
|
syslogMessage.facility = Facility.getByNumber(facility);
|
||||||
|
syslogMessage.severity = Severity.getByNumber(severity);
|
||||||
|
syslogMessage.version = Integer.parseInt(ver);
|
||||||
|
syslogMessage.timestamp = parseTimestamp(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;
|
||||||
|
if(data != null && !data.equals("-"))
|
||||||
|
syslogMessage.structuredData = data;
|
||||||
|
|
||||||
|
return syslogMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse rfc5424 TIMESTAMP field into Instant.
|
||||||
|
*
|
||||||
|
* @param dateString
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected Instant parseTimestamp(String dateString) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 {
|
||||||
|
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
||||||
|
instant = Instant.from(dateTimeFormatter.parse(dateString));
|
||||||
|
} catch(DateTimeParseException e) {
|
||||||
|
log.error("parseTimestamp()", e);
|
||||||
|
}
|
||||||
|
return instant;*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
package biz.nellemann.syslogd
|
||||||
|
|
||||||
|
import biz.nellemann.syslogd.msg.SyslogMessage
|
||||||
|
import biz.nellemann.syslogd.parser.SyslogParser
|
||||||
|
import biz.nellemann.syslogd.parser.SyslogParserRfc3164
|
||||||
|
import spock.lang.Specification
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
|
class SyslogParserRfc3164Test extends Specification {
|
||||||
|
|
||||||
|
SyslogParser syslogParser;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
syslogParser = new SyslogParserRfc3164();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void "test rfc3164 aix/vios message"() {
|
||||||
|
|
||||||
|
setup:
|
||||||
|
def input = "<13>Sep 23 08:37:09 Message forwarded from p924vio1: padmin: test"
|
||||||
|
|
||||||
|
when:
|
||||||
|
SyslogMessage msg = syslogParser.parse(input)
|
||||||
|
|
||||||
|
then:
|
||||||
|
msg.message == "test"
|
||||||
|
msg.hostname == "p924vio1"
|
||||||
|
msg.application == "padmin"
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test another rfc3164 aix/vios message"() {
|
||||||
|
|
||||||
|
setup:
|
||||||
|
def input = "<13>Dec 18 10:09:22 Message forwarded from p924vio1: root: [errnotify] seq: 24266 - AA8AB241 1218100920 T O OPERATOR OPERATOR NOTIFICATION"
|
||||||
|
|
||||||
|
when:
|
||||||
|
SyslogMessage msg = syslogParser.parse(input)
|
||||||
|
|
||||||
|
then:
|
||||||
|
msg.message == "[errnotify] seq: 24266 - AA8AB241 1218100920 T O OPERATOR OPERATOR NOTIFICATION"
|
||||||
|
msg.hostname == "p924vio1"
|
||||||
|
msg.application == "root"
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test rfc3164 normal message"() {
|
||||||
|
|
||||||
|
setup:
|
||||||
|
def input = "<13>Sep 23 08:53:28 xps13 mark: adfdfdf3432434"
|
||||||
|
|
||||||
|
when:
|
||||||
|
SyslogMessage msg = syslogParser.parse(input)
|
||||||
|
|
||||||
|
then:
|
||||||
|
msg.message == "adfdfdf3432434"
|
||||||
|
msg.hostname == "xps13"
|
||||||
|
msg.application == "mark"
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test rsyslogd sudo message"() {
|
||||||
|
setup:
|
||||||
|
String input = "<85>Oct 5 17:13:41 xps13 sudo: mark : TTY=pts/1 ; PWD=/etc/rsyslog.d ; USER=root ; COMMAND=/usr/sbin/service rsyslog restart"
|
||||||
|
|
||||||
|
when:
|
||||||
|
SyslogMessage msg = syslogParser.parse(input)
|
||||||
|
|
||||||
|
then:
|
||||||
|
msg.application == "sudo"
|
||||||
|
msg.message == "mark : TTY=pts/1 ; PWD=/etc/rsyslog.d ; USER=root ; COMMAND=/usr/sbin/service rsyslog restart"
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test gdm-session message"() {
|
||||||
|
setup:
|
||||||
|
String input = "<12>Oct 5 18:31:01 xps13 /usr/lib/gdm3/gdm-x-session[1921]: (EE) event5 - CUST0001:00 06CB:76AF Touchpad: kernel bug: Touch jump detected and discarded."
|
||||||
|
|
||||||
|
when:
|
||||||
|
SyslogMessage msg = syslogParser.parse(input)
|
||||||
|
|
||||||
|
then:
|
||||||
|
msg.application == "/usr/lib/gdm3/gdm-x-session[1921]"
|
||||||
|
msg.message == "(EE) event5 - CUST0001:00 06CB:76AF Touchpad: kernel bug: Touch jump detected and discarded."
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test intellij message"() {
|
||||||
|
setup:
|
||||||
|
String input = "<14>Oct 6 05:10:26 xps13 com.jetbrains.IntelliJ-IDEA-Ulti git4idea.commands.GitStandardProgressAnalyzer\$1.onLineAvailable(GitStandardProgressAnalyzer.java:45)"
|
||||||
|
|
||||||
|
when:
|
||||||
|
SyslogMessage msg = syslogParser.parse(input)
|
||||||
|
|
||||||
|
then:
|
||||||
|
msg.application == "com.jetbrains.IntelliJ-IDEA-Ulti"
|
||||||
|
msg.message == "git4idea.commands.GitStandardProgressAnalyzer\$1.onLineAvailable(GitStandardProgressAnalyzer.java:45)"
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test parseRfc3164Timestamp"() {
|
||||||
|
|
||||||
|
setup:
|
||||||
|
OffsetDateTime odt = OffsetDateTime.now()
|
||||||
|
String dateString = "Sep 12 20:50:13"
|
||||||
|
|
||||||
|
when:
|
||||||
|
Instant inst = syslogParser.parseTimestamp(dateString)
|
||||||
|
|
||||||
|
then:
|
||||||
|
inst.toString() == "${odt.getYear()}-09-12T18:50:13Z"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
package biz.nellemann.syslogd
|
||||||
|
|
||||||
|
import biz.nellemann.syslogd.msg.SyslogMessage
|
||||||
|
import biz.nellemann.syslogd.parser.SyslogParser
|
||||||
|
import biz.nellemann.syslogd.parser.SyslogParserRfc5424
|
||||||
|
import spock.lang.Specification
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
class SyslogParserRfc5424Test extends Specification {
|
||||||
|
|
||||||
|
SyslogParser syslogParser;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
syslogParser = new SyslogParserRfc5424();
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test rfc5424 message"() {
|
||||||
|
|
||||||
|
setup:
|
||||||
|
def input = '<13>1 2020-09-23T08:57:30.950699+02:00 xps13 mark - - [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"] adfdfdf3432434565656'
|
||||||
|
|
||||||
|
when:
|
||||||
|
SyslogMessage msg = syslogParser.parse(input)
|
||||||
|
|
||||||
|
then:
|
||||||
|
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.parse(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.parse(input)
|
||||||
|
|
||||||
|
then:
|
||||||
|
msg.hostname == "192.0.2.1"
|
||||||
|
msg.application == "myproc"
|
||||||
|
msg.processId == "8710"
|
||||||
|
msg.messageId == "-"
|
||||||
|
msg.structuredData == "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
void "test parseRfc5424Timestamp ex1"() {
|
||||||
|
setup:
|
||||||
|
String dateString = "1985-04-12T23:20:50.52Z"
|
||||||
|
|
||||||
|
when:
|
||||||
|
Instant inst = syslogParser.parseTimestamp(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.parseTimestamp(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.parseTimestamp(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.parseTimestamp(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.parseTimestamp(dateString)
|
||||||
|
|
||||||
|
then:
|
||||||
|
inst.toString() == "2003-08-24T12:14:15.003Z"
|
||||||
|
inst.toEpochMilli() == 1061727255003
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,125 +1,33 @@
|
||||||
package biz.nellemann.syslogd
|
package biz.nellemann.syslogd
|
||||||
|
|
||||||
|
import biz.nellemann.syslogd.msg.Facility
|
||||||
|
import biz.nellemann.syslogd.msg.Severity
|
||||||
|
import biz.nellemann.syslogd.parser.SyslogParser
|
||||||
|
import biz.nellemann.syslogd.parser.SyslogParserRfc5424
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
import java.time.Instant
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
|
|
||||||
class SyslogParserTest extends Specification {
|
class SyslogParserTest extends Specification {
|
||||||
|
|
||||||
void "test rfc5424 message"() {
|
SyslogParser syslogParser;
|
||||||
|
|
||||||
setup:
|
void setup() {
|
||||||
def input = "<13>1 2020-09-23T08:57:30.950699+02:00 xps13 mark - - [timeQuality tzKnown=\"1\" isSynced=\"1\" syncAccuracy=\"125500\"] adfdfdf3432434565656"
|
syslogParser = new SyslogParserRfc5424();
|
||||||
|
|
||||||
when:
|
|
||||||
SyslogMessage msg = SyslogParser.parseRfc5424(input)
|
|
||||||
|
|
||||||
then:
|
|
||||||
msg.message == "adfdfdf3432434565656"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void "test rfc3164 aix/vios message"() {
|
void "test facility LOCAL0"() {
|
||||||
|
|
||||||
setup:
|
|
||||||
def input = "<13>Sep 23 08:37:09 Message forwarded from p924vio1: padmin: test"
|
|
||||||
|
|
||||||
when:
|
when:
|
||||||
SyslogMessage msg = SyslogParser.parseRfc3164(input)
|
int code = syslogParser.getFacility("132")
|
||||||
|
|
||||||
then:
|
then:
|
||||||
msg.message == "test"
|
code == Facility.LOCAL0.toNumber()
|
||||||
msg.hostname == "p924vio1"
|
|
||||||
msg.application == "padmin"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void "test another rfc3164 aix/vios message"() {
|
void "test severity WARN"() {
|
||||||
|
|
||||||
setup:
|
|
||||||
def input = "<13>Dec 18 10:09:22 Message forwarded from p924vio1: root: [errnotify] seq: 24266 - AA8AB241 1218100920 T O OPERATOR OPERATOR NOTIFICATION"
|
|
||||||
|
|
||||||
when:
|
when:
|
||||||
SyslogMessage msg = SyslogParser.parseRfc3164(input)
|
int code = syslogParser.getSeverity("132")
|
||||||
|
|
||||||
then:
|
then:
|
||||||
msg.message == "[errnotify] seq: 24266 - AA8AB241 1218100920 T O OPERATOR OPERATOR NOTIFICATION"
|
code == Severity.WARN.toNumber()
|
||||||
msg.hostname == "p924vio1"
|
|
||||||
msg.application == "root"
|
|
||||||
}
|
|
||||||
|
|
||||||
void "test rfc3164 normal message"() {
|
|
||||||
|
|
||||||
setup:
|
|
||||||
def input = "<13>Sep 23 08:53:28 xps13 mark: adfdfdf3432434"
|
|
||||||
|
|
||||||
when:
|
|
||||||
SyslogMessage msg = SyslogParser.parseRfc3164(input)
|
|
||||||
|
|
||||||
then:
|
|
||||||
msg.message == "adfdfdf3432434"
|
|
||||||
msg.hostname == "xps13"
|
|
||||||
msg.application == "mark"
|
|
||||||
}
|
|
||||||
|
|
||||||
void "test rsyslogd sudo message"() {
|
|
||||||
setup:
|
|
||||||
String input = "<85>Oct 5 17:13:41 xps13 sudo: mark : TTY=pts/1 ; PWD=/etc/rsyslog.d ; USER=root ; COMMAND=/usr/sbin/service rsyslog restart"
|
|
||||||
|
|
||||||
when:
|
|
||||||
SyslogMessage msg = SyslogParser.parseRfc3164(input)
|
|
||||||
|
|
||||||
then:
|
|
||||||
msg.application == "sudo"
|
|
||||||
msg.message == "mark : TTY=pts/1 ; PWD=/etc/rsyslog.d ; USER=root ; COMMAND=/usr/sbin/service rsyslog restart"
|
|
||||||
}
|
|
||||||
|
|
||||||
void "test gdm-session message"() {
|
|
||||||
setup:
|
|
||||||
String input = "<12>Oct 5 18:31:01 xps13 /usr/lib/gdm3/gdm-x-session[1921]: (EE) event5 - CUST0001:00 06CB:76AF Touchpad: kernel bug: Touch jump detected and discarded."
|
|
||||||
|
|
||||||
when:
|
|
||||||
SyslogMessage msg = SyslogParser.parseRfc3164(input)
|
|
||||||
|
|
||||||
then:
|
|
||||||
msg.application == "/usr/lib/gdm3/gdm-x-session[1921]"
|
|
||||||
msg.message == "(EE) event5 - CUST0001:00 06CB:76AF Touchpad: kernel bug: Touch jump detected and discarded."
|
|
||||||
}
|
|
||||||
|
|
||||||
void "test intellij message"() {
|
|
||||||
setup:
|
|
||||||
String input = "<14>Oct 6 05:10:26 xps13 com.jetbrains.IntelliJ-IDEA-Ulti git4idea.commands.GitStandardProgressAnalyzer\$1.onLineAvailable(GitStandardProgressAnalyzer.java:45)"
|
|
||||||
|
|
||||||
when:
|
|
||||||
SyslogMessage msg = SyslogParser.parseRfc3164(input)
|
|
||||||
|
|
||||||
then:
|
|
||||||
msg.application == "com.jetbrains.IntelliJ-IDEA-Ulti"
|
|
||||||
msg.message == "git4idea.commands.GitStandardProgressAnalyzer\$1.onLineAvailable(GitStandardProgressAnalyzer.java:45)"
|
|
||||||
}
|
|
||||||
|
|
||||||
void "test parseRfc3164Timestamp"() {
|
|
||||||
|
|
||||||
setup:
|
|
||||||
OffsetDateTime odt = OffsetDateTime.now()
|
|
||||||
String dateString = "Sep 12 20:50:13"
|
|
||||||
|
|
||||||
when:
|
|
||||||
Instant inst = SyslogParser.parseRfc3164Timestamp(dateString)
|
|
||||||
|
|
||||||
then:
|
|
||||||
inst.toString() == "${odt.getYear()}-09-12T20:50:13Z"
|
|
||||||
}
|
|
||||||
|
|
||||||
void "test parseRfc5424Timestamp"() {
|
|
||||||
|
|
||||||
setup:
|
|
||||||
String dateString = "2020-09-22T20:10:30.925438+02:00"
|
|
||||||
|
|
||||||
when:
|
|
||||||
Instant inst = SyslogParser.parseRfc5424Timestamp(dateString)
|
|
||||||
|
|
||||||
then:
|
|
||||||
inst.toString() == "2020-09-22T18:10:30.925438Z"
|
|
||||||
inst.toEpochMilli() == 1600798230925l
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
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