Repository: logging-log4j2 Updated Branches: refs/heads/master 0295bcb47 -> 2f3724591
[LOG4J2-2228] Split off ZeroMq/JeroMq support into a new module log4j-jeromq. Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/2f372459 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/2f372459 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/2f372459 Branch: refs/heads/master Commit: 2f3724591c8cdb59cb8b2e10289b3365585afee8 Parents: 0295bcb Author: Gary Gregory <[email protected]> Authored: Sun Jan 28 08:57:15 2018 -0700 Committer: Gary Gregory <[email protected]> Committed: Sun Jan 28 08:57:15 2018 -0700 ---------------------------------------------------------------------- log4j-core/pom.xml | 6 - .../appender/mom/jeromq/JeroMqAppender.java | 185 ---------------- .../core/appender/mom/jeromq/JeroMqManager.java | 222 ------------------- .../core/appender/mom/jeromq/package-info.java | 23 -- .../appender/mom/jeromq/JeroMqAppenderTest.java | 139 ------------ .../appender/mom/jeromq/JeroMqTestClient.java | 55 ----- log4j-jeromq/pom.xml | 165 ++++++++++++++ .../appender/mom/jeromq/JeroMqAppender.java | 185 ++++++++++++++++ .../core/appender/mom/jeromq/JeroMqManager.java | 222 +++++++++++++++++++ log4j-jeromq/src/site/manual/index.md | 33 +++ log4j-jeromq/src/site/site.xml | 52 +++++ .../appender/mom/jeromq/JeroMqAppenderTest.java | 139 ++++++++++++ .../appender/mom/jeromq/JeroMqTestClient.java | 55 +++++ .../core/appender/db/jpa/log4j2-h2-jpa-base.xml | 38 ++++ .../appender/db/jpa/log4j2-h2-jpa-basic.xml | 38 ++++ .../appender/db/jpa/log4j2-hsqldb-jpa-base.xml | 38 ++++ .../appender/db/jpa/log4j2-hsqldb-jpa-basic.xml | 38 ++++ pom.xml | 1 + src/changes/changes.xml | 3 + src/site/xdoc/manual/appenders.xml | 3 + 20 files changed, 1010 insertions(+), 630 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-core/pom.xml ---------------------------------------------------------------------- diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index 4ae808a..ef854c1 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -126,12 +126,6 @@ <artifactId>kafka-clients</artifactId> <optional>true</optional> </dependency> - <!-- Used for ZeroMQ JeroMQ appender --> - <dependency> - <groupId>org.zeromq</groupId> - <artifactId>jeromq</artifactId> - <optional>true</optional> - </dependency> <!-- Used for compressing to formats other than zip and gz --> <dependency> <groupId>org.apache.commons</groupId> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java deleted file mode 100644 index aa78fad..0000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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.logging.log4j.core.appender.mom.jeromq; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.Filter; -import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.appender.AbstractAppender; -import org.apache.logging.log4j.core.config.Node; -import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.config.plugins.Plugin; -import org.apache.logging.log4j.core.config.plugins.PluginAttribute; -import org.apache.logging.log4j.core.config.plugins.PluginElement; -import org.apache.logging.log4j.core.config.plugins.PluginFactory; -import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; -import org.apache.logging.log4j.core.layout.PatternLayout; -import org.apache.logging.log4j.util.Strings; - -/** - * Sends log events to one or more ZeroMQ (JeroMQ) endpoints. - * <p> - * Requires the JeroMQ jar (LGPL as of 0.3.5) - * </p> - */ -// TODO -// Some methods are synchronized because a ZMQ.Socket is not thread-safe -// Using a ThreadLocal for the publisher hangs tests on shutdown. There must be -// some issue on threads owning certain resources as opposed to others. -@Plugin(name = "JeroMQ", category = Node.CATEGORY, elementType = Appender.ELEMENT_TYPE, printObject = true) -public final class JeroMqAppender extends AbstractAppender { - - private static final int DEFAULT_BACKLOG = 100; - - private static final int DEFAULT_IVL = 100; - - private static final int DEFAULT_RCV_HWM = 1000; - - private static final int DEFAULT_SND_HWM = 1000; - - private final JeroMqManager manager; - private final List<String> endpoints; - private int sendRcFalse; - private int sendRcTrue; - - private JeroMqAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout, - final boolean ignoreExceptions, final List<String> endpoints, final long affinity, final long backlog, - final boolean delayAttachOnConnect, final byte[] identity, final boolean ipv4Only, final long linger, - final long maxMsgSize, final long rcvHwm, final long receiveBufferSize, final int receiveTimeOut, - final long reconnectIVL, final long reconnectIVLMax, final long sendBufferSize, final int sendTimeOut, - final long sndHWM, final int tcpKeepAlive, final long tcpKeepAliveCount, final long tcpKeepAliveIdle, - final long tcpKeepAliveInterval, final boolean xpubVerbose) { - super(name, filter, layout, ignoreExceptions); - this.manager = JeroMqManager.getJeroMqManager(name, affinity, backlog, delayAttachOnConnect, identity, ipv4Only, - linger, maxMsgSize, rcvHwm, receiveBufferSize, receiveTimeOut, reconnectIVL, reconnectIVLMax, - sendBufferSize, sendTimeOut, sndHWM, tcpKeepAlive, tcpKeepAliveCount, tcpKeepAliveIdle, - tcpKeepAliveInterval, xpubVerbose, endpoints); - this.endpoints = endpoints; - } - - // The ZMQ.Socket class has other set methods that we do not cover because - // they throw unsupported operation exceptions. - @PluginFactory - public static JeroMqAppender createAppender( - // @formatter:off - @Required(message = "No name provided for JeroMqAppender") @PluginAttribute("name") final String name, - @PluginElement("Layout") Layout<?> layout, - @PluginElement("Filter") final Filter filter, - @PluginElement("Properties") final Property[] properties, - // Super attributes - @PluginAttribute("ignoreExceptions") final boolean ignoreExceptions, - // ZMQ attributes; defaults picked from zmq.Options. - @PluginAttribute(value = "affinity", defaultLong = 0) final long affinity, - @PluginAttribute(value = "backlog", defaultLong = DEFAULT_BACKLOG) final long backlog, - @PluginAttribute(value = "delayAttachOnConnect") final boolean delayAttachOnConnect, - @PluginAttribute(value = "identity") final byte[] identity, - @PluginAttribute(value = "ipv4Only", defaultBoolean = true) final boolean ipv4Only, - @PluginAttribute(value = "linger", defaultLong = -1) final long linger, - @PluginAttribute(value = "maxMsgSize", defaultLong = -1) final long maxMsgSize, - @PluginAttribute(value = "rcvHwm", defaultLong = DEFAULT_RCV_HWM) final long rcvHwm, - @PluginAttribute(value = "receiveBufferSize", defaultLong = 0) final long receiveBufferSize, - @PluginAttribute(value = "receiveTimeOut", defaultLong = -1) final int receiveTimeOut, - @PluginAttribute(value = "reconnectIVL", defaultLong = DEFAULT_IVL) final long reconnectIVL, - @PluginAttribute(value = "reconnectIVLMax", defaultLong = 0) final long reconnectIVLMax, - @PluginAttribute(value = "sendBufferSize", defaultLong = 0) final long sendBufferSize, - @PluginAttribute(value = "sendTimeOut", defaultLong = -1) final int sendTimeOut, - @PluginAttribute(value = "sndHwm", defaultLong = DEFAULT_SND_HWM) final long sndHwm, - @PluginAttribute(value = "tcpKeepAlive", defaultInt = -1) final int tcpKeepAlive, - @PluginAttribute(value = "tcpKeepAliveCount", defaultLong = -1) final long tcpKeepAliveCount, - @PluginAttribute(value = "tcpKeepAliveIdle", defaultLong = -1) final long tcpKeepAliveIdle, - @PluginAttribute(value = "tcpKeepAliveInterval", defaultLong = -1) final long tcpKeepAliveInterval, - @PluginAttribute(value = "xpubVerbose") final boolean xpubVerbose - // @formatter:on - ) { - if (layout == null) { - layout = PatternLayout.createDefaultLayout(); - } - List<String> endpoints; - if (properties == null) { - endpoints = new ArrayList<>(0); - } else { - endpoints = new ArrayList<>(properties.length); - for (final Property property : properties) { - if ("endpoint".equalsIgnoreCase(property.getName())) { - final String value = property.getValue(); - if (Strings.isNotEmpty(value)) { - endpoints.add(value); - } - } - } - } - LOGGER.debug("Creating JeroMqAppender with name={}, filter={}, layout={}, ignoreExceptions={}, endpoints={}", - name, filter, layout, ignoreExceptions, endpoints); - return new JeroMqAppender(name, filter, layout, ignoreExceptions, endpoints, affinity, backlog, - delayAttachOnConnect, identity, ipv4Only, linger, maxMsgSize, rcvHwm, receiveBufferSize, - receiveTimeOut, reconnectIVL, reconnectIVLMax, sendBufferSize, sendTimeOut, sndHwm, tcpKeepAlive, - tcpKeepAliveCount, tcpKeepAliveIdle, tcpKeepAliveInterval, xpubVerbose); - } - - @Override - public synchronized void append(final LogEvent event) { - final Layout<? extends Serializable> layout = getLayout(); - final byte[] formattedMessage = layout.toByteArray(event); - if (manager.send(getLayout().toByteArray(event))) { - sendRcTrue++; - } else { - sendRcFalse++; - LOGGER.error("Appender {} could not send message {} to JeroMQ {}", getName(), sendRcFalse, formattedMessage); - } - } - - @Override - public boolean stop(final long timeout, final TimeUnit timeUnit) { - setStopping(); - boolean stopped = super.stop(timeout, timeUnit, false); - stopped &= manager.stop(timeout, timeUnit); - setStopped(); - return stopped; - } - - // not public, handy for testing - int getSendRcFalse() { - return sendRcFalse; - } - - // not public, handy for testing - int getSendRcTrue() { - return sendRcTrue; - } - - // not public, handy for testing - void resetSendRcs() { - sendRcTrue = sendRcFalse = 0; - } - - @Override - public String toString() { - return "JeroMqAppender{" + - "name=" + getName() + - ", state=" + getState() + - ", manager=" + manager + - ", endpoints=" + endpoints + - '}'; - } -} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java deleted file mode 100644 index a438faf..0000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * 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.logging.log4j.core.appender.mom.jeromq; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.appender.AbstractManager; -import org.apache.logging.log4j.core.appender.ManagerFactory; -import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.zeromq.ZMQ; - -/** - * Manager for publishing messages via JeroMq. - * - * @since 2.6 - */ -public class JeroMqManager extends AbstractManager { - - /** - * System property to enable shutdown hook. - */ - public static final String SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK = "log4j.jeromq.enableShutdownHook"; - - /** - * System property to control JeroMQ I/O thread count. - */ - public static final String SYS_PROPERTY_IO_THREADS = "log4j.jeromq.ioThreads"; - - private static final JeroMqManagerFactory FACTORY = new JeroMqManagerFactory(); - private static final ZMQ.Context CONTEXT; - - static { - LOGGER.trace("JeroMqManager using ZMQ version {}", ZMQ.getVersionString()); - - final int ioThreads = PropertiesUtil.getProperties().getIntegerProperty(SYS_PROPERTY_IO_THREADS, 1); - LOGGER.trace("JeroMqManager creating ZMQ context with ioThreads = {}", ioThreads); - CONTEXT = ZMQ.context(ioThreads); - - final boolean enableShutdownHook = PropertiesUtil.getProperties().getBooleanProperty( - SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK, true); - if (enableShutdownHook) { - ((ShutdownCallbackRegistry) LogManager.getFactory()).addShutdownCallback(new Runnable() { - @Override - public void run() { - CONTEXT.close(); - } - }); - } - } - - private final ZMQ.Socket publisher; - - private JeroMqManager(final String name, final JeroMqConfiguration config) { - super(null, name); - publisher = CONTEXT.socket(ZMQ.PUB); - publisher.setAffinity(config.affinity); - publisher.setBacklog(config.backlog); - publisher.setDelayAttachOnConnect(config.delayAttachOnConnect); - if (config.identity != null) { - publisher.setIdentity(config.identity); - } - publisher.setIPv4Only(config.ipv4Only); - publisher.setLinger(config.linger); - publisher.setMaxMsgSize(config.maxMsgSize); - publisher.setRcvHWM(config.rcvHwm); - publisher.setReceiveBufferSize(config.receiveBufferSize); - publisher.setReceiveTimeOut(config.receiveTimeOut); - publisher.setReconnectIVL(config.reconnectIVL); - publisher.setReconnectIVLMax(config.reconnectIVLMax); - publisher.setSendBufferSize(config.sendBufferSize); - publisher.setSendTimeOut(config.sendTimeOut); - publisher.setSndHWM(config.sndHwm); - publisher.setTCPKeepAlive(config.tcpKeepAlive); - publisher.setTCPKeepAliveCount(config.tcpKeepAliveCount); - publisher.setTCPKeepAliveIdle(config.tcpKeepAliveIdle); - publisher.setTCPKeepAliveInterval(config.tcpKeepAliveInterval); - publisher.setXpubVerbose(config.xpubVerbose); - for (final String endpoint : config.endpoints) { - publisher.bind(endpoint); - } - LOGGER.debug("Created JeroMqManager with {}", config); - } - - public boolean send(final byte[] data) { - return publisher.send(data); - } - - @Override - protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) { - publisher.close(); - return true; - } - - public static JeroMqManager getJeroMqManager(final String name, final long affinity, final long backlog, - final boolean delayAttachOnConnect, final byte[] identity, - final boolean ipv4Only, final long linger, final long maxMsgSize, - final long rcvHwm, final long receiveBufferSize, - final int receiveTimeOut, final long reconnectIVL, - final long reconnectIVLMax, final long sendBufferSize, - final int sendTimeOut, final long sndHwm, final int tcpKeepAlive, - final long tcpKeepAliveCount, final long tcpKeepAliveIdle, - final long tcpKeepAliveInterval, final boolean xpubVerbose, - final List<String> endpoints) { - return getManager(name, FACTORY, - new JeroMqConfiguration(affinity, backlog, delayAttachOnConnect, identity, ipv4Only, linger, maxMsgSize, - rcvHwm, receiveBufferSize, receiveTimeOut, reconnectIVL, reconnectIVLMax, sendBufferSize, sendTimeOut, - sndHwm, tcpKeepAlive, tcpKeepAliveCount, tcpKeepAliveIdle, tcpKeepAliveInterval, xpubVerbose, - endpoints)); - } - - public static ZMQ.Context getContext() { - return CONTEXT; - } - - private static class JeroMqConfiguration { - private final long affinity; - private final long backlog; - private final boolean delayAttachOnConnect; - private final byte[] identity; - private final boolean ipv4Only; - private final long linger; - private final long maxMsgSize; - private final long rcvHwm; - private final long receiveBufferSize; - private final int receiveTimeOut; - private final long reconnectIVL; - private final long reconnectIVLMax; - private final long sendBufferSize; - private final int sendTimeOut; - private final long sndHwm; - private final int tcpKeepAlive; - private final long tcpKeepAliveCount; - private final long tcpKeepAliveIdle; - private final long tcpKeepAliveInterval; - private final boolean xpubVerbose; - private final List<String> endpoints; - - private JeroMqConfiguration(final long affinity, final long backlog, final boolean delayAttachOnConnect, - final byte[] identity, final boolean ipv4Only, final long linger, - final long maxMsgSize, final long rcvHwm, final long receiveBufferSize, - final int receiveTimeOut, final long reconnectIVL, final long reconnectIVLMax, - final long sendBufferSize, final int sendTimeOut, final long sndHwm, - final int tcpKeepAlive, final long tcpKeepAliveCount, final long tcpKeepAliveIdle, - final long tcpKeepAliveInterval, final boolean xpubVerbose, - final List<String> endpoints) { - this.affinity = affinity; - this.backlog = backlog; - this.delayAttachOnConnect = delayAttachOnConnect; - this.identity = identity; - this.ipv4Only = ipv4Only; - this.linger = linger; - this.maxMsgSize = maxMsgSize; - this.rcvHwm = rcvHwm; - this.receiveBufferSize = receiveBufferSize; - this.receiveTimeOut = receiveTimeOut; - this.reconnectIVL = reconnectIVL; - this.reconnectIVLMax = reconnectIVLMax; - this.sendBufferSize = sendBufferSize; - this.sendTimeOut = sendTimeOut; - this.sndHwm = sndHwm; - this.tcpKeepAlive = tcpKeepAlive; - this.tcpKeepAliveCount = tcpKeepAliveCount; - this.tcpKeepAliveIdle = tcpKeepAliveIdle; - this.tcpKeepAliveInterval = tcpKeepAliveInterval; - this.xpubVerbose = xpubVerbose; - this.endpoints = endpoints; - } - - @Override - public String toString() { - return "JeroMqConfiguration{" + - "affinity=" + affinity + - ", backlog=" + backlog + - ", delayAttachOnConnect=" + delayAttachOnConnect + - ", identity=" + Arrays.toString(identity) + - ", ipv4Only=" + ipv4Only + - ", linger=" + linger + - ", maxMsgSize=" + maxMsgSize + - ", rcvHwm=" + rcvHwm + - ", receiveBufferSize=" + receiveBufferSize + - ", receiveTimeOut=" + receiveTimeOut + - ", reconnectIVL=" + reconnectIVL + - ", reconnectIVLMax=" + reconnectIVLMax + - ", sendBufferSize=" + sendBufferSize + - ", sendTimeOut=" + sendTimeOut + - ", sndHwm=" + sndHwm + - ", tcpKeepAlive=" + tcpKeepAlive + - ", tcpKeepAliveCount=" + tcpKeepAliveCount + - ", tcpKeepAliveIdle=" + tcpKeepAliveIdle + - ", tcpKeepAliveInterval=" + tcpKeepAliveInterval + - ", xpubVerbose=" + xpubVerbose + - ", endpoints=" + endpoints + - '}'; - } - } - - private static class JeroMqManagerFactory implements ManagerFactory<JeroMqManager, JeroMqConfiguration> { - @Override - public JeroMqManager createManager(final String name, final JeroMqConfiguration data) { - return new JeroMqManager(name, data); - } - } -} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/package-info.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/package-info.java deleted file mode 100644 index b1df1e7..0000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -/** - * Classes and interfaces for ZeroMQ/JeroMQ support. - * - * @since 2.4 - */ -package org.apache.logging.log4j.core.appender.mom.jeromq; http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java deleted file mode 100644 index 24b8d25..0000000 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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.logging.log4j.core.appender.mom.jeromq; - -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.categories.Appenders; -import org.apache.logging.log4j.core.Logger; -import org.apache.logging.log4j.core.util.ExecutorServices; -import org.apache.logging.log4j.junit.LoggerContextRule; -import org.junit.Assert; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -@Category(Appenders.ZeroMq.class) -public class JeroMqAppenderTest { - - private static final String ENDPOINT = "tcp://localhost:5556"; - - private static final String APPENDER_NAME = "JeroMQAppender"; - - private static final int DEFAULT_TIMEOUT_MILLIS = 60000; - - @ClassRule - public static LoggerContextRule ctx = new LoggerContextRule("JeroMqAppenderTest.xml"); - - @Test(timeout = DEFAULT_TIMEOUT_MILLIS) - public void testAppenderLifeCycle() throws Exception { - // do nothing to make sure the appender starts and stops without - // locking up resources. - Assert.assertNotNull(JeroMqManager.getContext()); - } - - @Test(timeout = DEFAULT_TIMEOUT_MILLIS) - public void testClientServer() throws Exception { - final JeroMqAppender appender = ctx.getRequiredAppender(APPENDER_NAME, JeroMqAppender.class); - final int expectedReceiveCount = 3; - final JeroMqTestClient client = new JeroMqTestClient(JeroMqManager.getContext(), ENDPOINT, expectedReceiveCount); - final ExecutorService executor = Executors.newSingleThreadExecutor(); - try { - final Future<List<String>> future = executor.submit(client); - Thread.sleep(100); - final Logger logger = ctx.getLogger(getClass().getName()); - appender.resetSendRcs(); - logger.info("Hello"); - logger.info("Again"); - ThreadContext.put("foo", "bar"); - logger.info("World"); - final List<String> list = future.get(); - Assert.assertEquals(expectedReceiveCount, appender.getSendRcTrue()); - Assert.assertEquals(0, appender.getSendRcFalse()); - Assert.assertEquals("Hello", list.get(0)); - Assert.assertEquals("Again", list.get(1)); - Assert.assertEquals("barWorld", list.get(2)); - } finally { - executor.shutdown(); - } - } - - @Test(timeout = DEFAULT_TIMEOUT_MILLIS) - public void testMultiThreadedServer() throws Exception { - final int nThreads = 10; - final JeroMqAppender appender = ctx.getRequiredAppender(APPENDER_NAME, JeroMqAppender.class); - final int expectedReceiveCount = 2 * nThreads; - final JeroMqTestClient client = new JeroMqTestClient(JeroMqManager.getContext(), ENDPOINT, - expectedReceiveCount); - final ExecutorService executor = Executors.newSingleThreadExecutor(); - try { - final Future<List<String>> future = executor.submit(client); - Thread.sleep(100); - final Logger logger = ctx.getLogger(getClass().getName()); - appender.resetSendRcs(); - final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads); - for (int i = 0; i < 10.; i++) { - fixedThreadPool.submit(new Runnable() { - @Override - public void run() { - logger.info("Hello"); - logger.info("Again"); - } - }); - } - final List<String> list = future.get(); - Assert.assertEquals(expectedReceiveCount, appender.getSendRcTrue()); - Assert.assertEquals(0, appender.getSendRcFalse()); - int hello = 0; - int again = 0; - for (final String string : list) { - switch (string) { - case "Hello": - hello++; - break; - case "Again": - again++; - break; - default: - Assert.fail("Unexpected message: " + string); - } - } - Assert.assertEquals(nThreads, hello); - Assert.assertEquals(nThreads, again); - } finally { - ExecutorServices.shutdown(executor, DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, - JeroMqAppenderTest.class.getSimpleName()); - } - } - - @Test(timeout = DEFAULT_TIMEOUT_MILLIS) - public void testServerOnly() throws Exception { - final Logger logger = ctx.getLogger(getClass().getName()); - final JeroMqAppender appender = ctx.getRequiredAppender(APPENDER_NAME, JeroMqAppender.class); - appender.resetSendRcs(); - logger.info("Hello"); - logger.info("Again"); - Assert.assertEquals(2, appender.getSendRcTrue()); - Assert.assertEquals(0, appender.getSendRcFalse()); - } -} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java deleted file mode 100644 index ddd06ab..0000000 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.logging.log4j.core.appender.mom.jeromq; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; - -import org.zeromq.ZMQ; - -class JeroMqTestClient implements Callable<List<String>> { - - private final ZMQ.Context context; - - private final String endpoint; - private final List<String> messages; - private final int receiveCount; - - JeroMqTestClient(final ZMQ.Context context, final String endpoint, final int receiveCount) { - super(); - this.context = context; - this.endpoint = endpoint; - this.receiveCount = receiveCount; - this.messages = new ArrayList<>(receiveCount); - } - - @Override - public List<String> call() throws Exception { - try (ZMQ.Socket subscriber = context.socket(ZMQ.SUB)) { - subscriber.connect(endpoint); - subscriber.subscribe(new byte[0]); - for (int messageNum = 0; messageNum < receiveCount - && !Thread.currentThread().isInterrupted(); messageNum++) { - // Use trim to remove the tailing '0' character - messages.add(subscriber.recvStr(0).trim()); - } - } - return messages; - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/pom.xml ---------------------------------------------------------------------- diff --git a/log4j-jeromq/pom.xml b/log4j-jeromq/pom.xml new file mode 100644 index 0000000..77f4775 --- /dev/null +++ b/log4j-jeromq/pom.xml @@ -0,0 +1,165 @@ +<?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. --> + +<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j</artifactId> + <version>2.10.1-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>log4j-jeromq</artifactId> + <name>Apache Log4j JeroMQ</name> + <description> + Apache Log4j ZeroMQ using JeroMQ. + </description> + <properties> + <log4jParentDir>${basedir}/..</log4jParentDir> + <docLabel>Log4j ZeroMQ using JeroMQ Documentation</docLabel> + <projectDir>/log4j-jpa</projectDir> + <module.name>org.apache.logging.log4j.jeromq</module.name> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-core</artifactId> + </dependency> + <!-- Used for ZeroMQ JeroMQ appender --> + <dependency> + <groupId>org.zeromq</groupId> + <artifactId>jeromq</artifactId> + </dependency> + <!-- Test Dependencies --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + <type>test-jar</type> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-core</artifactId> + <type>test-jar</type> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <configuration> + <instructions> + <Fragment-Host>org.apache.logging.log4j.core.appender.mom.jeromq</Fragment-Host> + <Export-Package>*</Export-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + <reporting> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-changes-plugin</artifactId> + <version>${changes.plugin.version}</version> + <reportSets> + <reportSet> + <reports> + <report>changes-report</report> + </reports> + </reportSet> + </reportSets> + <configuration> + <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate> + <useJql>true</useJql> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-checkstyle-plugin</artifactId> + <version>${checkstyle.plugin.version}</version> + <configuration> + <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation> --> + <configLocation>${log4jParentDir}/checkstyle.xml</configLocation> + <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation> + <enableRulesSummary>false</enableRulesSummary> + <propertyExpansion>basedir=${basedir}</propertyExpansion> + <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>${javadoc.plugin.version}</version> + <configuration> + <bottom><![CDATA[<p align="center">Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br /> + Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.</p>]]></bottom> + <!-- module link generation is completely broken in the javadoc plugin for a multi-module non-aggregating project --> + <detectOfflineLinks>false</detectOfflineLinks> + <linksource>true</linksource> + </configuration> + <reportSets> + <reportSet> + <id>non-aggregate</id> + <reports> + <report>javadoc</report> + </reports> + </reportSet> + </reportSets> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <version>${findbugs.plugin.version}</version> + <configuration> + <fork>true</fork> + <jvmArgs>-Duser.language=en</jvmArgs> + <threshold>Normal</threshold> + <effort>Default</effort> + <excludeFilterFile>${log4jParentDir}/findbugs-exclude-filter.xml</excludeFilterFile> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jxr-plugin</artifactId> + <version>${jxr.plugin.version}</version> + <reportSets> + <reportSet> + <id>non-aggregate</id> + <reports> + <report>jxr</report> + </reports> + </reportSet> + <reportSet> + <id>aggregate</id> + <reports> + <report>aggregate</report> + </reports> + </reportSet> + </reportSets> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + <version>${pmd.plugin.version}</version> + <configuration> + <targetJdk>${maven.compiler.target}</targetJdk> + </configuration> + </plugin> + </plugins> + </reporting> +</project> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java ---------------------------------------------------------------------- diff --git a/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java b/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java new file mode 100644 index 0000000..aa78fad --- /dev/null +++ b/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java @@ -0,0 +1,185 @@ +/* + * 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.logging.log4j.core.appender.mom.jeromq; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.config.Node; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; +import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.apache.logging.log4j.util.Strings; + +/** + * Sends log events to one or more ZeroMQ (JeroMQ) endpoints. + * <p> + * Requires the JeroMQ jar (LGPL as of 0.3.5) + * </p> + */ +// TODO +// Some methods are synchronized because a ZMQ.Socket is not thread-safe +// Using a ThreadLocal for the publisher hangs tests on shutdown. There must be +// some issue on threads owning certain resources as opposed to others. +@Plugin(name = "JeroMQ", category = Node.CATEGORY, elementType = Appender.ELEMENT_TYPE, printObject = true) +public final class JeroMqAppender extends AbstractAppender { + + private static final int DEFAULT_BACKLOG = 100; + + private static final int DEFAULT_IVL = 100; + + private static final int DEFAULT_RCV_HWM = 1000; + + private static final int DEFAULT_SND_HWM = 1000; + + private final JeroMqManager manager; + private final List<String> endpoints; + private int sendRcFalse; + private int sendRcTrue; + + private JeroMqAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout, + final boolean ignoreExceptions, final List<String> endpoints, final long affinity, final long backlog, + final boolean delayAttachOnConnect, final byte[] identity, final boolean ipv4Only, final long linger, + final long maxMsgSize, final long rcvHwm, final long receiveBufferSize, final int receiveTimeOut, + final long reconnectIVL, final long reconnectIVLMax, final long sendBufferSize, final int sendTimeOut, + final long sndHWM, final int tcpKeepAlive, final long tcpKeepAliveCount, final long tcpKeepAliveIdle, + final long tcpKeepAliveInterval, final boolean xpubVerbose) { + super(name, filter, layout, ignoreExceptions); + this.manager = JeroMqManager.getJeroMqManager(name, affinity, backlog, delayAttachOnConnect, identity, ipv4Only, + linger, maxMsgSize, rcvHwm, receiveBufferSize, receiveTimeOut, reconnectIVL, reconnectIVLMax, + sendBufferSize, sendTimeOut, sndHWM, tcpKeepAlive, tcpKeepAliveCount, tcpKeepAliveIdle, + tcpKeepAliveInterval, xpubVerbose, endpoints); + this.endpoints = endpoints; + } + + // The ZMQ.Socket class has other set methods that we do not cover because + // they throw unsupported operation exceptions. + @PluginFactory + public static JeroMqAppender createAppender( + // @formatter:off + @Required(message = "No name provided for JeroMqAppender") @PluginAttribute("name") final String name, + @PluginElement("Layout") Layout<?> layout, + @PluginElement("Filter") final Filter filter, + @PluginElement("Properties") final Property[] properties, + // Super attributes + @PluginAttribute("ignoreExceptions") final boolean ignoreExceptions, + // ZMQ attributes; defaults picked from zmq.Options. + @PluginAttribute(value = "affinity", defaultLong = 0) final long affinity, + @PluginAttribute(value = "backlog", defaultLong = DEFAULT_BACKLOG) final long backlog, + @PluginAttribute(value = "delayAttachOnConnect") final boolean delayAttachOnConnect, + @PluginAttribute(value = "identity") final byte[] identity, + @PluginAttribute(value = "ipv4Only", defaultBoolean = true) final boolean ipv4Only, + @PluginAttribute(value = "linger", defaultLong = -1) final long linger, + @PluginAttribute(value = "maxMsgSize", defaultLong = -1) final long maxMsgSize, + @PluginAttribute(value = "rcvHwm", defaultLong = DEFAULT_RCV_HWM) final long rcvHwm, + @PluginAttribute(value = "receiveBufferSize", defaultLong = 0) final long receiveBufferSize, + @PluginAttribute(value = "receiveTimeOut", defaultLong = -1) final int receiveTimeOut, + @PluginAttribute(value = "reconnectIVL", defaultLong = DEFAULT_IVL) final long reconnectIVL, + @PluginAttribute(value = "reconnectIVLMax", defaultLong = 0) final long reconnectIVLMax, + @PluginAttribute(value = "sendBufferSize", defaultLong = 0) final long sendBufferSize, + @PluginAttribute(value = "sendTimeOut", defaultLong = -1) final int sendTimeOut, + @PluginAttribute(value = "sndHwm", defaultLong = DEFAULT_SND_HWM) final long sndHwm, + @PluginAttribute(value = "tcpKeepAlive", defaultInt = -1) final int tcpKeepAlive, + @PluginAttribute(value = "tcpKeepAliveCount", defaultLong = -1) final long tcpKeepAliveCount, + @PluginAttribute(value = "tcpKeepAliveIdle", defaultLong = -1) final long tcpKeepAliveIdle, + @PluginAttribute(value = "tcpKeepAliveInterval", defaultLong = -1) final long tcpKeepAliveInterval, + @PluginAttribute(value = "xpubVerbose") final boolean xpubVerbose + // @formatter:on + ) { + if (layout == null) { + layout = PatternLayout.createDefaultLayout(); + } + List<String> endpoints; + if (properties == null) { + endpoints = new ArrayList<>(0); + } else { + endpoints = new ArrayList<>(properties.length); + for (final Property property : properties) { + if ("endpoint".equalsIgnoreCase(property.getName())) { + final String value = property.getValue(); + if (Strings.isNotEmpty(value)) { + endpoints.add(value); + } + } + } + } + LOGGER.debug("Creating JeroMqAppender with name={}, filter={}, layout={}, ignoreExceptions={}, endpoints={}", + name, filter, layout, ignoreExceptions, endpoints); + return new JeroMqAppender(name, filter, layout, ignoreExceptions, endpoints, affinity, backlog, + delayAttachOnConnect, identity, ipv4Only, linger, maxMsgSize, rcvHwm, receiveBufferSize, + receiveTimeOut, reconnectIVL, reconnectIVLMax, sendBufferSize, sendTimeOut, sndHwm, tcpKeepAlive, + tcpKeepAliveCount, tcpKeepAliveIdle, tcpKeepAliveInterval, xpubVerbose); + } + + @Override + public synchronized void append(final LogEvent event) { + final Layout<? extends Serializable> layout = getLayout(); + final byte[] formattedMessage = layout.toByteArray(event); + if (manager.send(getLayout().toByteArray(event))) { + sendRcTrue++; + } else { + sendRcFalse++; + LOGGER.error("Appender {} could not send message {} to JeroMQ {}", getName(), sendRcFalse, formattedMessage); + } + } + + @Override + public boolean stop(final long timeout, final TimeUnit timeUnit) { + setStopping(); + boolean stopped = super.stop(timeout, timeUnit, false); + stopped &= manager.stop(timeout, timeUnit); + setStopped(); + return stopped; + } + + // not public, handy for testing + int getSendRcFalse() { + return sendRcFalse; + } + + // not public, handy for testing + int getSendRcTrue() { + return sendRcTrue; + } + + // not public, handy for testing + void resetSendRcs() { + sendRcTrue = sendRcFalse = 0; + } + + @Override + public String toString() { + return "JeroMqAppender{" + + "name=" + getName() + + ", state=" + getState() + + ", manager=" + manager + + ", endpoints=" + endpoints + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java ---------------------------------------------------------------------- diff --git a/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java b/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java new file mode 100644 index 0000000..0326ebe --- /dev/null +++ b/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java @@ -0,0 +1,222 @@ +/* + * 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.logging.log4j.core.appender.mom.jeromq; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.appender.AbstractManager; +import org.apache.logging.log4j.core.appender.ManagerFactory; +import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry; +import org.apache.logging.log4j.util.PropertiesUtil; +import org.zeromq.ZMQ; + +/** + * Manager for publishing messages via JeroMq. + * + * @since 2.6 + */ +public class JeroMqManager extends AbstractManager { + + /** + * System property to enable shutdown hook. + */ + public static final String SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK = "log4j.jeromq.enableShutdownHook"; + + /** + * System property to control JeroMQ I/O thread count. + */ + public static final String SYS_PROPERTY_IO_THREADS = "log4j.jeromq.ioThreads"; + + private static final JeroMqManagerFactory FACTORY = new JeroMqManagerFactory(); + private static final ZMQ.Context CONTEXT; + + static { + LOGGER.trace("JeroMqManager using ZMQ version {}", ZMQ.getVersionString()); + + final int ioThreads = PropertiesUtil.getProperties().getIntegerProperty(SYS_PROPERTY_IO_THREADS, 1); + LOGGER.trace("JeroMqManager creating ZMQ context with ioThreads = {}", ioThreads); + CONTEXT = ZMQ.context(ioThreads); + + final boolean enableShutdownHook = PropertiesUtil.getProperties().getBooleanProperty( + SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK, true); + if (enableShutdownHook) { + ((ShutdownCallbackRegistry) LogManager.getFactory()).addShutdownCallback(new Runnable() { + @Override + public void run() { + CONTEXT.close(); + } + }); + } + } + + private final ZMQ.Socket publisher; + + private JeroMqManager(final String name, final JeroMqConfiguration config) { + super(null, name); + publisher = CONTEXT.socket(ZMQ.PUB); + publisher.setAffinity(config.affinity); + publisher.setBacklog(config.backlog); + publisher.setDelayAttachOnConnect(config.delayAttachOnConnect); + if (config.identity != null) { + publisher.setIdentity(config.identity); + } + publisher.setIPv4Only(config.ipv4Only); + publisher.setLinger(config.linger); + publisher.setMaxMsgSize(config.maxMsgSize); + publisher.setRcvHWM(config.rcvHwm); + publisher.setReceiveBufferSize(config.receiveBufferSize); + publisher.setReceiveTimeOut(config.receiveTimeOut); + publisher.setReconnectIVL(config.reconnectIVL); + publisher.setReconnectIVLMax(config.reconnectIVLMax); + publisher.setSendBufferSize(config.sendBufferSize); + publisher.setSendTimeOut(config.sendTimeOut); + publisher.setSndHWM(config.sndHwm); + publisher.setTCPKeepAlive(config.tcpKeepAlive); + publisher.setTCPKeepAliveCount(config.tcpKeepAliveCount); + publisher.setTCPKeepAliveIdle(config.tcpKeepAliveIdle); + publisher.setTCPKeepAliveInterval(config.tcpKeepAliveInterval); + publisher.setXpubVerbose(config.xpubVerbose); + for (final String endpoint : config.endpoints) { + publisher.bind(endpoint); + } + LOGGER.debug("Created JeroMqManager with {}", config); + } + + public boolean send(final byte[] data) { + return publisher.send(data); + } + + @Override + protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) { + publisher.close(); + return true; + } + + public static JeroMqManager getJeroMqManager(final String name, final long affinity, final long backlog, + final boolean delayAttachOnConnect, final byte[] identity, + final boolean ipv4Only, final long linger, final long maxMsgSize, + final long rcvHwm, final long receiveBufferSize, + final int receiveTimeOut, final long reconnectIVL, + final long reconnectIVLMax, final long sendBufferSize, + final int sendTimeOut, final long sndHwm, final int tcpKeepAlive, + final long tcpKeepAliveCount, final long tcpKeepAliveIdle, + final long tcpKeepAliveInterval, final boolean xpubVerbose, + final List<String> endpoints) { + return getManager(name, FACTORY, + new JeroMqConfiguration(affinity, backlog, delayAttachOnConnect, identity, ipv4Only, linger, maxMsgSize, + rcvHwm, receiveBufferSize, receiveTimeOut, reconnectIVL, reconnectIVLMax, sendBufferSize, sendTimeOut, + sndHwm, tcpKeepAlive, tcpKeepAliveCount, tcpKeepAliveIdle, tcpKeepAliveInterval, xpubVerbose, + endpoints)); + } + + public static ZMQ.Context getContext() { + return CONTEXT; + } + + private static class JeroMqConfiguration { + private final long affinity; + private final long backlog; + private final boolean delayAttachOnConnect; + private final byte[] identity; + private final boolean ipv4Only; + private final long linger; + private final long maxMsgSize; + private final long rcvHwm; + private final long receiveBufferSize; + private final int receiveTimeOut; + private final long reconnectIVL; + private final long reconnectIVLMax; + private final long sendBufferSize; + private final int sendTimeOut; + private final long sndHwm; + private final int tcpKeepAlive; + private final long tcpKeepAliveCount; + private final long tcpKeepAliveIdle; + private final long tcpKeepAliveInterval; + private final boolean xpubVerbose; + private final List<String> endpoints; + + private JeroMqConfiguration(final long affinity, final long backlog, final boolean delayAttachOnConnect, + final byte[] identity, final boolean ipv4Only, final long linger, + final long maxMsgSize, final long rcvHwm, final long receiveBufferSize, + final int receiveTimeOut, final long reconnectIVL, final long reconnectIVLMax, + final long sendBufferSize, final int sendTimeOut, final long sndHwm, + final int tcpKeepAlive, final long tcpKeepAliveCount, final long tcpKeepAliveIdle, + final long tcpKeepAliveInterval, final boolean xpubVerbose, + final List<String> endpoints) { + this.affinity = affinity; + this.backlog = backlog; + this.delayAttachOnConnect = delayAttachOnConnect; + this.identity = identity; + this.ipv4Only = ipv4Only; + this.linger = linger; + this.maxMsgSize = maxMsgSize; + this.rcvHwm = rcvHwm; + this.receiveBufferSize = receiveBufferSize; + this.receiveTimeOut = receiveTimeOut; + this.reconnectIVL = reconnectIVL; + this.reconnectIVLMax = reconnectIVLMax; + this.sendBufferSize = sendBufferSize; + this.sendTimeOut = sendTimeOut; + this.sndHwm = sndHwm; + this.tcpKeepAlive = tcpKeepAlive; + this.tcpKeepAliveCount = tcpKeepAliveCount; + this.tcpKeepAliveIdle = tcpKeepAliveIdle; + this.tcpKeepAliveInterval = tcpKeepAliveInterval; + this.xpubVerbose = xpubVerbose; + this.endpoints = endpoints; + } + + @Override + public String toString() { + return "JeroMqConfiguration{" + + "affinity=" + affinity + + ", backlog=" + backlog + + ", delayAttachOnConnect=" + delayAttachOnConnect + + ", identity=" + Arrays.toString(identity) + + ", ipv4Only=" + ipv4Only + + ", linger=" + linger + + ", maxMsgSize=" + maxMsgSize + + ", rcvHwm=" + rcvHwm + + ", receiveBufferSize=" + receiveBufferSize + + ", receiveTimeOut=" + receiveTimeOut + + ", reconnectIVL=" + reconnectIVL + + ", reconnectIVLMax=" + reconnectIVLMax + + ", sendBufferSize=" + sendBufferSize + + ", sendTimeOut=" + sendTimeOut + + ", sndHwm=" + sndHwm + + ", tcpKeepAlive=" + tcpKeepAlive + + ", tcpKeepAliveCount=" + tcpKeepAliveCount + + ", tcpKeepAliveIdle=" + tcpKeepAliveIdle + + ", tcpKeepAliveInterval=" + tcpKeepAliveInterval + + ", xpubVerbose=" + xpubVerbose + + ", endpoints=" + endpoints + + '}'; + } + } + + private static class JeroMqManagerFactory implements ManagerFactory<JeroMqManager, JeroMqConfiguration> { + @Override + public JeroMqManager createManager(final String name, final JeroMqConfiguration data) { + return new JeroMqManager(name, data); + } + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/src/site/manual/index.md ---------------------------------------------------------------------- diff --git a/log4j-jeromq/src/site/manual/index.md b/log4j-jeromq/src/site/manual/index.md new file mode 100644 index 0000000..66fe24f --- /dev/null +++ b/log4j-jeromq/src/site/manual/index.md @@ -0,0 +1,33 @@ +<!-- vim: set syn=markdown : --> +<!-- + 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. +--> + +# Apache Log4j ZeroMQ using JeroMQ module + +As of Log4j 2.11.0, ZeroMQ using JeroMQ support has moved from the existing module logj-core to the new module log4j-jeromq. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires the jeromq JAR. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/src/site/site.xml ---------------------------------------------------------------------- diff --git a/log4j-jeromq/src/site/site.xml b/log4j-jeromq/src/site/site.xml new file mode 100644 index 0000000..6d4cddc --- /dev/null +++ b/log4j-jeromq/src/site/site.xml @@ -0,0 +1,52 @@ +<!-- + 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. + +--> +<project name="Log4j Core" + xmlns="http://maven.apache.org/DECORATION/1.4.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 http://maven.apache.org/xsd/decoration-1.4.0.xsd"> + <body> + <links> + <item name="Apache" href="http://www.apache.org/" /> + <item name="Logging Services" href="http://logging.apache.org/"/> + <item name="Log4j" href="../index.html"/> + </links> + + <!-- Component-specific reports --> + <menu ref="reports"/> + + <!-- Overall Project Info --> + <menu name="Log4j Project Information" img="icon-info-sign"> + <item name="Dependencies" href="../dependencies.html" /> + <item name="Dependency Convergence" href="../dependency-convergence.html" /> + <item name="Dependency Management" href="../dependency-management.html" /> + <item name="Project Team" href="../team-list.html" /> + <item name="Mailing Lists" href="../mail-lists.html" /> + <item name="Issue Tracking" href="../issue-tracking.html" /> + <item name="Project License" href="../license.html" /> + <item name="Source Repository" href="../source-repository.html" /> + <item name="Project Summary" href="../project-summary.html" /> + </menu> + + <menu name="Log4j Project Reports" img="icon-cog"> + <item name="Changes Report" href="../changes-report.html" /> + <item name="JIRA Report" href="../jira-report.html" /> + <item name="Surefire Report" href="../surefire-report.html" /> + <item name="RAT Report" href="../rat-report.html" /> + </menu> + </body> +</project> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java ---------------------------------------------------------------------- diff --git a/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java b/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java new file mode 100644 index 0000000..24b8d25 --- /dev/null +++ b/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java @@ -0,0 +1,139 @@ +/* + * 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.logging.log4j.core.appender.mom.jeromq; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.util.ExecutorServices; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(Appenders.ZeroMq.class) +public class JeroMqAppenderTest { + + private static final String ENDPOINT = "tcp://localhost:5556"; + + private static final String APPENDER_NAME = "JeroMQAppender"; + + private static final int DEFAULT_TIMEOUT_MILLIS = 60000; + + @ClassRule + public static LoggerContextRule ctx = new LoggerContextRule("JeroMqAppenderTest.xml"); + + @Test(timeout = DEFAULT_TIMEOUT_MILLIS) + public void testAppenderLifeCycle() throws Exception { + // do nothing to make sure the appender starts and stops without + // locking up resources. + Assert.assertNotNull(JeroMqManager.getContext()); + } + + @Test(timeout = DEFAULT_TIMEOUT_MILLIS) + public void testClientServer() throws Exception { + final JeroMqAppender appender = ctx.getRequiredAppender(APPENDER_NAME, JeroMqAppender.class); + final int expectedReceiveCount = 3; + final JeroMqTestClient client = new JeroMqTestClient(JeroMqManager.getContext(), ENDPOINT, expectedReceiveCount); + final ExecutorService executor = Executors.newSingleThreadExecutor(); + try { + final Future<List<String>> future = executor.submit(client); + Thread.sleep(100); + final Logger logger = ctx.getLogger(getClass().getName()); + appender.resetSendRcs(); + logger.info("Hello"); + logger.info("Again"); + ThreadContext.put("foo", "bar"); + logger.info("World"); + final List<String> list = future.get(); + Assert.assertEquals(expectedReceiveCount, appender.getSendRcTrue()); + Assert.assertEquals(0, appender.getSendRcFalse()); + Assert.assertEquals("Hello", list.get(0)); + Assert.assertEquals("Again", list.get(1)); + Assert.assertEquals("barWorld", list.get(2)); + } finally { + executor.shutdown(); + } + } + + @Test(timeout = DEFAULT_TIMEOUT_MILLIS) + public void testMultiThreadedServer() throws Exception { + final int nThreads = 10; + final JeroMqAppender appender = ctx.getRequiredAppender(APPENDER_NAME, JeroMqAppender.class); + final int expectedReceiveCount = 2 * nThreads; + final JeroMqTestClient client = new JeroMqTestClient(JeroMqManager.getContext(), ENDPOINT, + expectedReceiveCount); + final ExecutorService executor = Executors.newSingleThreadExecutor(); + try { + final Future<List<String>> future = executor.submit(client); + Thread.sleep(100); + final Logger logger = ctx.getLogger(getClass().getName()); + appender.resetSendRcs(); + final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads); + for (int i = 0; i < 10.; i++) { + fixedThreadPool.submit(new Runnable() { + @Override + public void run() { + logger.info("Hello"); + logger.info("Again"); + } + }); + } + final List<String> list = future.get(); + Assert.assertEquals(expectedReceiveCount, appender.getSendRcTrue()); + Assert.assertEquals(0, appender.getSendRcFalse()); + int hello = 0; + int again = 0; + for (final String string : list) { + switch (string) { + case "Hello": + hello++; + break; + case "Again": + again++; + break; + default: + Assert.fail("Unexpected message: " + string); + } + } + Assert.assertEquals(nThreads, hello); + Assert.assertEquals(nThreads, again); + } finally { + ExecutorServices.shutdown(executor, DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, + JeroMqAppenderTest.class.getSimpleName()); + } + } + + @Test(timeout = DEFAULT_TIMEOUT_MILLIS) + public void testServerOnly() throws Exception { + final Logger logger = ctx.getLogger(getClass().getName()); + final JeroMqAppender appender = ctx.getRequiredAppender(APPENDER_NAME, JeroMqAppender.class); + appender.resetSendRcs(); + logger.info("Hello"); + logger.info("Again"); + Assert.assertEquals(2, appender.getSendRcTrue()); + Assert.assertEquals(0, appender.getSendRcFalse()); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java ---------------------------------------------------------------------- diff --git a/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java b/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java new file mode 100644 index 0000000..b84cc72 --- /dev/null +++ b/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java @@ -0,0 +1,55 @@ +/* + * 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.logging.log4j.core.appender.mom.jeromq; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +import org.zeromq.ZMQ; + +class JeroMqTestClient implements Callable<List<String>> { + + private final ZMQ.Context context; + + private final String endpoint; + private final List<String> messages; + private final int receiveCount; + + JeroMqTestClient(final ZMQ.Context context, final String endpoint, final int receiveCount) { + super(); + this.context = context; + this.endpoint = endpoint; + this.receiveCount = receiveCount; + this.messages = new ArrayList<>(receiveCount); + } + + @Override + public List<String> call() throws Exception { + try (ZMQ.Socket subscriber = context.socket(ZMQ.SUB)) { + subscriber.connect(endpoint); + subscriber.subscribe(new byte[0]); + for (int messageNum = 0; messageNum < receiveCount + && !Thread.currentThread().isInterrupted(); messageNum++) { + // Use trim to remove the tailing '0' character + messages.add(subscriber.recvStr(0).trim()); + } + } + return messages; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml ---------------------------------------------------------------------- diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml new file mode 100644 index 0000000..ad22f65 --- /dev/null +++ b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml @@ -0,0 +1,38 @@ +<?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. +--> +<Configuration status="OFF"> + + <Appenders> + <Console name="STDOUT"> + <PatternLayout pattern="%C{1.} %m %level MDC%X%n"/> + </Console> + <Jpa name="databaseAppender" persistenceUnitName="h2JpaAppenderTestUnit" + entityClassName="org.apache.logging.log4j.core.appender.db.jpa.TestBaseEntity" ignoreExceptions="false" /> + </Appenders> + + <Loggers> + <Logger name="org.apache.logging.log4j.core.appender.db" level="debug" additivity="false"> + <AppenderRef ref="databaseAppender" /> + </Logger> + + <Root level="fatal"> + <AppenderRef ref="STDOUT"/> + </Root> + </Loggers> + +</Configuration> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml ---------------------------------------------------------------------- diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml new file mode 100644 index 0000000..af3a0b7 --- /dev/null +++ b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml @@ -0,0 +1,38 @@ +<?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. +--> +<Configuration status="OFF"> + + <Appenders> + <Console name="STDOUT"> + <PatternLayout pattern="%C{1.} %m %level MDC%X%n"/> + </Console> + <Jpa name="databaseAppender" persistenceUnitName="h2JpaAppenderTestUnit" + entityClassName="org.apache.logging.log4j.core.appender.db.jpa.TestBasicEntity" ignoreExceptions="false" /> + </Appenders> + + <Loggers> + <Logger name="org.apache.logging.log4j.core.appender.db" level="debug" additivity="false"> + <AppenderRef ref="databaseAppender" /> + </Logger> + + <Root level="fatal"> + <AppenderRef ref="STDOUT"/> + </Root> + </Loggers> + +</Configuration> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml ---------------------------------------------------------------------- diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml new file mode 100644 index 0000000..3f6e50a --- /dev/null +++ b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml @@ -0,0 +1,38 @@ +<?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. +--> +<Configuration status="OFF"> + + <Appenders> + <Console name="STDOUT"> + <PatternLayout pattern="%C{1.} %m %level MDC%X%n"/> + </Console> + <Jpa name="databaseAppender" persistenceUnitName="hyperSqlJpaAppenderTestUnit" + entityClassName="org.apache.logging.log4j.core.appender.db.jpa.TestBaseEntity" ignoreExceptions="false" /> + </Appenders> + + <Loggers> + <Logger name="org.apache.logging.log4j.core.appender.db" level="debug" additivity="false"> + <AppenderRef ref="databaseAppender" /> + </Logger> + + <Root level="fatal"> + <AppenderRef ref="STDOUT"/> + </Root> + </Loggers> + +</Configuration> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml ---------------------------------------------------------------------- diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml new file mode 100644 index 0000000..8215ea3 --- /dev/null +++ b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml @@ -0,0 +1,38 @@ +<?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. +--> +<Configuration status="OFF"> + + <Appenders> + <Console name="STDOUT"> + <PatternLayout pattern="%C{1.} %m %level MDC%X%n"/> + </Console> + <Jpa name="databaseAppender" persistenceUnitName="hyperSqlJpaAppenderTestUnit" + entityClassName="org.apache.logging.log4j.core.appender.db.jpa.TestBasicEntity" ignoreExceptions="false" /> + </Appenders> + + <Loggers> + <Logger name="org.apache.logging.log4j.core.appender.db" level="debug" additivity="false"> + <AppenderRef ref="databaseAppender" /> + </Logger> + + <Root level="fatal"> + <AppenderRef ref="STDOUT"/> + </Root> + </Loggers> + +</Configuration> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 362eb41..34bb670 100644 --- a/pom.xml +++ b/pom.xml @@ -1336,6 +1336,7 @@ <module>log4j-bom</module> <module>log4j-jdbc-dbcp2</module> <module>log4j-jpa</module> + <module>log4j-jeromq</module> <module>log4j-couchdb</module> <module>log4j-mongodb2</module> <module>log4j-mongodb3</module> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 431e665..aea4e1c 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -164,6 +164,9 @@ <action issue="LOG4J2-2229" dev="ggregory" type="update" due-to="Gary Gregory"> Update Jackson from 2.9.3 to 2.9.4. </action> + <action issue="LOG4J2-2228" dev="ggregory" type="update" due-to="Gary Gregory"> + Split off ZeroMq/JeroMq support into a new module log4j-jeromq. + </action> </release> <release version="2.10.0" date="2017-11-18" description="GA Release 2.10.0"> <action issue="LOG4J2-2120" dev="mikes" type="add" due-to="Carter Douglas Kozak"> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2f372459/src/site/xdoc/manual/appenders.xml ---------------------------------------------------------------------- diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml index a6401bb..bcd7736 100644 --- a/src/site/xdoc/manual/appenders.xml +++ b/src/site/xdoc/manual/appenders.xml @@ -5219,6 +5219,9 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { <a name="JeroMQAppender"/> <subsection name="ZeroMQ/JeroMQ Appender"> <p> + As of Log4j 2.11.0, ZeroMQ/JeroMQ support has moved from the existing module <code>logj-core</code> to the new module <code>log4j-jeromq</code>. + </p> + <p> The ZeroMQ appender uses the <a href="https://github.com/zeromq/jeromq">JeroMQ</a> library to send log events to one or more ZeroMQ endpoints. </p>
