This is an automated email from the ASF dual-hosted git repository.
rgoers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/master by this push:
new 6d19687 LOG4J2-63 - Add SyslogAppender
6d19687 is described below
commit 6d196870f66e69d05465c2167bb0a5d702232bd3
Author: Ralph Goers <[email protected]>
AuthorDate: Sat Nov 23 20:54:56 2019 -0700
LOG4J2-63 - Add SyslogAppender
---
.../builders/appender/SyslogAppenderBuilder.java | 173 +++++++++++++++++++++
.../apache/log4j/config/SyslogAppenderTest.java | 82 ++++++++++
log4j-1.2-api/src/test/resources/log4j1-syslog.xml | 36 +++++
3 files changed, 291 insertions(+)
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
new file mode 100644
index 0000000..0600279
--- /dev/null
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.SyslogAppender;
+import org.apache.logging.log4j.core.layout.SyslogLayout;
+import org.apache.logging.log4j.core.net.Facility;
+import org.apache.logging.log4j.core.net.Protocol;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+/**
+ * Build a File Appender
+ */
+@Plugin(name = "org.apache.log4j.net.SyslogAppender", category = CATEGORY)
+public class SyslogAppenderBuilder extends AbstractBuilder implements
AppenderBuilder {
+
+ private static final Logger LOGGER = StatusLogger.getLogger();
+ private static final String FACILITY_PARAM = "Facility";
+ private static final String SYSLOG_HOST_PARAM = "SyslogHost";
+ private static int SYSLOG_PORT = 512;
+
+ public SyslogAppenderBuilder() {
+ }
+
+ public SyslogAppenderBuilder(String prefix, Properties props) {
+ super(prefix, props);
+ }
+
+ @Override
+ public Appender parseAppender(Element appenderElement, XmlConfiguration
config) {
+ String name = appenderElement.getAttribute(NAME_ATTR);
+ Holder<Layout> layout = new Holder<>();
+ Holder<Filter> filter = new Holder<>();
+ Holder<String> facility = new Holder<>();
+ Holder<String> level = new Holder<>();
+ Holder<String> host = new Holder<>();
+ forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+ switch (currentElement.getTagName()) {
+ case LAYOUT_TAG:
+ layout.set(config.parseLayout(currentElement));
+ break;
+ case FILTER_TAG:
+ filter.set(config.parseFilters(currentElement));
+ break;
+ case PARAM_TAG: {
+ switch (currentElement.getAttribute(NAME_ATTR)) {
+ case SYSLOG_HOST_PARAM: {
+ host.set(currentElement.getAttribute(VALUE_ATTR));
+ break;
+ }
+ case FACILITY_PARAM:
+
facility.set(currentElement.getAttribute(VALUE_ATTR));
+ break;
+ case THRESHOLD_PARAM: {
+ String value =
currentElement.getAttribute(VALUE_ATTR);
+ if (value == null) {
+ LOGGER.warn("No value supplied for Threshold
parameter, ignoring.");
+ } else {
+ level.set(value);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ });
+
+ return createAppender(name, config, layout.get(), facility.get(),
filter.get(), host.get(), level.get());
+ }
+
+
+ @Override
+ public Appender parseAppender(final String name, final String
layoutPrefix, final String filterPrefix,
+ final Properties props, final PropertiesConfiguration
configuration) {
+ Filter filter = configuration.parseAppenderFilters(props,
filterPrefix, name);
+ Layout layout = configuration.parseLayout(layoutPrefix, name, props);
+ String level = getProperty(THRESHOLD_PARAM);
+ String facility = getProperty(FACILITY_PARAM, "LOCAL0");
+ String syslogHost = getProperty(SYSLOG_HOST_PARAM, "localhost:514");
+
+ return createAppender(name, configuration, layout, facility, filter,
syslogHost, level);
+ }
+
+ private Appender createAppender(final String name, final
Log4j1Configuration configuration, Layout layout,
+ String facility, final Filter filter, final String syslogHost,
final String level) {
+ Holder<String> host = new Holder<>();
+ Holder<Integer> port = new Holder<>();
+ resolveSyslogHost(syslogHost, host, port);
+ org.apache.logging.log4j.core.Layout appenderLayout;
+ if (layout instanceof LayoutWrapper) {
+ appenderLayout = ((LayoutWrapper) layout).getLayout();
+ } else if (layout != null) {
+ appenderLayout = new LayoutAdapter(layout);
+ } else {
+ appenderLayout = SyslogLayout.newBuilder()
+ .setFacility(Facility.toFacility(facility))
+ .setConfiguration(configuration)
+ .build();
+ }
+
+ org.apache.logging.log4j.core.Filter fileFilter = buildFilters(level,
filter);
+ return new AppenderWrapper(SyslogAppender.newBuilder()
+ .setName(name)
+ .setConfiguration(configuration)
+ .setLayout(appenderLayout)
+ .setFilter(fileFilter)
+ .setPort(port.get())
+ .setProtocol(Protocol.TCP)
+ .setHost(host.get())
+ .build());
+ }
+
+ private void resolveSyslogHost(String syslogHost, Holder<String> host,
Holder<Integer> port) {
+ int urlPort = -1;
+
+ //
+ // If not an unbracketed IPv6 address then
+ // parse as a URL
+ //
+ String[] parts = syslogHost.split(":");
+ if (parts.length == 1) {
+ host.set(parts[0]);
+ port.set(SYSLOG_PORT);
+ } else if (parts.length == 2) {
+ host.set(parts[0]);
+ port.set(Integer.parseInt(parts[1]));
+ } else {
+ LOGGER.warn("Invalid syslogHost setting: {}. Using default",
syslogHost);
+ host.set("localhost");
+ port.set(SYSLOG_PORT);
+ }
+ }
+}
diff --git
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/SyslogAppenderTest.java
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/SyslogAppenderTest.java
new file mode 100644
index 0000000..7ccb463
--- /dev/null
+++
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/SyslogAppenderTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.log4j.config;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.net.mock.MockSyslogServer;
+import org.apache.logging.log4j.core.net.mock.MockSyslogServerFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+
+
+/**
+ * Class Description goes here.
+ */
+public class SyslogAppenderTest {
+
+ private static final int PORTNUM = 9999;
+ private MockSyslogServer syslogServer;
+
+ @BeforeClass
+ public static void beforeClass() {
+ System.setProperty("log4j.configuration",
"target/test-classes/log4j1-syslog.xml");
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void teardown() {
+ if (syslogServer != null) {
+ syslogServer.shutdown();
+ }
+ }
+
+ @Test
+ public void sendMessage() throws Exception {
+ initTCPTestEnvironment(null);
+ Logger logger = LogManager.getLogger(SyslogAppenderTest.class);
+ logger.info("This is a test");
+ List<String> messages = null;
+ for (int i = 0; i < 5; ++i) {
+ Thread.sleep(250);
+ messages = syslogServer.getMessageList();
+ if (messages != null && messages.size() > 0) {
+ break;
+ }
+ }
+ assertNotNull("No messages received", messages);
+ assertEquals("Sent message not detected", 1, messages.size());
+ }
+
+
+ protected void initTCPTestEnvironment(final String messageFormat) throws
IOException {
+ syslogServer = MockSyslogServerFactory.createTCPSyslogServer(1,
PORTNUM);
+ syslogServer.start();
+ }
+}
diff --git a/log4j-1.2-api/src/test/resources/log4j1-syslog.xml
b/log4j-1.2-api/src/test/resources/log4j1-syslog.xml
new file mode 100644
index 0000000..4fd96a8
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-syslog.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="syslog" class="org.apache.log4j.net.SyslogAppender">
+ <param name="SyslogHost" value="localhost:9999"/>
+ <param name="Facility" value="USER"/>
+ <param name="FacilityPrinting" value="true"/>
+ <param name="Threshold" value="DEBUG"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p
%c{1}:%L - %m%n" />
+ </layout>
+ </appender>
+
+ <root>
+ <priority value ="trace" />
+ <appender-ref ref="syslog" />
+ </root>
+
+</log4j:configuration>
\ No newline at end of file