Improve UDP reception and add file output and ansi flag on/off.
This commit is contained in:
parent
a1599d0862
commit
8ae2ec7573
|
@ -59,7 +59,7 @@ ospackage {
|
||||||
|
|
||||||
buildRpm {
|
buildRpm {
|
||||||
dependsOn startShadowScripts
|
dependsOn startShadowScripts
|
||||||
requires('java-1.8.0-openjdk-headless')
|
//requires('java-1.8.0-openjdk-headless')
|
||||||
os = LINUX
|
os = LINUX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
id = syslogd
|
id = syslogd
|
||||||
group = biz.nellemann.syslogd
|
group = biz.nellemann.syslogd
|
||||||
version = 1.0.0
|
version = 1.0.1
|
||||||
|
|
|
@ -20,9 +20,9 @@ import java.util.EventObject;
|
||||||
|
|
||||||
public class LogEvent extends EventObject {
|
public class LogEvent extends EventObject {
|
||||||
|
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
public LogEvent(Object source, String message ) {
|
public LogEvent(final Object source, final String message ) {
|
||||||
super( source );
|
super( source );
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package biz.nellemann.syslogd;
|
package biz.nellemann.syslogd;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public interface LogListener {
|
public interface LogListener {
|
||||||
void onLogEvent(LogEvent event);
|
void onLogEvent(LogEvent event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,12 +44,26 @@ public class SyslogMessage {
|
||||||
String structuredData;
|
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.
|
||||||
String message;
|
final private String message;
|
||||||
|
|
||||||
|
SyslogMessage(final String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
//return String.format("%s %s %s: %s", timestamp.toString(), hostname, application, message);
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(timestamp.toString() + " ");
|
||||||
|
sb.append("[" + facility + "." + severity + "]");
|
||||||
|
sb.append("\t" + hostname);
|
||||||
|
sb.append("\t" + application);
|
||||||
|
sb.append("\t" + message);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String toAnsiString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
sb.append(timestamp.toString() + " ");
|
sb.append(timestamp.toString() + " ");
|
||||||
|
@ -65,7 +79,7 @@ public class SyslogMessage {
|
||||||
|
|
||||||
sb.append(Ansi.BLUE); sb.append("\t" + hostname); sb.append(Ansi.RESET);
|
sb.append(Ansi.BLUE); sb.append("\t" + hostname); sb.append(Ansi.RESET);
|
||||||
sb.append(Ansi.CYAN); sb.append("\t" + application); sb.append(Ansi.RESET);
|
sb.append(Ansi.CYAN); sb.append("\t" + application); sb.append(Ansi.RESET);
|
||||||
sb.append("\t" + message); sb.append(Ansi.CLEAR_LINE);
|
sb.append("\t" + message);
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class SyslogParser {
|
||||||
private final static Logger log = LoggerFactory.getLogger(SyslogParser.class);
|
private final static Logger log = LoggerFactory.getLogger(SyslogParser.class);
|
||||||
|
|
||||||
|
|
||||||
public static SyslogMessage parseRfc3164(String input) throws NumberFormatException {
|
public static SyslogMessage parseRfc3164(final String input) throws NumberFormatException {
|
||||||
|
|
||||||
Pattern pattern = Pattern.compile("^<(\\d{1,3})>(\\D{3} \\d{2} \\d{2}:\\d{2}:\\d{2})\\s+(?:Message forwarded from )?([^\\s:]+):?\\s+(\\S+): (.*)", Pattern.CASE_INSENSITIVE);
|
Pattern pattern = Pattern.compile("^<(\\d{1,3})>(\\D{3} \\d{2} \\d{2}:\\d{2}:\\d{2})\\s+(?:Message forwarded from )?([^\\s:]+):?\\s+(\\S+): (.*)", Pattern.CASE_INSENSITIVE);
|
||||||
Matcher matcher = pattern.matcher(input);
|
Matcher matcher = pattern.matcher(input);
|
||||||
|
@ -45,11 +45,11 @@ public class SyslogParser {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String pri = matcher.group(1);
|
final String pri = matcher.group(1);
|
||||||
String date = matcher.group(2);
|
final String date = matcher.group(2);
|
||||||
String hostname = matcher.group(3);
|
final String hostname = matcher.group(3);
|
||||||
String application = matcher.group(4);
|
final String application = matcher.group(4);
|
||||||
String message = matcher.group(5);
|
final String message = matcher.group(5);
|
||||||
|
|
||||||
log.debug("PRI: " + pri);
|
log.debug("PRI: " + pri);
|
||||||
log.debug("DATE: " + date);
|
log.debug("DATE: " + date);
|
||||||
|
@ -62,19 +62,18 @@ public class SyslogParser {
|
||||||
log.debug("facility: " + facility);
|
log.debug("facility: " + facility);
|
||||||
log.debug("severity: " + severity);
|
log.debug("severity: " + severity);
|
||||||
|
|
||||||
SyslogMessage syslogMessage = new SyslogMessage();
|
SyslogMessage syslogMessage = new SyslogMessage(message);
|
||||||
syslogMessage.facility = Facility.getByNumber(facility);
|
syslogMessage.facility = Facility.getByNumber(facility);
|
||||||
syslogMessage.severity = Severity.getByNumber(severity);
|
syslogMessage.severity = Severity.getByNumber(severity);
|
||||||
syslogMessage.timestamp = parseRfc3164Timestamp(date);
|
syslogMessage.timestamp = parseRfc3164Timestamp(date);
|
||||||
syslogMessage.hostname = hostname;
|
syslogMessage.hostname = hostname;
|
||||||
syslogMessage.application = application;
|
syslogMessage.application = application;
|
||||||
syslogMessage.message = message;
|
|
||||||
|
|
||||||
return syslogMessage;
|
return syslogMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static SyslogMessage parseRfc5424(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);
|
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);
|
||||||
|
@ -84,15 +83,15 @@ public class SyslogParser {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String pri = matcher.group(1);
|
final String pri = matcher.group(1);
|
||||||
String ver = matcher.group(2);
|
final String ver = matcher.group(2);
|
||||||
String date = matcher.group(3);
|
final String date = matcher.group(3);
|
||||||
String host = matcher.group(4);
|
final String host = matcher.group(4);
|
||||||
String app = matcher.group(5);
|
final String app = matcher.group(5);
|
||||||
String procId = matcher.group(6);
|
final String procId = matcher.group(6);
|
||||||
String msgId = matcher.group(7);
|
final String msgId = matcher.group(7);
|
||||||
String data = matcher.group(8);
|
final String data = matcher.group(8);
|
||||||
String msg = matcher.group(9);
|
final String msg = matcher.group(9);
|
||||||
|
|
||||||
log.debug("PRI: " + pri);
|
log.debug("PRI: " + pri);
|
||||||
log.debug("VER: " + ver);
|
log.debug("VER: " + ver);
|
||||||
|
@ -109,7 +108,7 @@ public class SyslogParser {
|
||||||
log.debug("facility: " + facility);
|
log.debug("facility: " + facility);
|
||||||
log.debug("severity: " + severity);
|
log.debug("severity: " + severity);
|
||||||
|
|
||||||
SyslogMessage syslogMessage = new SyslogMessage();
|
SyslogMessage syslogMessage = new SyslogMessage(msg);
|
||||||
syslogMessage.facility = Facility.getByNumber(facility);
|
syslogMessage.facility = Facility.getByNumber(facility);
|
||||||
syslogMessage.severity = Severity.getByNumber(severity);
|
syslogMessage.severity = Severity.getByNumber(severity);
|
||||||
syslogMessage.version = Integer.parseInt(ver);
|
syslogMessage.version = Integer.parseInt(ver);
|
||||||
|
@ -122,7 +121,6 @@ public class SyslogParser {
|
||||||
if(msgId != null && !msgId.equals("-"))
|
if(msgId != null && !msgId.equals("-"))
|
||||||
syslogMessage.messageId = msgId;
|
syslogMessage.messageId = msgId;
|
||||||
syslogMessage.structuredData = data;
|
syslogMessage.structuredData = data;
|
||||||
syslogMessage.message = msg;
|
|
||||||
|
|
||||||
return syslogMessage;
|
return syslogMessage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,26 +19,37 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
import picocli.CommandLine.Command;
|
import picocli.CommandLine.Command;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
@Command(name = "syslogd", mixinStandardHelpOptions = true, version = "syslogd 1.0",
|
@Command(name = "syslogd",
|
||||||
description = "Simple syslog server that prints messages to stdout.")
|
mixinStandardHelpOptions = true,
|
||||||
|
description = "Basic syslog server.",
|
||||||
|
versionProvider = biz.nellemann.syslogd.VersionProvider.class)
|
||||||
public class SyslogServer implements Callable<Integer>, LogListener {
|
public class SyslogServer implements Callable<Integer>, LogListener {
|
||||||
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(SyslogServer.class);
|
private final static Logger log = LoggerFactory.getLogger(SyslogServer.class);
|
||||||
|
private BufferedWriter bw;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"-p", "--port"}, description = "Listening port, 514 (privileged) by default.")
|
@CommandLine.Option(names = {"-p", "--port"}, description = "Listening port [default: 514]")
|
||||||
private int port = 514;
|
private int port = 514;
|
||||||
|
|
||||||
@CommandLine.Option(names = "--no-udp", negatable = true, description = "Listen on UDP, true by default.")
|
@CommandLine.Option(names = "--no-udp", negatable = true, description = "Listen on UDP [default: true]")
|
||||||
boolean udpServer = true;
|
boolean udpServer = true;
|
||||||
|
|
||||||
@CommandLine.Option(names = "--no-tcp", negatable = true, description = "Listen on TCP, true by default.")
|
@CommandLine.Option(names = "--no-tcp", negatable = true, description = "Listen on TCP [default: true]")
|
||||||
boolean tcpServer = true;
|
boolean tcpServer = true;
|
||||||
|
|
||||||
@CommandLine.Option(names = "--rfc3164", negatable = false, description = "Parse RFC3164 syslog message, RFC5424 by default.")
|
@CommandLine.Option(names = "--rfc3164", negatable = false, description = "Parse RFC3164 messages [default: RFC5424]")
|
||||||
boolean rfc3164 = false;
|
boolean rfc3164 = false;
|
||||||
|
|
||||||
|
@CommandLine.Option(names = "--no-ansi", negatable = true, description = "ANSI in output [default: true]")
|
||||||
|
boolean ansiOutput = true;
|
||||||
|
|
||||||
|
@CommandLine.Option(names = {"-f", "--file"}, description = "Write output to file [default: STDOUT]")
|
||||||
|
File outputFile;
|
||||||
|
|
||||||
public static void main(String... args) {
|
public static void main(String... args) {
|
||||||
int exitCode = new CommandLine(new SyslogServer()).execute(args);
|
int exitCode = new CommandLine(new SyslogServer()).execute(args);
|
||||||
System.exit(exitCode);
|
System.exit(exitCode);
|
||||||
|
@ -48,6 +59,15 @@ public class SyslogServer implements Callable<Integer>, LogListener {
|
||||||
@Override
|
@Override
|
||||||
public Integer call() throws Exception {
|
public Integer call() throws Exception {
|
||||||
|
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
OutputStreamWriter w;
|
||||||
|
|
||||||
|
if(outputFile != null) {
|
||||||
|
fos = new FileOutputStream(outputFile);
|
||||||
|
w = new OutputStreamWriter(fos, "UTF-8");
|
||||||
|
bw = new BufferedWriter(w);
|
||||||
|
}
|
||||||
|
|
||||||
if(udpServer) {
|
if(udpServer) {
|
||||||
UdpServer udpServer = new UdpServer(port);
|
UdpServer udpServer = new UdpServer(port);
|
||||||
udpServer.addEventListener(this);
|
udpServer.addEventListener(this);
|
||||||
|
@ -60,6 +80,11 @@ public class SyslogServer implements Callable<Integer>, LogListener {
|
||||||
tcpServer.start();
|
tcpServer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(outputFile != null) {
|
||||||
|
bw.close();
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +92,7 @@ public class SyslogServer implements Callable<Integer>, LogListener {
|
||||||
@Override
|
@Override
|
||||||
public void onLogEvent(LogEvent event) {
|
public void onLogEvent(LogEvent event) {
|
||||||
|
|
||||||
|
// Parse message
|
||||||
String message = event.getMessage();
|
String message = event.getMessage();
|
||||||
SyslogMessage msg = null;
|
SyslogMessage msg = null;
|
||||||
try {
|
try {
|
||||||
|
@ -80,9 +106,37 @@ public class SyslogServer implements Callable<Integer>, LogListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(msg != null) {
|
if(msg != null) {
|
||||||
System.out.println(msg);
|
if(bw != null) {
|
||||||
|
writeToFile(msg);
|
||||||
|
} else {
|
||||||
|
writeToStdout(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void writeToFile(SyslogMessage msg) {
|
||||||
|
try {
|
||||||
|
if(ansiOutput) {
|
||||||
|
bw.append(msg.toAnsiString());
|
||||||
|
} else {
|
||||||
|
bw.append(msg.toString());
|
||||||
|
}
|
||||||
|
bw.newLine();
|
||||||
|
bw.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("file error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void writeToStdout(SyslogMessage msg) {
|
||||||
|
if(ansiOutput) {
|
||||||
|
System.out.println(msg.toAnsiString());
|
||||||
|
} else {
|
||||||
|
System.out.println(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,13 +38,13 @@ public class UdpServer extends Thread {
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
byte[] buf = new byte[10000];
|
byte[] buf = new byte[4096];
|
||||||
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||||
|
|
||||||
while (listen) {
|
while (listen) {
|
||||||
try {
|
try {
|
||||||
socket.receive(packet);
|
socket.receive(packet);
|
||||||
String packetData = new String(packet.getData(), "UTF8");
|
String packetData = new String(packet.getData(), packet.getOffset(), packet.getLength(), "UTF8");
|
||||||
sendEvent(packetData);
|
sendEvent(packetData);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
22
src/main/java/biz/nellemann/syslogd/VersionProvider.java
Normal file
22
src/main/java/biz/nellemann/syslogd/VersionProvider.java
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package biz.nellemann.syslogd;
|
||||||
|
|
||||||
|
import picocli.CommandLine;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
class VersionProvider implements CommandLine.IVersionProvider {
|
||||||
|
|
||||||
|
public String[] getVersion() throws IOException {
|
||||||
|
|
||||||
|
URL url = getClass().getResource("/version.properties");
|
||||||
|
if (url == null) {
|
||||||
|
return new String[] { "No version.txt file found in the classpath." };
|
||||||
|
}
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.load(url.openStream());
|
||||||
|
return new String[] { "${COMMAND-FULL-NAME} " + properties.getProperty("VERSION_GRADLE") + "-" + properties.getProperty("VERSION_BUILD") };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue