Improve robustness of GELF forwarding and parsing.
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing

This commit is contained in:
Mark Nellemann 2023-01-22 11:44:03 +01:00
parent b291f87693
commit c47f682c34
8 changed files with 47 additions and 23 deletions

View file

@ -11,13 +11,13 @@ steps:
- name: publish - name: publish
image: eclipse-temurin:8-jdk image: eclipse-temurin:8-jdk
environment: environment:
AUTH_TOKEN: # Gitea authentication: username:token AUTH_TOKEN: # Gitea access token ENV variable
from_secret: auth # Name of DroneCI secret exposing above from_secret: auth # Name of DroneCI secret exposed above
commands: commands:
- ./gradlew packages - ./gradlew packages
- for file in build/libs/*-all.jar ; do curl --user "$${AUTH_TOKEN}" --upload-file "$${file}" "https://git.data.coop/api/packages/${DRONE_REPO_OWNER}/generic/${DRONE_REPO_NAME}/${DRONE_TAG}/$(basename $file)" ; done - for file in build/libs/*-all.jar ; do curl --user "${DRONE_REPO_OWNER}:$${AUTH_TOKEN}" --upload-file "$${file}" "https://git.data.coop/api/packages/${DRONE_REPO_OWNER}/generic/${DRONE_REPO_NAME}/${DRONE_TAG}/$(basename $file)" ; done
- for file in build/distributions/*.deb ; do curl --user "$${AUTH_TOKEN}" --upload-file "$${file}" "https://git.data.coop/api/packages/${DRONE_REPO_OWNER}/generic/${DRONE_REPO_NAME}/${DRONE_TAG}/$(basename $file)" ; done - for file in build/distributions/*.deb ; do curl --user "${DRONE_REPO_OWNER}:$${AUTH_TOKEN}" --upload-file "$${file}" "https://git.data.coop/api/packages/${DRONE_REPO_OWNER}/generic/${DRONE_REPO_NAME}/${DRONE_TAG}/$(basename $file)" ; done
- for file in build/distributions/*.rpm ; do curl --user "$${AUTH_TOKEN}" --upload-file "$${file}" "https://git.data.coop/api/packages/${DRONE_REPO_OWNER}/generic/${DRONE_REPO_NAME}/${DRONE_TAG}/$(basename $file)" ; done - for file in build/distributions/*.rpm ; do curl --user "${DRONE_REPO_OWNER}:$${AUTH_TOKEN}" --upload-file "$${file}" "https://git.data.coop/api/packages/${DRONE_REPO_OWNER}/generic/${DRONE_REPO_NAME}/${DRONE_TAG}/$(basename $file)" ; done
when: when:
event: event:
- tag - tag

View file

@ -4,7 +4,7 @@ Description=Syslog Director
[Service] [Service]
TimeoutStartSec=0 TimeoutStartSec=0
Restart=always Restart=always
ExecStart=/opt/syslogd/bin/syslogd --port 514 --no-stdout --syslog=udp://localhost:1514 ExecStart=/opt/syslogd/bin/syslogd --port 514 --no-ansi
[Install] [Install]
WantedBy=default.target WantedBy=default.target

View file

@ -1,5 +1,5 @@
id = syslogd id = syslogd
name = syslogd name = syslogd
group = biz.nellemann.syslogd group = biz.nellemann.syslogd
version = 1.3.1 version = 1.3.2
description = "Syslog Director" description = "Syslog Director"

View file

@ -103,18 +103,18 @@ public class SyslogPrinter {
* @return * @return
*/ */
public static String toGelf(SyslogMessage msg) { public static String toGelf(SyslogMessage msg) {
StringBuilder sb = new StringBuilder("{ \"version\": \"1.1\","); StringBuilder sb = new StringBuilder("{ \"version\": \"1.1\"");
sb.append(String.format("\"host\": \"%s\",", msg.hostname)); sb.append(String.format(", \"host\": \"%s\"", msg.hostname));
sb.append(String.format("\"short_message\": \"%s\",", JsonUtil.encode(msg.message))); sb.append(String.format(", \"short_message\": \"%s\"", JsonUtil.encode(msg.message)));
sb.append(String.format("\"full_message\": \"%s\",", msg.structuredData)); sb.append(String.format(", \"full_message\": \"%s\"", JsonUtil.encode(msg.structuredData)));
sb.append(String.format("\"timestamp\": %d,", msg.timestamp.getEpochSecond())); sb.append(String.format(", \"timestamp\": %d", msg.timestamp.getEpochSecond()));
sb.append(String.format("\"level\": %d,", msg.severity.toNumber())); sb.append(String.format(", \"level\": %d", msg.severity.toNumber()));
sb.append(String.format("\"_facility\": \"%s\",", msg.facility)); sb.append(String.format(", \"_facility\": \"%s\"", msg.facility));
sb.append(String.format("\"_severity\": \"%s\",", msg.severity)); sb.append(String.format(", \"_severity\": \"%s\"", msg.severity));
sb.append(String.format("\"_application\": \"%s\",", msg.application)); sb.append(String.format(", \"_application\": \"%s\"", msg.application));
if(msg.processId != null) { sb.append(String.format("\"_process-id\": \"%s\",", msg.processId)); } if(msg.processId != null) { sb.append(String.format(", \"_process-id\": \"%s\"", msg.processId)); }
if(msg.messageId != null) { sb.append(String.format("\"_message-id\": \"%s\",", msg.messageId)); } if(msg.messageId != null) { sb.append(String.format(", \"_message-id\": \"%s\"", msg.messageId)); }
if(msg.structuredData != null) { sb.append(String.format("\"_structured-data\": \"%s\",", msg.structuredData)); } if(msg.structuredData != null) { sb.append(String.format(", \"_structured-data\": \"%s\"", JsonUtil.encode(msg.structuredData))); }
sb.append("}"); sb.append("}");
return sb.toString(); return sb.toString();
} }

View file

@ -26,10 +26,16 @@ import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
public class TcpServer { public class TcpServer {
private final static Logger log = LoggerFactory.getLogger(TcpServer.class);
private final int port; private final int port;
private ServerSocket serverSocket; private ServerSocket serverSocket;
@ -91,14 +97,14 @@ public class TcpServer {
sendEvent(inputLine); sendEvent(inputLine);
} }
} catch (IOException e) { } catch (IOException e) {
System.err.printf("TcpServer - error: %s\n", e.getMessage()); log.warn("run() - read error: {}", e.getMessage());
} }
try { try {
in.close(); in.close();
clientSocket.close(); clientSocket.close();
} catch (IOException e) { } catch (IOException e) {
System.err.printf("TcpServer - error: %s\n", e.getMessage()); log.warn("run() - close error: {}", e.getMessage());
} }
} }

View file

@ -24,8 +24,13 @@ import java.net.DatagramSocket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UdpServer extends Thread { public class UdpServer extends Thread {
private final static Logger log = LoggerFactory.getLogger(UdpServer.class);
protected DatagramSocket socket; protected DatagramSocket socket;
protected boolean listen = true; protected boolean listen = true;
@ -44,7 +49,7 @@ public class UdpServer extends Thread {
//String packetData = new String(packet.getData(), packet.getOffset(), packet.getLength(), StandardCharsets.UTF_8); //String packetData = new String(packet.getData(), packet.getOffset(), packet.getLength(), StandardCharsets.UTF_8);
sendEvent(packet); sendEvent(packet);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); log.error("run() - error: {}", e.getMessage());
listen = false; listen = false;
} }
} }

View file

@ -81,11 +81,12 @@ public class GelfParser extends SyslogParser {
@Override @Override
public SyslogMessage parse(String input) { public SyslogMessage parse(String input) {
if(!input.startsWith("{")) return null; // Avoid trying to parse non-JSON content
SyslogMessage message = null; SyslogMessage message = null;
try { try {
message = objectMapper.readValue(input, SyslogMessage.class); message = objectMapper.readValue(input, SyslogMessage.class);
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
log.warn("parse() - error: {}", e.getMessage()); log.debug("parse() - error: {}", e.getMessage());
} }
return message; return message;
} }

View file

@ -85,4 +85,16 @@ class GelfParserTest extends Specification {
} }
void "junk GET request"() {
setup:
def input = 'GET /'
when:
SyslogMessage msg = syslogParser.parse(input)
then:
msg == null
}
} }