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

Reply via email to