diff --git a/README.md b/README.md index e8d84d2..0306c63 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,35 @@ # Syslog Server -All received messages are written to *stdout* and/or forwarded to another syslog server. +All received messages are written to *stdout* and/or forwarded to a remote logging solution. The syslog server is able to listen on both UDP and TCP and parses syslog messages in either RFC5424 or RFC3164 (BSD) format. The default syslog port (514) requires you to run syslogd as root / administrator. If you do not wish to do so, you can choose a port number (with the *-p* or *--port* flag) above 1024. +Supported remote logging solutions are Syslog (RFC5424 over UDP), Graylog (GELF over UDP) and Grafana Loki. + ## Usage Instructions - Install the syslogd package (*.deb* or *.rpm*) from [downloads](https://bitbucket.org/mnellemann/syslogd/downloads/) or build from source. - Run *bin/syslogd*, use the *-h* option for help :) -```` -Usage: syslogd [-dghV] [--[no-]ansi] [--[no-]stdout] [--[no-]tcp] [--[no-]udp] - [--rfc5424] [-f=] [-p=] -Syslog Server - -d, --debug Enable debugging [default: 'false']. - -f, --forward= Forward to UDP host[:port] (RFC-5424). - -g, --gelf Forward in Graylog (GELF) JSON format. - -h, --help Show this help message and exit. - --[no-]ansi Output ANSI colors [default: true]. - --[no-]stdout Output messages to stdout [default: true]. - --[no-]tcp Listen on TCP [default: true]. - --[no-]udp Listen on UDP [default: true]. - -p, --port= Listening port [default: 514]. - --rfc5424 Parse RFC-5424 messages [default: RFC-3164]. - -V, --version Print version information and exit. -```` +```text +Usage: syslogd [-dhV] [--[no-]ansi] [--[no-]stdout] [--[no-]tcp] [--[no-]udp] + [--rfc5424] [-g=] [-l=] [-p=] [-s=] + -d, --debug Enable debugging [default: 'false']. + -g, --gelf= Forward to Graylog . + -h, --help Show this help message and exit. + -l, --loki= Forward to Grafana Loki . + --[no-]ansi Output ANSI colors [default: true]. + --[no-]stdout Output messages to stdout [default: true]. + --[no-]tcp Listen on TCP [default: true]. + --[no-]udp Listen on UDP [default: true]. + -p, --port= Listening port [default: 514]. + --rfc5424 Parse RFC-5424 messages [default: RFC-3164]. + -s, --syslog= Forward to Syslog (RFC-5424). + -V, --version Print version information and exit. +``` ### Examples @@ -46,30 +48,40 @@ or, if installed as a *deb* or *rpm* package: Listening on the standard syslog port (requires root privileges) and forwarding messages on to another log-system on a non-standard port. ``` -java -jar /path/to/syslogd-x.y.z-all.jar --forward remotehost:1514 +java -jar /path/to/syslogd-x.y.z-all.jar --syslog udp://remotehost:514 ``` Forwarding to a Graylog server in GELF format. ``` -java -jar /path/to/syslogd-x.y.z-all.jar --forward remotehost:12201 --gelf +java -jar /path/to/syslogd-x.y.z-all.jar --gelf udp://remotehost:12201 ``` +Forwarding to a Grafana Loki server. + +``` +java -jar /path/to/syslogd-x.y.z-all.jar --loki http://remotehost:3100 +``` If you don't want any output locally (only forwarding), you can use the ```--no-stdout``` flag. ## Notes +### IBM AIX and VIO Servers + Syslog messages from AIX (and IBM Power Virtual I/O Servers) can be troublesome with some logging solutions. These can be received with -syslogd and optionally forwarded on to Graylog, Splunk or other logging solutions. +syslogd and then forwarded on to your preferred logging solution. -## Development - +## Development Notes ### Test Grafana Loki +Run Loki and Grafana in local containers to test. + ```shell docker run --rm -d --name=loki -p 3100:3100 grafana/loki +docker run --rm -d --name=grafana --link loki:loki -p 3000:3000 grafana/grafana:7.1.3 ``` + diff --git a/gradle.properties b/gradle.properties index 199c37e..3887c25 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ id = syslogd group = biz.nellemann.syslogd -version = 1.0.13 +version = 1.0.14 diff --git a/src/main/java/biz/nellemann/syslogd/Application.java b/src/main/java/biz/nellemann/syslogd/Application.java index 3b92d13..8f1ff14 100644 --- a/src/main/java/biz/nellemann/syslogd/Application.java +++ b/src/main/java/biz/nellemann/syslogd/Application.java @@ -30,6 +30,9 @@ import picocli.CommandLine.Command; import java.io.IOException; import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URL; +import java.util.Locale; import java.util.concurrent.Callable; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -46,7 +49,7 @@ public class Application implements Callable, LogListener { private LokiClient lokiClient; - @CommandLine.Option(names = {"-p", "--port"}, description = "Listening port [default: 514].", defaultValue = "514") + @CommandLine.Option(names = {"-p", "--port"}, description = "Listening port [default: 514].", defaultValue = "514", paramLabel = "") private int port; @CommandLine.Option(names = "--no-udp", negatable = true, description = "Listen on UDP [default: true].", defaultValue = "true") @@ -64,14 +67,14 @@ public class Application implements Callable, LogListener { @CommandLine.Option(names = "--rfc5424", description = "Parse RFC-5424 messages [default: RFC-3164].", defaultValue = "false") private boolean rfc5424; - @CommandLine.Option(names = { "-s", "--syslog"}, description = "Forward to Syslog UDP host[:port] (RFC-5424).", paramLabel = "") - private String syslog; + @CommandLine.Option(names = { "-s", "--syslog"}, description = "Forward to Syslog (RFC-5424).", paramLabel = "") + private URI syslog; - @CommandLine.Option(names = { "-g", "--gelf"}, description = "Forward to Graylog host[:port] (GELF).", paramLabel = "") - private String gelf; + @CommandLine.Option(names = { "-g", "--gelf"}, description = "Forward to Graylog .", paramLabel = "") + private URI gelf; - @CommandLine.Option(names = { "-l", "--loki"}, description = "Forward to Grafana Loki.", paramLabel = "") - private String loki; + @CommandLine.Option(names = { "-l", "--loki"}, description = "Forward to Grafana Loki .", paramLabel = "") + private URL loki; @CommandLine.Option(names = { "-d", "--debug" }, description = "Enable debugging [default: 'false'].") private boolean enableDebug = false; @@ -90,17 +93,26 @@ public class Application implements Callable, LogListener { syslogParser = new SyslogParserRfc3164(); } - if(syslog != null && !syslog.isEmpty()) { - udpClient = new UdpClient(getInetSocketAddress(syslog)); - doForward = true; + if(syslog != null) { + if(syslog.getScheme().toLowerCase(Locale.ROOT).equals("udp")) { + udpClient = new UdpClient(getInetSocketAddress(syslog)); + doForward = true; + } else { + throw new UnsupportedOperationException("Syslog protocol not implemented: " + syslog.getScheme()); + } } - if(gelf != null && !gelf.isEmpty()) { - gelfClient = new UdpClient(getInetSocketAddress(gelf)); - doForward = true; + if(gelf != null) { + System.err.println(gelf.getScheme()); + if(gelf.getScheme().toLowerCase(Locale.ROOT).equals("udp")) { + gelfClient = new UdpClient(getInetSocketAddress(gelf)); + doForward = true; + } else { + throw new UnsupportedOperationException("GELF protocol not implemented: " + gelf.getScheme()); + } } - if(loki != null && !loki.isEmpty()) { + if(loki != null) { lokiClient = new LokiClient(loki); doForward = true; } @@ -167,6 +179,12 @@ public class Application implements Callable, LogListener { } + private InetSocketAddress getInetSocketAddress(URI input) { + InetSocketAddress inetSocketAddress = new InetSocketAddress(input.getHost(), input.getPort()); + return inetSocketAddress; + } + + private InetSocketAddress getInetSocketAddress(String input) { String dstHost; diff --git a/src/main/java/biz/nellemann/syslogd/net/LokiClient.java b/src/main/java/biz/nellemann/syslogd/net/LokiClient.java index 800f022..7eda2b9 100644 --- a/src/main/java/biz/nellemann/syslogd/net/LokiClient.java +++ b/src/main/java/biz/nellemann/syslogd/net/LokiClient.java @@ -3,9 +3,7 @@ package biz.nellemann.syslogd.net; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; import java.io.OutputStream; import java.net.*; import java.nio.charset.StandardCharsets; @@ -17,49 +15,33 @@ public class LokiClient { private final URL url; - public LokiClient(String url) throws MalformedURLException { - this.url = new URL(url); + public LokiClient(URL url) { + this.url = url; } public void send(String msg) throws MalformedURLException { URL pushUrl = new URL(url, "/loki/api/v1/push"); - log.warn("send() - URL: " + pushUrl.toString()); - HttpURLConnection con = null; try { con = (HttpURLConnection)pushUrl.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "application/json"); - //con.setRequestProperty("Content-Type", "application/json; utf-8"); - //con.setRequestProperty("Accept", "application/json"); con.setDoOutput(true); - byte[] input = msg.getBytes(StandardCharsets.US_ASCII); + byte[] input = msg.getBytes(StandardCharsets.UTF_8); try(OutputStream os = con.getOutputStream()) { os.write(input, 0, input.length); - log.warn("send() - Data: " + msg); } catch (IOException e) { - e.printStackTrace(); + log.warn(e.getMessage()); } - StringBuilder content; - - try (BufferedReader br = new BufferedReader( - new InputStreamReader(con.getInputStream()))) { - - String line; - content = new StringBuilder(); - - while ((line = br.readLine()) != null) { - content.append(line); - content.append(System.lineSeparator()); - } + int responseCode = con.getResponseCode(); + if(responseCode != 204) { + log.warn("send() - response: " + responseCode); } - System.out.println(content.toString()); - } catch (IOException e) { log.warn("send() - " + e.getMessage()); } finally {