Skip to content

Commit

Permalink
Add syslog writer (#507)
Browse files Browse the repository at this point in the history
Co-authored-by: pkarlowicz <[email protected]>
  • Loading branch information
pkarlowicz and pkarlowicz authored Aug 18, 2023
1 parent ec0777a commit 1566c7f
Show file tree
Hide file tree
Showing 10 changed files with 1,070 additions and 0 deletions.
69 changes: 69 additions & 0 deletions tinylog-impl/src/main/java/org/tinylog/writers/SyslogWriter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2023 Piotr Karlowicz
*
* 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 org.tinylog.writers;

import java.io.IOException;
import java.util.Locale;
import java.util.Map;

import org.tinylog.core.LogEntry;
import org.tinylog.writers.raw.AbstractSocketWriter;
import org.tinylog.writers.raw.TcpSocketWriter;
import org.tinylog.writers.raw.UdpSocketWriter;

/**
* Writer for outputting log entries to syslog server.
*/
public final class SyslogWriter extends AbstractFormatPatternWriter {

private AbstractSocketWriter socketWriter;

/**
* @param properties
* Configuration for writer
*
* @throws IOException
* Socket cannot be opened for write access
* @throws IllegalArgumentException
* A property has an invalid value or is missing in configuration
*/
public SyslogWriter(final Map<String, String> properties) throws IllegalArgumentException, IOException {
super(properties);

String protocol = getStringValue("protocol");
if (protocol == null || protocol.toUpperCase(Locale.ROOT).equals("UDP")) {
socketWriter = new UdpSocketWriter(properties);
} else if (protocol.toUpperCase(Locale.ROOT).equals("TCP")) {
socketWriter = new TcpSocketWriter(properties);
} else {
throw new IllegalArgumentException("Invalid protocol");
}
}

@Override
public void write(final LogEntry logEntry) throws Exception {
socketWriter.write(logEntry);
}

@Override
public void flush() throws Exception {
socketWriter.flush();
}

@Override
public void close() throws Exception {
socketWriter.close();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright 2023 Piotr Karlowicz
*
* 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 org.tinylog.writers.raw;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.Map;

import org.tinylog.Level;
import org.tinylog.core.LogEntry;
import org.tinylog.writers.AbstractFormatPatternWriter;

/**
* Base writer for outputting log entries to syslog server.
*/
public abstract class AbstractSocketWriter extends AbstractFormatPatternWriter {

private static final String DEFAULT_HOST_NAME = "localhost";
private static final int DEFAULT_PORT_NUMBER = 514;
private static final String DEFAULT_FACILITY = "USER";
private static final int FACILITY_CODE_SHIFT = 3;
private static final String DEFAULT_SEVERITY = "INFO";

private final InetAddress inetAddress;
private final int port;
private final Charset charset;
private final String identification;

/**
* @param properties
* Configuration for writer
*
* @throws UnknownHostException
* Host name cannot be identified
*/
public AbstractSocketWriter(final Map<String, String> properties) throws UnknownHostException {
super(properties);

String host = getStringValue("host");
if (host == null) {
host = DEFAULT_HOST_NAME;
}
inetAddress = InetAddress.getByName("localhost");
String portNumber = getStringValue("port");
if (portNumber == null) {
port = DEFAULT_PORT_NUMBER;
} else {
port = Integer.parseInt(portNumber);
}
charset = super.getCharset();
String identification = getStringValue("identification");
if (identification == null) {
this.identification = "";
} else {
this.identification = identification;
}
}

public final InetAddress getInetAddress() {
return inetAddress;
}

public final int getPort() {
return port;
}

/**
* Return the priority code for facility and severity.
*
* @param level
* Log level to use when severity is not specified.
*
* @return The priority code calculated from facility and severity code.
*/
public int getCode(final Level level) {
String facility = getStringValue("facility");
String severity = getStringValue("severity");

if (facility == null) {
facility = DEFAULT_FACILITY;
}

int facilityCode = SyslogFacility.valueOf(facility).getCode();

if (severity == null) {
if (level != null) {
severity = SyslogSeverity.getSeverity(level).name();
} else {
severity = DEFAULT_SEVERITY;
}
}

int severityCode = SyslogSeverity.valueOf(severity).getCode();

return (facilityCode << FACILITY_CODE_SHIFT) + severityCode;
}

/**
* Return the formated syslog message.
*
* @param logEntry
* Log entry for rendering.
*
* @return The formated message.
*/
public byte[] formatMessage(final LogEntry logEntry) {
StringBuilder builder = new StringBuilder();
builder.append("<");
builder.append(getCode(logEntry.getLevel()));
builder.append(">");
builder.append(identification);
builder.append(": ");
builder.append(render(logEntry));
return builder.toString().getBytes(charset);
}

}
154 changes: 154 additions & 0 deletions tinylog-impl/src/main/java/org/tinylog/writers/raw/SyslogFacility.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright 2023 Piotr Karlowicz
*
* 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 org.tinylog.writers.raw;

/**
* Syslog Facility codes.
*/
public enum SyslogFacility {

/**
* Kernel messages.
*/
KERN(0),

/**
* User level messages.
*/
USER(1),

/**
* Mail system.
*/
MAIL(2),

/**
* System daemons.
*/
DAEMON(3),

/**
* Security/Authorization messages.
*/
AUTH(4),

/**
* Messages generated by syslogd.
*/
SYSLOG(5),

/**
* Line printer subsystem.
*/
LPR(6),

/**
* Network news subsystem.
*/
NEWS(7),

/**
* UUCP subsystem.
*/
UUCP(8),

/**
* Clock daemon.
*/
CRON(9),

/**
* Security/Authorization messages.
*/
AUTHPRIV(10),

/**
* FTP daemon.
*/
FTP(11),

/**
* NTP subsystem.
*/
NTP(12),

/**
* Log audit.
*/
LOG_AUDIT(13),

/**
* Log alert.
*/
LOG_ALERT(14),

/**
* Clock daemon.
*/
CLOCK(15),

/**
* Local use 0.
*/
LOCAL0(16),

/**
* Local use 1.
*/
LOCAL1(17),

/**
* Local use 2.
*/
LOCAL2(18),

/**
* Local use 3.
*/
LOCAL3(19),

/**
* Local use 4.
*/
LOCAL4(20),

/**
* Local use 5.
*/
LOCAL5(21),

/**
* Local use 6.
*/
LOCAL6(22),

/**
* Local use 7.
*/
LOCAL7(23);

private final int code;

SyslogFacility(final int code) {
this.code = code;
}

/**
* Retrieve the value of the enumeration.
* @return The value associated with the enumeration.
*/
public int getCode() {
return this.code;
}
}
Loading

0 comments on commit 1566c7f

Please sign in to comment.