Compare commits

..

7 Commits

12 changed files with 909 additions and 35 deletions

10
.gitignore vendored
View File

@ -24,3 +24,13 @@
hs_err_pid*
replay_pid*
**/.DS_Store
**/*.class
/bin/
/.project
/.classpath
/.factorypath
/.settings/
/target/
/.apt_generated/
/.apt_generated_tests/

View File

@ -1,3 +1,46 @@
# Verteilte_Systeme
# PU 1: "Praktikum Service-Discovery"
Bearbeitung Prüfungsvorleistung für Verteilte Systeme
Dieses Projekt wurde von der **Gruppe D** entwickelt:
**Antoniadis Dimitrios, Dexheimer Fynn, Schmitt Corinna**
Dieses Projekt implementiert einen Syslog-Server auf Basis von UDP gemäß dem RFC 5424 Standard. Es beinhaltet eine automatische Service-Discovery via Broadcast.
> **Hinweis:** Um den Server zu testen, wird ein entsprechender Client benötigt. Das System setzt die installierten Technologien **Java** und **Maven** voraus. Die Nutzung von **Just** ist optional und dient lediglich der vereinfachten Ausführung der Befehle.
## Projektstruktur & Klassen
* **`pom.xml`**: Maven-Konfigurationsdatei für Abhängigkeiten und Build-Prozess.
* **`justfile`**: Automatisierungsskript für einfache Ausführung (`just server`).
* **`vs.SyslogServer`**: Der Hauptdienst. Er startet zwei parallele Threads:
* **Syslog-Service**: Empfängt Log-Nachrichten auf Port 514, validiert die Länge und trennt Metadaten optisch vom Nachrichteninhalt.
* **Discovery-Service**: Antwortet auf Broadcast-Anfragen auf Port 8888, um Clients die Server-IP mitzuteilen.
* **`vs.SyslogMessage`**: Kernklasse zur Erzeugung/Repräsentation standardkonformer Nachrichten (inkl. Header, Zeitstempel und Structured Data).
* **`vs.AsciiChars` / `vs.StructuredData`**: Hilfsklassen zur Einhaltung der RFC-Spezifikationen.
## Funktionsablauf (Service Discovery & Logging)
1. **Broadcast**: Ein Client sendet ein UDP-Paket an die Broadcast-Adresse `255.255.255.255:8888`.
2. **Antwort**: Der Server empfängt den Suchruf und sendet ein Bestätigungs-Paket an den Client zurück.
3. **Identifikation**: Der Client extrahiert die IP-Adresse des Servers aus dem Antwort-Paket.
4. **Logging**: Der Client formatiert die Nachricht nach RFC 5424 und sendet sie direkt an den Server (Port 514).
5. **Verarbeitung**: Der Server empfängt das Datenpaket, validiert die Länge, entfernt das Byte Order Mark (BOM) und trennt die RFC-Metadaten optisch vom eigentlichen Nachrichteninhalt für eine strukturierte Konsolenausgabe.
## Ausführung
Stellen Sie sicher, dass **Java** und **Maven** auf Ihrem System installiert sind. Die Installation von **Just** wird empfohlen, ist jedoch optional.
### 1. Konfiguration für Linux/macOS
Da das `justfile` standardmäßig für die PowerShell optimiert ist, passen Sie bei der Nutzung von Unix-basierten Systemen bitte die erste Zeile im `justfile` an:
* Ändern Sie `set shell := ["powershell.exe", "-c"]` zu `set shell := ["sh", "-c"]`.
### 2. Wichtige Befehle
Nutzen Sie `just`, um die folgenden Aufgaben automatisiert auszuführen:
* **Kompilieren**: `just compile`
* **Server starten**: `just server`
* **Projekt aufräumen**: `just clean`
**Hinweise:**
* Weitere Befehle (z. B. für Tests oder Javadoc) finden Sie direkt im `justfile`.
* Falls Sie **Just** nicht verwenden möchten, können die entsprechenden Maven-Befehle (z. B. `mvn compile` oder `mvn exec:java...`) direkt genutzt werden.

View File

@ -1,33 +0,0 @@
In dieser Aufgabe soll ein Logging-System entwickelt werden, das das Syslog-Protokoll (RFC 5424) unterstützt.
Dabei sollen abweichend von der Spezifikation in RFC 5424 die folgenden Vereinfachungen gelten:
- Als Transportprotokoll soll ausschließlich UDP verwendet werden.
- TLS (Transport Layer Security) braucht nicht betrachtet werden.
- Der Syslog-Server braucht die empfangenen Daten nur nachrichtenweise auf der Konsole (Standard-Ausgabe) ausgeben.
Dabei sollen Informationen über den sendenden Client (insb. IP-Adresse) mitausgegeben werden.
- Strukturierte Daten brauchen nicht berücksichtigt werden.
Berücksichtigen Sie unbedingt die maximale Nachrichtenlänge und prüfen Sie, dass Nachrichten, die von Clients empfangen werden auch kurz genug sind.
Abweichend vom Syslog-Protokoll soll der Server folgende zusätzliche Eigenschaften haben:
- Die IP-Adresse des Logging-Dienstes muss vom Client durch eine automatische Service Discovery ermittelt werden.
Clients sollen die IP-Adresse des Servers also durch Broadcast-Nachrichten selbstständig ermitteln können.
Es ist möglich, diese Anforderung unberücksichtigt zu lassen und die IP-Adresse des Servers fest zu konfigurieren. Es gibt dann aber bis zu 8 Punkte Abzug.
- Der Server soll zwei UDP-Sockets verwenden: einen auf dem SYSLOG-Standard-Port und den anderen auf dem Port 8888 für die Auto-Discovery.
- (Broadcast-) Nachrichten an 8888 sollen ähnlich wie bei DHCP beantwortet werden.
Da der Absender aber bereits eine IP-Adresse hat, kann hier direkt eine UDP-Nachricht zurückgeschickt werden.
Die zurückgeschickte Nachricht kann leer sein, der Client kann daraus trotzdem die Adresse des SYSLOG-Servers (seine IP-Adresse) auslesen
und dann Log-Nachrichten an den SYSLOG-Port auf dem Host mit der so gefundenen IP-Adresse senden.
Entwickeln Sie den Server in Java. Ein Client (in einer beliebigen Programmiersprache) ermöglicht Ihnen das Testen, ist aber nicht abzugeben.
Geben Sie den Quellcode des Servers in Form eines Maven- oder Eclipse-Projekts als ZIP/TAR/TGZ-Archiv verpackt ab.
Client und Server sollen sich in demselben Sub-Netz befinden und über IP miteinander kommunizieren.
Zur Kommunikation dürfen nur Datagramme (UDP) verwendet werden.
Auf dem Ziel-System wird es nur genau ein Netzwerk geben (nicht Ethernet und Wifi mit getrennten Sub-Netzen).
Sie können daher Broadcast-Nachrichten an 255.255.255.255 schicken.
vs.pu01.tgz

20
justfile 100644
View File

@ -0,0 +1,20 @@
# Konfiguration für Windows (PowerShell).
# Falls Sie Linux/macOS nutzen, bitte diese Zeile in ["sh", "-c"] ändern:
set shell := ["powershell.exe", "-c"]
default:
mvn clean compile test
server: compile
mvn exec:java "-Dexec.mainClass=vs.SyslogServer"
client +args="": compile
mvn exec:java "-Dexec.mainClass=vs.SyslogClient" "-Dexec.args={{args}}"
exec class +args="": compile
mvn exec:java "-Dexec.mainClass=vs.{{class}}" "-Dexec.args={{args}}"
clean:
mvn clean
compile:
mvn compile
test: compile
mvn test
javadoc:
mvn javadoc:javadoc

60
pom.xml 100644
View File

@ -0,0 +1,60 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>vs</groupId>
<artifactId>vs.pu01</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.release>10</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency><!-- für Unit-Tests -->
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency><!-- für Lombok -->
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<dependency><!-- für net.jcip Annotationen -->
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin><!-- für Unit-Tests [mvn test] -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin><!-- [mvn compile] -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.9.0</version>
</plugin>
<plugin><!-- [mvn exec:java] -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin><!-- [mvn javadoc:javadoc] -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<show>private</show>
<locale>en_US</locale>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,87 @@
package vs;
/**
* helper class for RFC 5424 (https://datatracker.ietf.org/doc/html/rfc5424)
* compliant log messages as immutable Java objects - representation of a subset
* of printable strings of specific length
*
* @author Sandro Leuchter
*
*/
public abstract class AsciiChars {
private final String value;
public String value() {
return this.value;
}
protected AsciiChars(int length, String value) {
if (value != null) {
if (value.length() > length) {
throw new IllegalArgumentException(
"Stringlänge = " + value.length() + " > " + length
);
}
for (int c : value.getBytes()) {
if (c < 33 || c > 126) {
throw new IllegalArgumentException(
"Stringinhalt nicht printable US-ASCII ohne Space"
);
}
}
}
this.value = value;
}
@Override
public String toString() {
if (value() == null || value().length() == 0) {
return "-";
} else {
return value();
}
}
public static final class L004 extends AsciiChars {
public L004(String value) {
super(4, value);
}
}
public static final class L012 extends AsciiChars {
public L012(String value) {
super(12, value);
}
}
public static final class L032 extends AsciiChars {
public L032(String value) {
super(32, value);
}
}
public static final class L048 extends AsciiChars {
public L048(String value) {
super(48, value);
}
}
public static final class L128 extends AsciiChars {
public L128(String value) {
super(128, value);
}
}
public static final class L255 extends AsciiChars {
public L255(String value) {
super(255, value);
}
}
}

View File

@ -0,0 +1,180 @@
package vs;
import java.util.ArrayList;
import java.util.List;
/**
* helper class for RFC 5424 (https://datatracker.ietf.org/doc/html/rfc5424)
* compliant log messages as immutable Java objects - structured data (set of
* key/value-pairs) with some predefined sets according to the standard
*
* @author Sandro Leuchter
*
*/
public class StructuredData {
public static class Element {
private final String name;
private List<Param> parameters;
public static Element newTimeQuality(
boolean tzKnown,
boolean isSynced
) {
return newTimeQuality(tzKnown, isSynced, null);
}
public static Element newTimeQuality(
boolean tzKnown,
boolean isSynced,
Integer syncAccuracy
) {
var e = new Element("timeQuality");
e.add(new Param("tzKnown", (tzKnown) ? "1" : "0"));
e.add(new Param("isSynced", (isSynced) ? "1" : "0"));
if (syncAccuracy != null && !isSynced) {
e.add(new Param("syncAccuracy", String.valueOf(syncAccuracy)));
}
return e;
}
public static Element newOrigin(
String enterpriseId,
String software,
String swVersion
) {
return newOrigin(
new String[] {},
enterpriseId,
software,
swVersion
);
}
public static Element newOrigin(
String ip,
String enterpriseId,
String software,
String swVersion
) {
return newOrigin(
new String[] { ip },
enterpriseId,
software,
swVersion
);
}
public static Element newOrigin(
String[] ip,
String enterpriseId,
String software,
String swVersion
) {
var e = new Element("origin");
for (var p : ip) {
e = e.add(new Param("ip", p));
}
if (enterpriseId != null && !enterpriseId.equals("")) {
e = e.add(new Param("enterpriseId", enterpriseId));
}
if (software != null && !software.equals("")) {
e = e.add(new Param("software", software));
}
if (swVersion != null && !swVersion.equals("")) {
e = e.add(new Param("swVersion", swVersion));
}
return e;
}
public static Element newMeta(
Integer sequenceId,
Integer sysUpTime,
String language
) {
var e = new Element("meta");
if (sequenceId != null && sequenceId > 0) {
e = e.add(
new Param(
"sequenceId",
String.valueOf(sequenceId % 2147483647)
)
);
}
if (sysUpTime != null && sysUpTime >= 0) {
e = e.add(new Param("sysUpTime", String.valueOf(sysUpTime)));
}
if (language != null && !language.equals("")) {
e = e.add(new Param("language", language));
}
return e;
}
public Element(String name) {
this.name = name;
this.parameters = new ArrayList<>();
}
public Element add(Param parameter) {
var e = new Element(this.name);
e.parameters = this.parameters;
e.parameters.add(parameter);
return e;
}
@Override
public String toString() {
var str = "[" + this.name;
for (var p : this.parameters) {
str = str + " " + p.toString();
}
return str + "]";
}
}
public static class Param {
private final String name;
// name: printable US-ASCII string ^[@=\]\"\s]+
// "@" + private enterpise number "@\d+(\.\d+)*"
private final String value;
public Param(String name, String value) {
this.name = name; // 7-Bit ASCII
this.value = value; // UTF-8
}
@Override
public String toString() {
return this.name + "=\"" + this.value + "\"";
}
}
private List<Element> params;
public StructuredData() {
this.params = new ArrayList<>();
}
public StructuredData(List<Element> params) {
this.params = params;
}
public String toString() {
if (this.params.size() == 0) {
return "-";
}
var str = "";
for (var p : this.params) {
str = str + p.toString();
}
return str;
}
public StructuredData add(Element e) {
var p = this.params;
p.add(e);
return new StructuredData(p);
}
}

View File

@ -0,0 +1,61 @@
package vs;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
public class SyslogClient {
private static final int SYSLOG_PORT = 514;
private static final int DISCOVERY_PORT = 8888;
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket();
socket.setBroadcast(true);
// 1. SERVICE DISCOVERY
System.out.println("[CLIENT] Suche Syslog-Server via Broadcast...");
byte[] discoverMsg = "DISCOVER".getBytes();
DatagramPacket discoverPacket = new DatagramPacket(
discoverMsg, discoverMsg.length,
InetAddress.getByName("255.255.255.255"), DISCOVERY_PORT
);
socket.send(discoverPacket);
// Auf Antwort warten
byte[] buffer = new byte[256];
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
InetAddress serverAddress = response.getAddress();
System.out.println("[CLIENT] Server gefunden unter: " + serverAddress.getHostAddress());
// 2. NACHRICHT ERSTELLEN
String text = (args.length > 0) ? String.join(" ", args) : "Standard-Testnachricht";
SyslogMessage msg = new SyslogMessage(
SyslogMessage.Facility.USER,
SyslogMessage.Severity.INFORMATIONAL,
new AsciiChars.L255("mein-laptop"),
new AsciiChars.L048("SyslogClient"),
new AsciiChars.L128("PID1234"),
new AsciiChars.L032("MSG-01"),
new StructuredData().add(StructuredData.Element.newTimeQuality(true, true)),
new SyslogMessage.TextMessage(text)
);
// 3. SENDEN
String logString = msg.toString();
byte[] data = logString.getBytes(StandardCharsets.UTF_8);
DatagramPacket syslogPacket = new DatagramPacket(
data, data.length, serverAddress, SYSLOG_PORT
);
socket.send(syslogPacket);
System.out.println("[CLIENT] Nachricht gesendet: " + logString);
socket.close();
}
}

View File

@ -0,0 +1,213 @@
package vs;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* RFC 5424 (https://datatracker.ietf.org/doc/html/rfc5424) compliant log
* messages as immutable Java objects
*
* @author Sandro Leuchter
*
*/
public class SyslogMessage implements Serializable {
private static final long serialVersionUID = -5895573029109990861L;
private final Facility fac;
private final Severity sev;
private final AsciiChars.L255 host;
private final AsciiChars.L048 appName;
private final AsciiChars.L128 procId;
private final AsciiChars.L032 msgId;
private final StructuredData data;
private final Message message;
public SyslogMessage(
Facility fac,
Severity sev,
AsciiChars.L255 host,
AsciiChars.L048 appName,
AsciiChars.L128 procId,
AsciiChars.L032 msgId,
StructuredData data,
Message message
) {
this.fac = fac;
this.sev = sev;
this.host = host;
this.appName = appName;
this.procId = procId;
this.msgId = msgId;
this.data = data;
this.message = message;
}
public Facility fac() {
return this.fac;
}
public Severity sev() {
return sev;
}
public AsciiChars.L255 host() {
return host;
}
public AsciiChars.L048 appName() {
return appName;
}
public AsciiChars.L128 procId() {
return procId;
}
public AsciiChars.L032 msgId() {
return msgId;
}
public StructuredData data() {
return data;
}
public Message message() {
return message;
}
public static int version() {
return VERSION;
}
public static enum Facility {
KERNEL,
USER,
MAIL_SYSTEM,
SYS_DAEMON,
SECURITY1,
INTERNAL,
PRINTER,
NEWS,
UUCP,
CLOCK1,
SECURITY2,
FTP,
NTP,
AUDIT,
ALERT,
CLOCK2,
LOCAL0,
LOCAL1,
LOCAL2,
LOCAL3,
LOCAL4,
LOCAL5,
LOCAL6,
LOCAL7,
}
public static enum Severity {
EMERGENCY,
ALERT,
CRITICAL,
ERROR,
WARNING,
NOTICE,
INFORMATIONAL,
DEBUG,
}
public static interface Message {
public Object message();
public int length();
}
public static class BinaryMessage implements Message {
private Byte[] message;
public BinaryMessage(Byte[] message) {
this.message = message;
}
@Override
public String toString() {
return message.toString();
}
@Override
public Object message() {
return this.message;
}
@Override
public int length() {
return this.message.length;
}
}
public static class TextMessage implements Message {
private String message; // UTF8
public TextMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "\u00EF\u00BB\u00BF" + message.toString();
}
@Override
public Object message() {
return this.message;
}
@Override
public int length() {
return this.message.length();
}
}
static final int VERSION = 1; // RFC 5424, Mar 2009
@Override
public String toString() {
var prival = String.valueOf(fac().ordinal() * 8 + sev().ordinal());
var d = "";
if (data() != null) {
d = " " + data();
}
var m = "";
if (
message() != null &&
message().message() != null &&
message().length() > 0
) {
m = " " + message();
}
var timestamp = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(
new Date()
);
return (
"<" +
prival +
">" +
VERSION +
" " +
timestamp +
" " +
host().toString() +
" " +
appName().toString() +
" " +
procId().toString() +
" " +
msgId().toString() +
d +
m
);
}
}

View File

@ -0,0 +1,84 @@
package vs;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.charset.StandardCharsets;
public class SyslogServer {
private static final int SYSLOG_PORT = 514;
private static final int DISCOVERY_PORT = 8888;
private static final int MAX_MESSAGE_LENGTH = 1024;
public static void main(String[] args) {
System.out.println("=== Syslog Server Management ===");
// Startet den Syslog-Server
new Thread(() -> runSyslogServer()).start();
// Startet den Discovery-Server
new Thread(() -> runDiscoveryServer()).start();
}
private static void runSyslogServer() {
try (DatagramSocket socket = new DatagramSocket(SYSLOG_PORT)) {
byte[] buffer = new byte[2048];
System.out.println("[INFO] Syslog-Dienst aktiv auf Port " + SYSLOG_PORT);
while (true) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
int length = packet.getLength();
if (length > MAX_MESSAGE_LENGTH) {
System.err.println("[WARN] Nachricht von " + packet.getAddress() + " zu lang. Ignoriert.");
continue;
}
String raw = new String(packet.getData(), 0, length, StandardCharsets.UTF_8);
String clean = raw.replace("\uFEFF", "").replace("", "");
// Trennung von Metadaten und Inhalt
int splitIndex = clean.lastIndexOf("]") + 1;
String metadata = "Unbekannt";
String messageContent = clean;
if (splitIndex > 0 && splitIndex < clean.length()) {
metadata = clean.substring(0, splitIndex).trim();
messageContent = clean.substring(splitIndex).trim();
}
String separator = "==================================================";
System.out.println("\n" + separator);
System.out.println("NEUE SYSLOG-NACHRICHT");
System.out.println("Quelle: " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
System.out.println("Metadaten: " + metadata);
System.out.println("Inhalt: " + messageContent);
System.out.println(separator);
}
} catch (IOException e) {
System.err.println("[ERROR] Syslog-Server Fehler: " + e.getMessage());
}
}
private static void runDiscoveryServer() {
try (DatagramSocket socket = new DatagramSocket(DISCOVERY_PORT)) {
byte[] buffer = new byte[256];
System.out.println("[INFO] Discovery-Service aktiv auf Port " + DISCOVERY_PORT);
while (true) {
DatagramPacket request = new DatagramPacket(buffer, buffer.length);
socket.receive(request);
DatagramPacket response = new DatagramPacket(
new byte[0], 0, request.getAddress(), request.getPort()
);
socket.send(response);
System.out.println("[DISCOVERY] Server-IP an Client mit der IP [" + request.getAddress().getHostAddress() + "] gemeldet.");
}
} catch (IOException e) {
System.err.println("[ERROR] Discovery-Fehler: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,56 @@
package vs;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class AsciiCharsTest {
@Test
void nullValue() {
var ac = new AsciiChars.L004(null);
assertEquals(ac.toString(), "-");
}
@Test
void emptyValue() {
var ac = new AsciiChars.L004("");
assertEquals(ac.toString(), "-");
}
@Test
void longValue() {
var ac = new AsciiChars.L004("1234");
assertEquals(ac.toString(), "1234");
}
@Test
void longerValue() {
var thrown = assertThrows(IllegalArgumentException.class, () -> {
new AsciiChars.L004("12345");
});
assertEquals("Stringlänge = 5 > 4", thrown.getMessage());
}
@Test
void space() {
var thrown = assertThrows(IllegalArgumentException.class, () -> {
new AsciiChars.L004("1 1");
});
assertEquals(
"Stringinhalt nicht printable US-ASCII ohne Space",
thrown.getMessage()
);
}
@Test
void special() {
var thrown = assertThrows(IllegalArgumentException.class, () -> {
new AsciiChars.L004("ä");
});
assertEquals(
"Stringinhalt nicht printable US-ASCII ohne Space",
thrown.getMessage()
);
}
}

View File

@ -0,0 +1,93 @@
package vs;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import vs.StructuredData.*;
import vs.SyslogMessage.*;
class SyslogMessageTest {
@Test
void testToString() {
var m1 = new SyslogMessage(
//
Facility.SECURITY1, //
Severity.CRITICAL, //
new AsciiChars.L255("mymachine.example.com"), //
new AsciiChars.L048("su"), //
new AsciiChars.L128(""), //
new AsciiChars.L032("ID47"), //
new StructuredData() //
.add(Element.newTimeQuality(true, true))
.add(
new Element("exampleSDID@32473")
.add(new Param("iut", "3"))
.add(new Param("eventSource", "Application"))
.add(new Param("eventID", "1011"))
)
.add(
new Element("examplePriority@32473").add(
new Param("class", "high")
)
),
new TextMessage("'su root' failed for lonvick on /dev/pts/8")
);
var s = m1.toString();
assertEquals(s.substring(0, 6), "<34>1 ");
assertEquals(
s.substring(s.length() - 221, s.length()),
" mymachine.example.com su - ID47 [timeQuality tzKnown=\"1\" isSynced=\"1\"][exampleSDID@32473 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@32473 class=\"high\"] 'su root' failed for lonvick on /dev/pts/8"
);
}
@Test
void test2() {
var m1 = new SyslogMessage(
//
Facility.SECURITY1, //
Severity.CRITICAL, //
new AsciiChars.L255("mymachine.example.com"), //
new AsciiChars.L048("su"), //
new AsciiChars.L128(""), //
new AsciiChars.L032("ID47"), //
null, //
new TextMessage("'su root' failed for lonvick on /dev/pts/8")
);
var s = m1.toString();
assertEquals(s.substring(0, 6), "<34>1 ");
assertEquals(
s.substring(s.length() - 78, s.length()),
" mymachine.example.com su - ID47 'su root' failed for lonvick on /dev/pts/8"
);
}
@Test
void test3() {
var m1 = new SyslogMessage(
//
Facility.SECURITY1, //
Severity.CRITICAL, //
new AsciiChars.L255("mymachine.example.com"), //
new AsciiChars.L048("su"), //
new AsciiChars.L128(""), //
new AsciiChars.L032("ID47"), //
new StructuredData() //
.add(Element.newTimeQuality(true, true))
.add(
Element.newOrigin(
new String[] { "0.0.8.8", "8.8.8.8" },
null,
null,
null
)
)
.add(Element.newMeta(null, 32, "de")),
new BinaryMessage(null)
);
assertEquals(
m1.data().toString(),
"[timeQuality tzKnown=\"1\" isSynced=\"1\"][origin ip=\"0.0.8.8\" ip=\"8.8.8.8\"][meta sysUpTime=\"32\" language=\"de\"]"
);
}
}