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 &#169; 
{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>

Reply via email to