You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2022/02/05 14:09:46 UTC
[logging-log4j2] branch release-2.x updated: Log4j 1.2 bridge now supports SocketAppender.
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/release-2.x by this push:
new 6573f8a Log4j 1.2 bridge now supports SocketAppender.
6573f8a is described below
commit 6573f8a4ed58112c15748aa4a34a051754b68be9
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sat Feb 5 09:09:42 2022 -0500
Log4j 1.2 bridge now supports SocketAppender.
First commit.
TODO: multicast support.
---
.../builders/appender/SocketAppenderBuilder.java | 164 +++++++++++++++++++++
.../config/SocketAppenderConfigurationTest.java | 80 ++++++++++
.../src/test/resources/log4j1-socket.properties | 25 ++++
log4j-1.2-api/src/test/resources/log4j1-socket.xml | 36 +++++
src/changes/changes.xml | 3 +
5 files changed, 308 insertions(+)
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SocketAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SocketAppenderBuilder.java
new file mode 100644
index 0000000..e16e140
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SocketAppenderBuilder.java
@@ -0,0 +1,164 @@
+/*
+ * 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 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.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+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.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.SocketAppender;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+/**
+ * Build a Console Appender
+ */
+@Plugin(name = "org.apache.log4j.net.SocketAppender", category = CATEGORY)
+public class SocketAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
+
+ private static final String HOST_PARAM = "RemoteHost";
+ private static final String PORT_PARAM = "Port";
+ private static final String RECONNECTION_DELAY_PARAM = "ReconnectionDelay";
+ private static final int DEFAULT_PORT = 4560;
+
+ /**
+ * The default reconnection delay (30000 milliseconds or 30 seconds).
+ */
+ private static final int DEFAULT_RECONNECTION_DELAY = 30_000;
+
+ public static final Logger LOGGER = StatusLogger.getLogger();
+
+ public SocketAppenderBuilder() {
+ }
+
+ public SocketAppenderBuilder(final String prefix, final Properties props) {
+ super(prefix, props);
+ }
+
+ private <T extends Log4j1Configuration> Appender createAppender(final String name, final String host, final int port, final Layout layout,
+ final Filter filter, final String level, final boolean immediateFlush, final int reconnectDelayMillis, final T configuration) {
+ org.apache.logging.log4j.core.Layout<?> actualLayout = null;
+ if (layout instanceof LayoutWrapper) {
+ actualLayout = ((LayoutWrapper) layout).getLayout();
+ } else if (layout != null) {
+ actualLayout = new LayoutAdapter(layout);
+ }
+ final org.apache.logging.log4j.core.Filter actualFilter = buildFilters(level, filter);
+ // @formatter:off
+ return new AppenderWrapper(SocketAppender.newBuilder()
+ .withHost(host)
+ .withPort(port)
+ .withReconnectDelayMillis(reconnectDelayMillis)
+ .setName(name)
+ .setLayout(actualLayout)
+ .setFilter(actualFilter)
+ .setConfiguration(configuration)
+ .setImmediateFlush(immediateFlush)
+ .build());
+ // @formatter:on
+ }
+
+ @Override
+ public Appender parseAppender(final Element appenderElement, final XmlConfiguration config) {
+ final String name = getNameAttribute(appenderElement);
+ final AtomicReference<String> host = new AtomicReference<>("localhost");
+ final AtomicInteger port = new AtomicInteger(DEFAULT_PORT);
+ final AtomicInteger reconnectDelay = new AtomicInteger(DEFAULT_RECONNECTION_DELAY);
+ final AtomicReference<Layout> layout = new AtomicReference<>();
+ final AtomicReference<List<Filter>> filters = new AtomicReference<>(new ArrayList<>());
+ final AtomicReference<String> level = new AtomicReference<>();
+ final AtomicBoolean immediateFlush = new AtomicBoolean(true);
+ forEachElement(appenderElement.getChildNodes(), currentElement -> {
+ switch (currentElement.getTagName()) {
+ case LAYOUT_TAG:
+ layout.set(config.parseLayout(currentElement));
+ break;
+ case FILTER_TAG:
+ filters.get().add(config.parseFilters(currentElement));
+ break;
+ case PARAM_TAG:
+ switch (getNameAttributeKey(currentElement)) {
+ case HOST_PARAM:
+ set(HOST_PARAM, currentElement, host);
+ break;
+ case PORT_PARAM:
+ set(PORT_PARAM, currentElement, port);
+ break;
+ case RECONNECTION_DELAY_PARAM:
+ set(RECONNECTION_DELAY_PARAM, currentElement, reconnectDelay);
+ break;
+ case THRESHOLD_PARAM:
+ set(THRESHOLD_PARAM, currentElement, level);
+ break;
+ case IMMEDIATE_FLUSH_PARAM:
+ set(IMMEDIATE_FLUSH_PARAM, currentElement, immediateFlush);
+ break;
+ }
+ break;
+ }
+ });
+ Filter head = null;
+ Filter current = null;
+ for (final Filter f : filters.get()) {
+ if (head == null) {
+ head = f;
+ } else {
+ current.next = f;
+ }
+ current = f;
+ }
+ return createAppender(name, host.get(), port.get(), layout.get(), head, level.get(), immediateFlush.get(), reconnectDelay.get(), config);
+ }
+
+ @Override
+ public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix, final String filterPrefix, final Properties props,
+ final PropertiesConfiguration configuration) {
+ // @formatter:off
+ return createAppender(name,
+ getProperty(HOST_PARAM),
+ getIntegerProperty(PORT_PARAM, DEFAULT_PORT),
+ configuration.parseLayout(layoutPrefix, name, props),
+ configuration.parseAppenderFilters(props, filterPrefix, name),
+ getProperty(THRESHOLD_PARAM),
+ getBooleanProperty(IMMEDIATE_FLUSH_PARAM),
+ getIntegerProperty(RECONNECTION_DELAY_PARAM, DEFAULT_RECONNECTION_DELAY),
+ configuration);
+ // @formatter:on
+ }
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/SocketAppenderConfigurationTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/SocketAppenderConfigurationTest.java
new file mode 100644
index 0000000..5fbaf30
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/SocketAppenderConfigurationTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.appender.SocketAppender;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.filter.ThresholdFilter;
+import org.apache.logging.log4j.core.net.Protocol;
+import org.apache.logging.log4j.core.net.TcpSocketManager;
+import org.junit.Test;
+
+/**
+ * Tests configuring a Syslog appender.
+ */
+public class SocketAppenderConfigurationTest {
+
+ private void check(final Protocol expected, final Configuration configuration) {
+ final Map<String, Appender> appenders = configuration.getAppenders();
+ assertNotNull(appenders);
+ final String appenderName = "socket";
+ final Appender appender = appenders.get(appenderName);
+ assertNotNull(appender, "Missing appender " + appenderName);
+ final SocketAppender syslogAppender = (SocketAppender) appender;
+ @SuppressWarnings("resource")
+ final TcpSocketManager manager = (TcpSocketManager) syslogAppender.getManager();
+ final String prefix = expected + ":";
+ assertTrue(manager.getName().startsWith(prefix), () -> String.format("'%s' does not start with '%s'", manager.getName(), prefix));
+ // Threshold
+ final ThresholdFilter filter = (ThresholdFilter) syslogAppender.getFilter();
+ assertEquals(Level.DEBUG, filter.getLevel());
+ // Host
+ assertEquals("localhost", manager.getHost());
+ // Port
+ assertEquals(9999, manager.getPort());
+ // Port
+ assertEquals(100, manager.getReconnectionDelayMillis());
+ }
+
+ private void checkProtocolPropertiesConfig(final Protocol expected, final String xmlPath) throws IOException {
+ check(expected, TestConfigurator.configure(xmlPath).getConfiguration());
+ }
+
+ private void checkProtocolXmlConfig(final Protocol expected, final String xmlPath) throws IOException {
+ check(expected, TestConfigurator.configure(xmlPath).getConfiguration());
+ }
+
+ @Test
+ public void testProperties() throws Exception {
+ checkProtocolXmlConfig(Protocol.TCP, "target/test-classes/log4j1-socket.properties");
+ }
+
+ @Test
+ public void testXml() throws Exception {
+ checkProtocolXmlConfig(Protocol.TCP, "target/test-classes/log4j1-socket.xml");
+ }
+
+}
diff --git a/log4j-1.2-api/src/test/resources/log4j1-socket.properties b/log4j-1.2-api/src/test/resources/log4j1-socket.properties
new file mode 100644
index 0000000..3072b46
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-socket.properties
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+log4j.rootLogger=DEBUG,socket
+log4j.appender.socket=org.apache.log4j.net.SocketAppender
+log4j.appender.socket.remoteHost=localhost
+log4j.appender.socket.port=9999
+log4j.appender.socket.reconnectionDelay=100
+log4j.appender.socket.layout=org.apache.log4j.PatternLayout
+log4j.appender.socket.layout.conversionPattern=Main[%pid] :%t: %c %-4p - %m\n
+log4j.appender.socket.Threshold=DEBUG
diff --git a/log4j-1.2-api/src/test/resources/log4j1-socket.xml b/log4j-1.2-api/src/test/resources/log4j1-socket.xml
new file mode 100644
index 0000000..eca3a0f
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-socket.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="socket" class="org.apache.log4j.net.SocketAppender">
+ <param name="RemoteHost" value="localhost"/>
+ <param name="Port" value="9999"/>
+ <param name="ReconnectionDelay" value="100"/>
+ <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>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d8cb19f..75eb9bb 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -160,6 +160,9 @@
<action dev="ggregory" type="fix" due-to="Piotr P. Karwasz">
Log4j 1.2 bridge uses some incorrect default property values in some appenders.
</action>
+ <action dev="ggregory" type="fix" due-to="Gary Gregory">
+ Log4j 1.2 bridge supports the SocketAppender.
+ </action>
<action dev="ggregory" type="fix" due-to="Gary Gregory, Piotr P. Karwasz">
</action>
<action dev="ggregory" type="fix">