You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2016/11/14 08:24:46 UTC

logging-log4j2 git commit: [LOG4J2-1707] and [LOG4J2-1708].

Repository: logging-log4j2
Updated Branches:
  refs/heads/master 06fe5e6d1 -> 92f1c6528


[LOG4J2-1707] and [LOG4J2-1708].

[LOG4J2-1707] Allow TCP Socket Appender to set socket options.
[LOG4J2-1708]Allow Secure Socket Appender to set socket options.


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/92f1c652
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/92f1c652
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/92f1c652

Branch: refs/heads/master
Commit: 92f1c65282cb37d95c7398b562ed2a80e6cfa02a
Parents: 06fe5e6
Author: Gary Gregory <gg...@apache.org>
Authored: Mon Nov 14 00:24:42 2016 -0800
Committer: Gary Gregory <gg...@apache.org>
Committed: Mon Nov 14 00:24:42 2016 -0800

----------------------------------------------------------------------
 .../log4j/core/appender/SocketAppender.java     |  33 ++-
 .../log4j/core/appender/SyslogAppender.java     |  37 ++++
 .../log4j/core/net/Rfc1349TrafficClass.java     |  50 +++++
 .../logging/log4j/core/net/SocketOptions.java   | 222 +++++++++++++++++++
 .../core/net/SocketPerformancePreferences.java  |  82 +++++++
 .../log4j/core/net/SslSocketManager.java        |  88 ++++++--
 .../log4j/core/net/TcpSocketManager.java        | 190 ++++++++++++----
 .../SecureSocketAppenderSocketOptionsTest.java  | 119 ++++++++++
 .../SocketAppenderSocketOptionsTest.java        |  99 +++++++++
 .../log4j/core/appender/SocketAppenderTest.java |   7 +-
 .../src/test/resources/log4j-socket-options.xml |  32 +++
 .../test/resources/log4j-ssl-socket-options.xml |  39 ++++
 src/changes/changes.xml                         |   6 +
 13 files changed, 937 insertions(+), 67 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
index 95f9d6e..fd0badb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
@@ -39,11 +39,11 @@ import org.apache.logging.log4j.core.net.AbstractSocketManager;
 import org.apache.logging.log4j.core.net.Advertiser;
 import org.apache.logging.log4j.core.net.DatagramSocketManager;
 import org.apache.logging.log4j.core.net.Protocol;
+import org.apache.logging.log4j.core.net.SocketOptions;
 import org.apache.logging.log4j.core.net.SslSocketManager;
 import org.apache.logging.log4j.core.net.TcpSocketManager;
 import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
 import org.apache.logging.log4j.core.util.Booleans;
-import org.apache.logging.log4j.core.util.Constants;
 
 /**
  * An Appender that delivers events over socket connections. Supports both TCP and UDP.
@@ -88,6 +88,9 @@ public class SocketAppender extends AbstractOutputStreamAppender<AbstractSocketM
         @PluginAliases({ "reconnectDelay, delayMillis" })
         private int reconnectDelayMillis;
         
+        @PluginElement("SocketOptions")
+        private SocketOptions socketOptions;
+        
         @PluginElement("SslConfiguration")
         @PluginAliases({ "SslConfig" })
         private SslConfiguration sslConfiguration;
@@ -114,7 +117,7 @@ public class SocketAppender extends AbstractOutputStreamAppender<AbstractSocketM
             }
 
             final AbstractSocketManager manager = SocketAppender.createSocketManager(name, actualProtocol, host, port,
-                    connectTimeoutMillis, sslConfiguration, reconnectDelayMillis, immediateFail, layout, getBufferSize());
+                    connectTimeoutMillis, sslConfiguration, reconnectDelayMillis, immediateFail, layout, getBufferSize(), socketOptions);
 
             return new SocketAppender(name, layout, getFilter(), manager, isIgnoreExceptions(),
                     !bufferedIo || immediateFlush, advertise ? configuration.getAdvertiser() : null);
@@ -188,6 +191,11 @@ public class SocketAppender extends AbstractOutputStreamAppender<AbstractSocketM
             return asBuilder();
         }
 
+        public B withSocketOptions(final SocketOptions socketOptions) {
+            this.socketOptions = socketOptions;
+            return asBuilder();
+        }
+
         public B withSslConfiguration(final SslConfiguration sslConfiguration) {
             this.sslConfiguration = sslConfiguration;
             return asBuilder();
@@ -373,10 +381,25 @@ public class SocketAppender extends AbstractOutputStreamAppender<AbstractSocketM
      *
      * @throws IllegalArgumentException
      *             if the protocol cannot be handled.
+     * @deprecated Use {@link #createSocketManager(String, Protocol, String, int, int, SslConfiguration, int, boolean, Layout, int, SocketOptions)}.
      */
+    @Deprecated
     protected static AbstractSocketManager createSocketManager(final String name, Protocol protocol, final String host,
             final int port, final int connectTimeoutMillis, final SslConfiguration sslConfig, final int reconnectDelayMillis,
             final boolean immediateFail, final Layout<? extends Serializable> layout, final int bufferSize) {
+        return createSocketManager(name, protocol, host, port, connectTimeoutMillis, sslConfig, reconnectDelayMillis, immediateFail, layout, bufferSize, null);
+    }
+
+    /**
+     * Creates an AbstractSocketManager for TCP, UDP, and SSL.
+     *
+     * @throws IllegalArgumentException
+     *             if the protocol cannot be handled.
+     */
+    protected static AbstractSocketManager createSocketManager(final String name, Protocol protocol, final String host,
+            final int port, final int connectTimeoutMillis, final SslConfiguration sslConfig,
+            final int reconnectDelayMillis, final boolean immediateFail, final Layout<? extends Serializable> layout,
+            final int bufferSize, final SocketOptions socketOptions) {
         if (protocol == Protocol.TCP && sslConfig != null) {
             // Upgrade TCP to SSL if an SSL config is specified.
             protocol = Protocol.SSL;
@@ -386,13 +409,13 @@ public class SocketAppender extends AbstractOutputStreamAppender<AbstractSocketM
         }
         switch (protocol) {
         case TCP:
-            return TcpSocketManager.getSocketManager(host, port, connectTimeoutMillis, reconnectDelayMillis, immediateFail,
-                    layout, bufferSize);
+            return TcpSocketManager.getSocketManager(host, port, connectTimeoutMillis, reconnectDelayMillis,
+                    immediateFail, layout, bufferSize, socketOptions);
         case UDP:
             return DatagramSocketManager.getSocketManager(host, port, layout, bufferSize);
         case SSL:
             return SslSocketManager.getSocketManager(sslConfig, host, port, connectTimeoutMillis, reconnectDelayMillis,
-                    immediateFail, layout, bufferSize);
+                    immediateFail, layout, bufferSize, socketOptions);
         default:
             throw new IllegalArgumentException(protocol.toString());
         }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
index bfe7e3a..6df591d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
@@ -23,10 +23,12 @@ import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.appender.SocketAppender.Builder;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.config.plugins.PluginAliases;
 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
@@ -37,6 +39,7 @@ import org.apache.logging.log4j.core.net.AbstractSocketManager;
 import org.apache.logging.log4j.core.net.Advertiser;
 import org.apache.logging.log4j.core.net.Facility;
 import org.apache.logging.log4j.core.net.Protocol;
+import org.apache.logging.log4j.core.net.SocketOptions;
 import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
 import org.apache.logging.log4j.core.util.Constants;
 import org.apache.logging.log4j.util.EnglishEnums;
@@ -47,6 +50,40 @@ import org.apache.logging.log4j.util.EnglishEnums;
 @Plugin(name = "Syslog", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
 public class SyslogAppender extends SocketAppender {
 
+    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
+            implements org.apache.logging.log4j.core.util.Builder<SyslogAppender> {
+
+//        @PluginAliases("reconnectionDelay") // deprecated
+//        @PluginAttribute("name") final String name,
+//        @PluginAttribute(value = "immediateFlush", defaultBoolean = true) final boolean immediateFlush,
+//        @PluginAttribute(value = "ignoreExceptions", defaultBoolean = true) final boolean ignoreExceptions,
+//        @PluginAttribute(value = "facility", defaultString = "LOCAL0") final Facility facility,
+//        @PluginAttribute("id") final String id,
+//        @PluginAttribute(value = "enterpriseNumber", defaultInt = Rfc5424Layout.DEFAULT_ENTERPRISE_NUMBER) final int enterpriseNumber,
+//        @PluginAttribute(value = "includeMdc", defaultBoolean = true) final boolean includeMdc,
+//        @PluginAttribute("mdcId") final String mdcId,
+//        @PluginAttribute("mdcPrefix") final String mdcPrefix,
+//        @PluginAttribute("eventPrefix") final String eventPrefix,
+//        @PluginAttribute(value = "newLine") final boolean newLine,
+//        @PluginAttribute("newLineEscape") final String escapeNL,
+//        @PluginAttribute("appName") final String appName,
+//        @PluginAttribute("messageId") final String msgId,
+//        @PluginAttribute("mdcExcludes") final String excludes,
+//        @PluginAttribute("mdcIncludes") final String includes,
+//        @PluginAttribute("mdcRequired") final String required,
+//        @PluginAttribute("format") final String format,
+//        @PluginElement("Filter") final Filter filter,
+//        @PluginAttribute(value = "charset", defaultString = "UTF-8") final Charset charsetName,
+//        @PluginAttribute("exceptionPattern") final String exceptionPattern,
+//        @PluginElement("LoggerFields") final LoggerFields[] loggerFields, 
+
+        @Override
+        public SyslogAppender build() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+    }
+    
     protected static final String RFC5424 = "RFC5424";
 
     protected SyslogAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/main/java/org/apache/logging/log4j/core/net/Rfc1349TrafficClass.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/Rfc1349TrafficClass.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/Rfc1349TrafficClass.java
new file mode 100644
index 0000000..cb071e4
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/Rfc1349TrafficClass.java
@@ -0,0 +1,50 @@
+/*
+ * 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.net;
+
+/**
+ * Enumerates the RFC 1349 TOS field.
+ * 
+ * <ul>
+ * <li>1000 -- minimize delay</li>
+ * <li>0100 -- maximize throughput</li>
+ * <li>0010 -- maximize reliability</li>
+ * <li>0001 -- minimize monetary cost</li>
+ * <li>0000 -- normal service</li>
+ * <ul>
+ */
+public enum Rfc1349TrafficClass {
+
+    // @formatter:off
+    IPTOS_NORMAL(0x00),
+    IPTOS_LOWCOST(0x02),
+    IPTOS_LOWDELAY (0x10),
+    IPTOS_RELIABILITY (0x04),
+    IPTOS_THROUGHPUT (0x08);
+    // @formatter:on
+
+    private final int trafficClass;
+
+    private Rfc1349TrafficClass(final int trafficClass) {
+        this.trafficClass = trafficClass;
+    }
+
+    public int value() {
+        return trafficClass;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketOptions.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketOptions.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketOptions.java
new file mode 100644
index 0000000..62364e5
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketOptions.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.net;
+
+import java.net.Socket;
+import java.net.SocketException;
+
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.util.Builder;
+
+/**
+ * Holds all socket options settable via {@link Socket} methods.
+ */
+@Plugin(name = "SocketOptions", category = Core.CATEGORY_NAME, printObject = true)
+public class SocketOptions implements Builder<SocketOptions>, Cloneable {
+
+    @PluginBuilderFactory
+    public static SocketOptions newBuilder() {
+        return new SocketOptions();
+    }
+
+    @PluginBuilderAttribute
+    private Boolean keepAlive;
+
+    @PluginBuilderAttribute
+    private Boolean oobInline;
+
+    @PluginElement("PerformancePreferences")
+    private SocketPerformancePreferences performancePreferences;
+
+    @PluginBuilderAttribute
+    private Integer receiveBufferSize;
+
+    @PluginBuilderAttribute
+    private Boolean reuseAddress;
+
+    @PluginBuilderAttribute
+    private Rfc1349TrafficClass rfc1349TrafficClass;
+
+    @PluginBuilderAttribute
+    private Integer sendBufferSize;
+
+    @PluginBuilderAttribute
+    private Integer soLinger;
+
+    @PluginBuilderAttribute
+    private Integer soTimeout;
+
+    @PluginBuilderAttribute
+    private Boolean tcpNoDelay;
+
+    @PluginBuilderAttribute
+    private Integer trafficClass;
+
+    public void apply(final Socket socket) throws SocketException {
+        if (keepAlive != null) {
+            socket.setKeepAlive(keepAlive.booleanValue());
+        }
+        if (oobInline != null) {
+            socket.setOOBInline(oobInline.booleanValue());
+        }
+        if (reuseAddress != null) {
+            socket.setReuseAddress(reuseAddress.booleanValue());
+        }
+        if (performancePreferences != null) {
+            performancePreferences.apply(socket);
+        }
+        if (receiveBufferSize != null) {
+            socket.setReceiveBufferSize(receiveBufferSize.intValue());
+        }
+        if (soLinger != null) {
+            socket.setSoLinger(true, soLinger.intValue());
+        }
+        if (soTimeout != null) {
+            socket.setSoTimeout(soTimeout.intValue());
+        }
+        if (tcpNoDelay != null) {
+            socket.setTcpNoDelay(tcpNoDelay.booleanValue());
+        }
+        final Integer actualTrafficClass = getActualTrafficClass();
+        if (actualTrafficClass != null) {
+            socket.setTrafficClass(actualTrafficClass);
+        }
+    }
+
+    @Override
+    public SocketOptions build() {
+        try {
+            return (SocketOptions) clone();
+        } catch (final CloneNotSupportedException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    public Integer getActualTrafficClass() {
+        if (trafficClass != null && rfc1349TrafficClass != null) {
+            throw new IllegalStateException("You MUST not set both customTrafficClass and trafficClass.");
+        }
+        if (trafficClass != null) {
+            return trafficClass;
+        }
+        if (rfc1349TrafficClass != null) {
+            return Integer.valueOf(rfc1349TrafficClass.value());
+        }
+        return null;
+    }
+
+    public SocketPerformancePreferences getPerformancePreferences() {
+        return performancePreferences;
+    }
+
+    public Integer getReceiveBufferSize() {
+        return receiveBufferSize;
+    }
+
+    public Rfc1349TrafficClass getRfc1349TrafficClass() {
+        return rfc1349TrafficClass;
+    }
+
+    public Integer getSendBufferSize() {
+        return sendBufferSize;
+    }
+
+    public Integer getSoLinger() {
+        return soLinger;
+    }
+
+    public Integer getSoTimeout() {
+        return soTimeout;
+    }
+
+    public Integer getTrafficClass() {
+        return trafficClass;
+    }
+
+    public Boolean isKeepAlive() {
+        return keepAlive;
+    }
+
+    public Boolean isOobInline() {
+        return oobInline;
+    }
+
+    public Boolean isReuseAddress() {
+        return reuseAddress;
+    }
+
+    public Boolean isTcpNoDelay() {
+        return tcpNoDelay;
+    }
+
+    public void setKeepAlive(final boolean keepAlive) {
+        this.keepAlive = Boolean.valueOf(keepAlive);
+    }
+
+    public void setOobInline(final boolean oobInline) {
+        this.oobInline = Boolean.valueOf(oobInline);
+    }
+
+    public void setPerformancePreferences(final SocketPerformancePreferences performancePreferences) {
+        this.performancePreferences = performancePreferences;
+    }
+
+    public void setReceiveBufferSize(final int receiveBufferSize) {
+        this.receiveBufferSize = receiveBufferSize;
+    }
+
+    public void setReuseAddress(final boolean reuseAddress) {
+        this.reuseAddress = Boolean.valueOf(reuseAddress);
+    }
+
+    public void setRfc1349TrafficClass(final Rfc1349TrafficClass trafficClass) {
+        this.rfc1349TrafficClass = trafficClass;
+    }
+
+    public void setSendBufferSize(final int sendBufferSize) {
+        this.sendBufferSize = sendBufferSize;
+    }
+
+    public void setSoLinger(final int soLinger) {
+        this.soLinger = soLinger;
+    }
+
+    public void setSoTimeout(final int soTimeout) {
+        this.soTimeout = soTimeout;
+    }
+
+    public void setTcpNoDelay(final boolean tcpNoDelay) {
+        this.tcpNoDelay = Boolean.valueOf(tcpNoDelay);
+    }
+
+    public void setTrafficClass(final int trafficClass) {
+        this.trafficClass = trafficClass;
+    }
+
+    @Override
+    public String toString() {
+        return "SocketOptions [keepAlive=" + keepAlive + ", oobInline=" + oobInline + ", performancePreferences="
+                + performancePreferences + ", receiveBufferSize=" + receiveBufferSize + ", reuseAddress=" + reuseAddress
+                + ", rfc1349TrafficClass=" + rfc1349TrafficClass + ", sendBufferSize=" + sendBufferSize + ", soLinger="
+                + soLinger + ", soTimeout=" + soTimeout + ", tcpNoDelay=" + tcpNoDelay + ", trafficClass="
+                + trafficClass + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketPerformancePreferences.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketPerformancePreferences.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketPerformancePreferences.java
new file mode 100644
index 0000000..c7a246a
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketPerformancePreferences.java
@@ -0,0 +1,82 @@
+package org.apache.logging.log4j.core.net;
+
+import java.net.Socket;
+import java.net.SocketException;
+
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
+import org.apache.logging.log4j.core.util.Builder;
+
+/**
+ * Holds all socket options settable via {@link Socket#setPerformancePreferences(int, int, int)}.
+ * <p>
+ * The {@link Socket#setPerformancePreferences(int, int, int)} API may not be implemented by a JRE.
+ * </p>
+ */
+@Plugin(name = "SocketPerformancePreferences", category = Core.CATEGORY_NAME, printObject = true)
+public class SocketPerformancePreferences implements Builder<SocketPerformancePreferences>, Cloneable {
+
+    @PluginBuilderFactory
+    public static SocketPerformancePreferences newBuilder() {
+        return new SocketPerformancePreferences();
+    }
+
+    @PluginBuilderAttribute
+    @Required
+    private int bandwidth;
+
+    @PluginBuilderAttribute
+    @Required
+    private int connectionTime;
+
+    @PluginBuilderAttribute
+    @Required
+    private int latency;
+
+    public void apply(final Socket socket) {
+        socket.setPerformancePreferences(connectionTime, latency, bandwidth);
+    }
+
+    @Override
+    public SocketPerformancePreferences build() {
+        try {
+            return (SocketPerformancePreferences) clone();
+        } catch (final CloneNotSupportedException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    public int getBandwidth() {
+        return bandwidth;
+    }
+
+    public int getConnectionTime() {
+        return connectionTime;
+    }
+
+    public int getLatency() {
+        return latency;
+    }
+
+    public void setBandwidth(final int bandwidth) {
+        this.bandwidth = bandwidth;
+    }
+
+    public void setConnectionTime(final int connectionTime) {
+        this.connectionTime = connectionTime;
+    }
+
+    public void setLatency(final int latency) {
+        this.latency = latency;
+    }
+
+    @Override
+    public String toString() {
+        return "SocketPerformancePreferences [bandwidth=" + bandwidth + ", connectionTime=" + connectionTime
+                + ", latency=" + latency + "]";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
index ec5c64a..c9d5c6e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
@@ -43,27 +43,51 @@ public class SslSocketManager extends TcpSocketManager {
     private final SslConfiguration sslConfig;
 
     /**
-     *
-     *
-     * @param name          The unique name of this connection.
-     * @param os            The OutputStream.
-     * @param sock          The Socket.
-     * @param inetAddress          The Internet address of the host.
-     * @param host          The name of the host.
-     * @param port          The port number on the host.
-     * @param connectTimeoutMillis the connect timeout in milliseconds.
-     * @param delay         Reconnection interval.
-     * @param immediateFail
-     * @param layout        The Layout.
-     * @param bufferSize The buffer size.
-     */
-    public SslSocketManager(final String name, final OutputStream os, final Socket sock,
-            final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
-            final int connectTimeoutMillis, final int delay, final boolean immediateFail,
-            final Layout<? extends Serializable> layout, final int bufferSize) {
-        super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, delay, immediateFail, layout, bufferSize);
-        this.sslConfig = sslConfig;
-    }
+    *
+    *
+    * @param name          The unique name of this connection.
+    * @param os            The OutputStream.
+    * @param sock          The Socket.
+    * @param inetAddress          The Internet address of the host.
+    * @param host          The name of the host.
+    * @param port          The port number on the host.
+    * @param connectTimeoutMillis the connect timeout in milliseconds.
+    * @param delay         Reconnection interval.
+    * @param immediateFail
+    * @param layout        The Layout.
+    * @param bufferSize The buffer size.
+    * @deprecated Use {@link #SslSocketManager(String, OutputStream, Socket, SslConfiguration, InetAddress, String, int, int, int, boolean, Layout, int, SocketOptions)}.
+    */
+   public SslSocketManager(final String name, final OutputStream os, final Socket sock,
+           final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
+           final int connectTimeoutMillis, final int delay, final boolean immediateFail,
+           final Layout<? extends Serializable> layout, final int bufferSize) {
+       super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, delay, immediateFail, layout, bufferSize, null);
+       this.sslConfig = sslConfig;
+   }
+
+   /**
+   *
+   *
+   * @param name          The unique name of this connection.
+   * @param os            The OutputStream.
+   * @param sock          The Socket.
+   * @param inetAddress          The Internet address of the host.
+   * @param host          The name of the host.
+   * @param port          The port number on the host.
+   * @param connectTimeoutMillis the connect timeout in milliseconds.
+   * @param delay         Reconnection interval.
+   * @param immediateFail
+   * @param layout        The Layout.
+   * @param bufferSize The buffer size.
+   */
+  public SslSocketManager(final String name, final OutputStream os, final Socket sock,
+          final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
+          final int connectTimeoutMillis, final int delay, final boolean immediateFail,
+          final Layout<? extends Serializable> layout, final int bufferSize, final SocketOptions socketOptions) {
+      super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, delay, immediateFail, layout, bufferSize, socketOptions);
+      this.sslConfig = sslConfig;
+  }
 
     private static class SslFactoryData {
         protected SslConfiguration sslConfiguration;
@@ -74,10 +98,11 @@ public class SslSocketManager extends TcpSocketManager {
         private final boolean immediateFail;
         private final Layout<? extends Serializable> layout;
         private final int bufferSize;
+        private final SocketOptions socketOptions;
 
         public SslFactoryData(final SslConfiguration sslConfiguration, final String host, final int port,
                 final int connectTimeoutMillis, final int delayMillis, final boolean immediateFail,
-                final Layout<? extends Serializable> layout, final int bufferSize) {
+                final Layout<? extends Serializable> layout, final int bufferSize, final SocketOptions socketOptions) {
             this.host = host;
             this.port = port;
             this.connectTimeoutMillis = connectTimeoutMillis;
@@ -86,12 +111,23 @@ public class SslSocketManager extends TcpSocketManager {
             this.layout = layout;
             this.sslConfiguration = sslConfiguration;
             this.bufferSize = bufferSize;
+            this.socketOptions = socketOptions;
         }
     }
 
+    /**
+     * @deprecated Use {@link SslSocketManager#getSocketManager(SslConfiguration, String, int, int, int, boolean, Layout, int, SocketOptions)}.
+     */
+    @Deprecated
     public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, int port,
             final int connectTimeoutMillis, int reconnectDelayMillis, final boolean immediateFail,
             final Layout<? extends Serializable> layout, final int bufferSize) {
+        return getSocketManager(sslConfig, host, port, connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout, bufferSize, null);
+    }
+
+    public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, int port,
+            final int connectTimeoutMillis, int reconnectDelayMillis, final boolean immediateFail,
+            final Layout<? extends Serializable> layout, final int bufferSize, final SocketOptions socketOptions) {
         if (Strings.isEmpty(host)) {
             throw new IllegalArgumentException("A host name is required");
         }
@@ -102,7 +138,7 @@ public class SslSocketManager extends TcpSocketManager {
             reconnectDelayMillis = DEFAULT_RECONNECTION_DELAY_MILLIS;
         }
         return (SslSocketManager) getManager("TLS:" + host + ':' + port, new SslFactoryData(sslConfig, host, port,
-                connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout, bufferSize), FACTORY);
+                connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout, bufferSize, socketOptions), FACTORY);
     }
 
     @Override
@@ -155,7 +191,7 @@ public class SslSocketManager extends TcpSocketManager {
                 return null;
             }
             return new SslSocketManager(name, os, socket, data.sslConfiguration, inetAddress, data.host, data.port, 0,
-                    data.delayMillis, data.immediateFail, data.layout, data.bufferSize);
+                    data.delayMillis, data.immediateFail, data.layout, data.bufferSize, data.socketOptions);
         }
 
         private InetAddress resolveAddress(final String hostName) throws TlsSocketManagerFactoryException {
@@ -183,6 +219,10 @@ public class SslSocketManager extends TcpSocketManager {
 
             socketFactory = createSslSocketFactory(data.sslConfiguration);
             socket = (SSLSocket) socketFactory.createSocket(data.host, data.port);
+            final SocketOptions socketOptions = data.socketOptions;
+            if (socketOptions != null) {
+                socketOptions.apply(socket);
+            }
             return socket;
         }
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java
index 1e43cee..d7d210e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java
@@ -23,6 +23,7 @@ import java.net.ConnectException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.util.HashMap;
 import java.util.Map;
@@ -32,6 +33,7 @@ import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
 import org.apache.logging.log4j.core.appender.ManagerFactory;
 import org.apache.logging.log4j.core.appender.OutputStreamManager;
+import org.apache.logging.log4j.core.net.TcpSocketManager.TcpSocketManagerFactory;
 import org.apache.logging.log4j.core.util.Log4jThread;
 import org.apache.logging.log4j.core.util.NullOutputStream;
 import org.apache.logging.log4j.util.Strings;
@@ -41,11 +43,11 @@ import org.apache.logging.log4j.util.Strings;
  */
 public class TcpSocketManager extends AbstractSocketManager {
     /**
-      The default reconnection delay (30000 milliseconds or 30 seconds).
+     * The default reconnection delay (30000 milliseconds or 30 seconds).
      */
-    public static final int DEFAULT_RECONNECTION_DELAY_MILLIS   = 30000;
+    public static final int DEFAULT_RECONNECTION_DELAY_MILLIS = 30000;
     /**
-      The default port number of remote logging server (4560).
+     * The default port number of remote logging server (4560).
      */
     private static final int DEFAULT_PORT = 4560;
 
@@ -57,29 +59,81 @@ public class TcpSocketManager extends AbstractSocketManager {
 
     private Socket socket;
 
+    private final SocketOptions socketOptions;
+
     private final boolean retry;
 
     private final boolean immediateFail;
-    
+
     private final int connectTimeoutMillis;
 
     /**
-     * The Constructor.
-     * @param name The unique name of this connection.
-     * @param os The OutputStream.
-     * @param socket The Socket.
-     * @param inetAddress The Internet address of the host.
-     * @param host The name of the host.
-     * @param port The port number on the host.
-     * @param connectTimeoutMillis the connect timeout in milliseconds.
-     * @param delay Reconnection interval.
-     * @param immediateFail True if the write should fail if no socket is immediately available.
-     * @param layout The Layout.
-     * @param bufferSize The buffer size.
+     * Constructs.
+     * 
+     * @param name
+     *            The unique name of this connection.
+     * @param os
+     *            The OutputStream.
+     * @param socket
+     *            The Socket.
+     * @param inetAddress
+     *            The Internet address of the host.
+     * @param host
+     *            The name of the host.
+     * @param port
+     *            The port number on the host.
+     * @param connectTimeoutMillis
+     *            the connect timeout in milliseconds.
+     * @param delay
+     *            Reconnection interval.
+     * @param immediateFail
+     *            True if the write should fail if no socket is immediately available.
+     * @param layout
+     *            The Layout.
+     * @param bufferSize
+     *            The buffer size.
+     * @deprecated Use
+     *             {@link TcpSocketManager#TcpSocketManager(String, OutputStream, Socket, InetAddress, String, int, int, int, boolean, Layout, int, SocketOptions)}.
+     */
+    @Deprecated
+    public TcpSocketManager(final String name, final OutputStream os, final Socket socket,
+            final InetAddress inetAddress, final String host, final int port, final int connectTimeoutMillis,
+            final int delay, final boolean immediateFail, final Layout<? extends Serializable> layout,
+            final int bufferSize) {
+        this(name, os, socket, inetAddress, host, port, connectTimeoutMillis, delay, immediateFail, layout, bufferSize,
+                null);
+    }
+
+    /**
+     * Constructs.
+     * 
+     * @param name
+     *            The unique name of this connection.
+     * @param os
+     *            The OutputStream.
+     * @param socket
+     *            The Socket.
+     * @param inetAddress
+     *            The Internet address of the host.
+     * @param host
+     *            The name of the host.
+     * @param port
+     *            The port number on the host.
+     * @param connectTimeoutMillis
+     *            the connect timeout in milliseconds.
+     * @param delay
+     *            Reconnection interval.
+     * @param immediateFail
+     *            True if the write should fail if no socket is immediately available.
+     * @param layout
+     *            The Layout.
+     * @param bufferSize
+     *            The buffer size.
      */
-    public TcpSocketManager(final String name, final OutputStream os, final Socket socket, final InetAddress inetAddress,
-                            final String host, final int port, final int connectTimeoutMillis, final int delay,
-                            final boolean immediateFail, final Layout<? extends Serializable> layout, final int bufferSize) {
+    public TcpSocketManager(final String name, final OutputStream os, final Socket socket,
+            final InetAddress inetAddress, final String host, final int port, final int connectTimeoutMillis,
+            final int delay, final boolean immediateFail, final Layout<? extends Serializable> layout,
+            final int bufferSize, final SocketOptions socketOptions) {
         super(name, os, inetAddress, host, port, layout, true, bufferSize);
         this.connectTimeoutMillis = connectTimeoutMillis;
         this.reconnectionDelay = delay;
@@ -90,19 +144,51 @@ public class TcpSocketManager extends AbstractSocketManager {
             reconnector = createReconnector();
             reconnector.start();
         }
+        this.socketOptions = socketOptions;
+    }
+
+    /**
+     * Obtains a TcpSocketManager.
+     * 
+     * @param host
+     *            The host to connect to.
+     * @param port
+     *            The port on the host.
+     * @param connectTimeoutMillis
+     *            the connect timeout in milliseconds
+     * @param reconnectDelayMillis
+     *            The interval to pause between retries.
+     * @param bufferSize
+     *            The buffer size.
+     * @return A TcpSocketManager.
+     * @deprecated Use {@link #getSocketManager(String, int, int, int, boolean, Layout, int, SocketOptions)}.
+     */
+    @Deprecated
+    public static TcpSocketManager getSocketManager(final String host, int port, final int connectTimeoutMillis,
+            int reconnectDelayMillis, final boolean immediateFail, final Layout<? extends Serializable> layout,
+            final int bufferSize) {
+        return getSocketManager(host, port, connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout,
+                bufferSize, null);
     }
 
     /**
      * Obtains a TcpSocketManager.
-     * @param host The host to connect to.
-     * @param port The port on the host.
-     * @param connectTimeoutMillis the connect timeout in milliseconds
-     * @param reconnectDelayMillis The interval to pause between retries.
-     * @param bufferSize The buffer size.
+     * 
+     * @param host
+     *            The host to connect to.
+     * @param port
+     *            The port on the host.
+     * @param connectTimeoutMillis
+     *            the connect timeout in milliseconds
+     * @param reconnectDelayMillis
+     *            The interval to pause between retries.
+     * @param bufferSize
+     *            The buffer size.
      * @return A TcpSocketManager.
      */
     public static TcpSocketManager getSocketManager(final String host, int port, final int connectTimeoutMillis,
-            int reconnectDelayMillis, final boolean immediateFail, final Layout<? extends Serializable> layout, final int bufferSize) {
+            int reconnectDelayMillis, final boolean immediateFail, final Layout<? extends Serializable> layout,
+            final int bufferSize, final SocketOptions socketOptions) {
         if (Strings.isEmpty(host)) {
             throw new IllegalArgumentException("A host name is required");
         }
@@ -112,12 +198,12 @@ public class TcpSocketManager extends AbstractSocketManager {
         if (reconnectDelayMillis == 0) {
             reconnectDelayMillis = DEFAULT_RECONNECTION_DELAY_MILLIS;
         }
-        return (TcpSocketManager) getManager("TCP:" + host + ':' + port, new FactoryData(
-                host, port, connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout, bufferSize), FACTORY);
+        return (TcpSocketManager) getManager("TCP:" + host + ':' + port, new FactoryData(host, port,
+                connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout, bufferSize, socketOptions), FACTORY);
     }
 
     @Override
-    protected void write(final byte[] bytes, final int offset, final int length, final boolean immediateFlush)  {
+    protected void write(final byte[] bytes, final int offset, final int length, final boolean immediateFlush) {
         if (socket == null) {
             if (reconnector != null && !immediateFail) {
                 reconnector.latch();
@@ -203,7 +289,7 @@ public class TcpSocketManager extends AbstractSocketManager {
             this.owner = owner;
         }
 
-        public void latch()  {
+        public void latch() {
             try {
                 latch.await();
             } catch (final InterruptedException ex) {
@@ -260,9 +346,11 @@ public class TcpSocketManager extends AbstractSocketManager {
     }
 
     protected Socket createSocket(final String host, final int port) throws IOException {
-        final InetSocketAddress address = new InetSocketAddress(host, port);
         final Socket newSocket = new Socket();
-        newSocket.connect(address, connectTimeoutMillis);
+        newSocket.connect(new InetSocketAddress(host, port), connectTimeoutMillis);
+        if (socketOptions != null) {
+            socketOptions.apply(newSocket);
+        }
         return newSocket;
     }
 
@@ -277,9 +365,11 @@ public class TcpSocketManager extends AbstractSocketManager {
         private final boolean immediateFail;
         private final Layout<? extends Serializable> layout;
         private final int bufferSize;
+        private final SocketOptions socketOptions;
 
-        public FactoryData(final String host, final int port, final int connectTimeoutMillis, final int reconnectDelayMillis,
-                           final boolean immediateFail, final Layout<? extends Serializable> layout, final int bufferSize) {
+        public FactoryData(final String host, final int port, final int connectTimeoutMillis,
+                final int reconnectDelayMillis, final boolean immediateFail,
+                final Layout<? extends Serializable> layout, final int bufferSize, final SocketOptions socketOptions) {
             this.host = host;
             this.port = port;
             this.connectTimeoutMillis = connectTimeoutMillis;
@@ -287,6 +377,7 @@ public class TcpSocketManager extends AbstractSocketManager {
             this.immediateFail = immediateFail;
             this.layout = layout;
             this.bufferSize = bufferSize;
+            this.socketOptions = socketOptions;
         }
     }
 
@@ -307,11 +398,11 @@ public class TcpSocketManager extends AbstractSocketManager {
             }
             try {
                 // LOG4J2-1042
-                final Socket socket = new Socket();
-                socket.connect(new InetSocketAddress(data.host, data.port), data.connectTimeoutMillis);
+                final Socket socket = createSocket(data);
                 os = socket.getOutputStream();
                 return new TcpSocketManager(name, os, socket, inetAddress, data.host, data.port,
-                        data.connectTimeoutMillis, data.reconnectDelayMillis, data.immediateFail, data.layout, data.bufferSize);
+                        data.connectTimeoutMillis, data.reconnectDelayMillis, data.immediateFail, data.layout,
+                        data.bufferSize, data.socketOptions);
             } catch (final IOException ex) {
                 LOGGER.error("TcpSocketManager (" + name + ") " + ex, ex);
                 os = NullOutputStream.getInstance();
@@ -320,8 +411,33 @@ public class TcpSocketManager extends AbstractSocketManager {
                 return null;
             }
             return new TcpSocketManager(name, os, null, inetAddress, data.host, data.port, data.connectTimeoutMillis,
-                    data.reconnectDelayMillis, data.immediateFail, data.layout, data.bufferSize);
+                    data.reconnectDelayMillis, data.immediateFail, data.layout, data.bufferSize, data.socketOptions);
+        }
+
+        static Socket createSocket(final FactoryData data) throws IOException, SocketException {
+            final Socket socket = new Socket();
+            socket.connect(new InetSocketAddress(data.host, data.port), data.connectTimeoutMillis);
+            final SocketOptions socketOptions = data.socketOptions;
+            if (socketOptions != null) {
+                socketOptions.apply(socket);
+            }
+            return socket;
         }
+
+    }
+
+    /**
+     * USE AT YOUR OWN RISK, method is public for testing purpose only for now.
+     */
+    public SocketOptions getSocketOptions() {
+        return socketOptions;
+    }
+
+    /**
+     * USE AT YOUR OWN RISK, method is public for testing purpose only for now.
+     */
+    public Socket getSocket() {
+        return socket;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
new file mode 100644
index 0000000..cc1327f
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+
+import javax.net.ssl.SSLServerSocketFactory;
+
+import org.apache.logging.log4j.core.appender.SocketAppenderTest.TcpSocketTestServer;
+import org.apache.logging.log4j.core.net.Rfc1349TrafficClass;
+import org.apache.logging.log4j.core.net.SocketOptions;
+import org.apache.logging.log4j.core.net.TcpSocketManager;
+import org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration;
+import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
+import org.apache.logging.log4j.core.net.ssl.StoreConfigurationException;
+import org.apache.logging.log4j.core.net.ssl.TestConstants;
+import org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration;
+import org.apache.logging.log4j.core.util.NullOutputStream;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.AvailablePortFinder;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+public class SecureSocketAppenderSocketOptionsTest {
+
+    private static final int PORT;
+    private static TcpSocketTestServer tcpSocketTestServer;
+
+    private static SSLServerSocketFactory serverSocketFactory;
+    private static SslConfiguration sslConfiguration;
+
+    static {
+        PORT = AvailablePortFinder.getNextAvailable();
+        System.setProperty("SecureSocketAppenderSocketOptionsTest.port", Integer.toString(PORT));
+        try {
+            initServerSocketFactory();            
+            tcpSocketTestServer = new TcpSocketTestServer(serverSocketFactory.createServerSocket(PORT));
+            tcpSocketTestServer.start();
+            loggerContextRule = new LoggerContextRule("log4j-ssl-socket-options.xml");
+        } catch (IOException | StoreConfigurationException e) {
+            throw new IllegalStateException(e);
+        }
+
+    }
+
+    @ClassRule
+    public static final LoggerContextRule loggerContextRule;
+
+    @AfterClass
+    public static void afterClass() {
+        if (tcpSocketTestServer != null) {
+            tcpSocketTestServer.shutdown();
+        }
+    }
+
+    public static void initServerSocketFactory() throws StoreConfigurationException {
+        final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE,
+                TestConstants.KEYSTORE_PWD, null, null);
+        final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE,
+                TestConstants.TRUSTSTORE_PWD, null, null);
+        sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, tsc);
+        serverSocketFactory = sslConfiguration.getSslServerSocketFactory();
+    }
+
+    @Test
+    public void testSocketOptions() throws IOException {
+        Assert.assertNotNull(loggerContextRule);
+        Assert.assertNotNull(loggerContextRule.getConfiguration());
+        final SocketAppender appender = loggerContextRule.getAppender("socket", SocketAppender.class);
+        Assert.assertNotNull(appender);
+        final TcpSocketManager manager = (TcpSocketManager) appender.getManager();
+        Assert.assertNotNull(manager);
+        final OutputStream outputStream = manager.getOutputStream();
+        Assert.assertFalse(outputStream instanceof NullOutputStream);
+        final SocketOptions socketOptions = manager.getSocketOptions();
+        Assert.assertNotNull(socketOptions);
+        final Socket socket = manager.getSocket();
+        Assert.assertNotNull(socket);
+        // Test config request
+        Assert.assertEquals(false, socketOptions.isKeepAlive());
+        Assert.assertEquals(null, socketOptions.isOobInline());
+        Assert.assertEquals(false, socketOptions.isReuseAddress());
+        Assert.assertEquals(false, socketOptions.isTcpNoDelay());
+        Assert.assertEquals(Rfc1349TrafficClass.IPTOS_LOWCOST.value(),
+                socketOptions.getActualTrafficClass().intValue());
+        Assert.assertEquals(10000, socketOptions.getReceiveBufferSize().intValue());
+        Assert.assertEquals(8000, socketOptions.getSendBufferSize().intValue());
+        Assert.assertEquals(12345, socketOptions.getSoLinger().intValue());
+        Assert.assertEquals(54321, socketOptions.getSoTimeout().intValue());
+        // Test live socket
+        Assert.assertEquals(false, socket.getKeepAlive());
+        Assert.assertEquals(false, socket.getReuseAddress());
+        Assert.assertEquals(false, socket.getTcpNoDelay());
+        Assert.assertEquals(Rfc1349TrafficClass.IPTOS_LOWCOST.value(), socket.getTrafficClass());
+        Assert.assertEquals(10000, socket.getReceiveBufferSize());
+        // This settings changes while we are running, so we cannot assert it.
+        // Assert.assertEquals(8000, socket.getSendBufferSize());
+        Assert.assertEquals(12345, socket.getSoLinger());
+        Assert.assertEquals(54321, socket.getSoTimeout());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
new file mode 100644
index 0000000..ea3ada1
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+
+import org.apache.logging.log4j.core.appender.SocketAppenderTest.TcpSocketTestServer;
+import org.apache.logging.log4j.core.net.Rfc1349TrafficClass;
+import org.apache.logging.log4j.core.net.SocketOptions;
+import org.apache.logging.log4j.core.net.TcpSocketManager;
+import org.apache.logging.log4j.core.util.NullOutputStream;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.AvailablePortFinder;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+public class SocketAppenderSocketOptionsTest {
+
+    private static final int PORT;
+    private static TcpSocketTestServer tcpSocketTestServer;
+
+    static {
+        PORT = AvailablePortFinder.getNextAvailable();
+        System.setProperty("SocketAppenderSocketOptionsTest.port", Integer.toString(PORT));
+        try {
+            tcpSocketTestServer = new TcpSocketTestServer(PORT);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+        tcpSocketTestServer.start();
+        loggerContextRule = new LoggerContextRule("log4j-socket-options.xml");
+    }
+
+    @ClassRule
+    public static final LoggerContextRule loggerContextRule;
+
+    @AfterClass
+    public static void afterClass() {
+        if (tcpSocketTestServer != null) {
+            tcpSocketTestServer.shutdown();
+        }
+    }
+
+    @Test
+    public void testSocketOptions() throws IOException {
+        Assert.assertNotNull(loggerContextRule);
+        Assert.assertNotNull(loggerContextRule.getConfiguration());
+        final SocketAppender appender = loggerContextRule.getAppender("socket", SocketAppender.class);
+        Assert.assertNotNull(appender);
+        final TcpSocketManager manager = (TcpSocketManager) appender.getManager();
+        Assert.assertNotNull(manager);
+        final OutputStream outputStream = manager.getOutputStream();
+        Assert.assertFalse(outputStream instanceof NullOutputStream);
+        final SocketOptions socketOptions = manager.getSocketOptions();
+        Assert.assertNotNull(socketOptions);
+        final Socket socket = manager.getSocket();
+        Assert.assertNotNull(socket);
+        // Test config request
+        Assert.assertEquals(false, socketOptions.isKeepAlive());
+        Assert.assertEquals(false, socketOptions.isOobInline());
+        Assert.assertEquals(false, socketOptions.isReuseAddress());
+        Assert.assertEquals(false, socketOptions.isTcpNoDelay());
+        Assert.assertEquals(Rfc1349TrafficClass.IPTOS_LOWCOST.value(),
+                socketOptions.getActualTrafficClass().intValue());
+        Assert.assertEquals(10000, socketOptions.getReceiveBufferSize().intValue());
+        Assert.assertEquals(8000, socketOptions.getSendBufferSize().intValue());
+        Assert.assertEquals(12345, socketOptions.getSoLinger().intValue());
+        Assert.assertEquals(54321, socketOptions.getSoTimeout().intValue());
+        // Test live socket
+        Assert.assertEquals(false, socket.getKeepAlive());
+        Assert.assertEquals(false, socket.getOOBInline());
+        Assert.assertEquals(false, socket.getReuseAddress());
+        Assert.assertEquals(false, socket.getTcpNoDelay());
+        Assert.assertEquals(Rfc1349TrafficClass.IPTOS_LOWCOST.value(), socket.getTrafficClass());
+        Assert.assertEquals(10000, socket.getReceiveBufferSize());
+        // This settings changes while we are running, so we cannot assert it.
+        // Assert.assertEquals(8000, socket.getSendBufferSize());
+        Assert.assertEquals(12345, socket.getSoLinger());
+        Assert.assertEquals(54321, socket.getSoTimeout());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
index 8d7e4b1..e8d1053 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
@@ -332,8 +332,13 @@ public class SocketAppenderTest {
         private volatile int count = 0;
         private final BlockingQueue<LogEvent> queue;
 
+        @SuppressWarnings("resource")
         public TcpSocketTestServer(final int port) throws IOException {
-            this.serverSocket = new ServerSocket(port);
+            this(new ServerSocket(port));
+        }
+
+        public TcpSocketTestServer(ServerSocket serverSocket) {
+            this.serverSocket = serverSocket;
             this.queue = new ArrayBlockingQueue<>(10);
         }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/test/resources/log4j-socket-options.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-socket-options.xml b/log4j-core/src/test/resources/log4j-socket-options.xml
new file mode 100644
index 0000000..3af324f
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-socket-options.xml
@@ -0,0 +1,32 @@
+<?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" name="MyApp">
+  <Appenders>
+    <Socket name="socket" host="localhost" port="${sys:SocketAppenderSocketOptionsTest.port}" protocol="TCP" ignoreExceptions="false">
+      <SocketOptions keepAlive="false" oobInline="false" receiveBufferSize="10000" reuseAddress="false"
+        rfc1349TrafficClass="IPTOS_LOWCOST" sendBufferSize="8000" soLinger="12345" soTimeout="54321" tcpNoDelay="false">
+        <SocketPerformancePreferences bandwidth="100" connectionTime="100" latency="100" />
+      </SocketOptions>
+    </Socket>
+  </Appenders>
+  <Loggers>
+    <Root level="debug">
+      <AppenderRef ref="socket" />
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/log4j-core/src/test/resources/log4j-ssl-socket-options.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-ssl-socket-options.xml b/log4j-core/src/test/resources/log4j-ssl-socket-options.xml
new file mode 100644
index 0000000..5b7d08d
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-ssl-socket-options.xml
@@ -0,0 +1,39 @@
+<?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" name="MyApp">
+  <Appenders>
+    <Socket name="socket" host="localhost" port="${sys:SecureSocketAppenderSocketOptionsTest.port}" protocol="SSL"
+      ignoreExceptions="false">
+      <SocketOptions keepAlive="false" receiveBufferSize="10000" reuseAddress="false" rfc1349TrafficClass="IPTOS_LOWCOST"
+        sendBufferSize="8000" soLinger="12345" soTimeout="54321" tcpNoDelay="false">
+        <SocketPerformancePreferences bandwidth="100" connectionTime="100" latency="100" />
+      </SocketOptions>
+      <Ssl>
+        <KeyStore location="src/test/resources/org/apache/logging/log4j/core/net/ssl/client.log4j2-keystore.jks"
+          password="changeit" type="JKS" />
+        <TrustStore location="src/test/resources/org/apache/logging/log4j/core/net/ssl/truststore.jks"
+          password="changeit" type="JKS" />
+      </Ssl>
+    </Socket>
+  </Appenders>
+  <Loggers>
+    <Root level="debug">
+      <AppenderRef ref="socket" />
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92f1c652/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index b9aa337..037f404 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -147,6 +147,12 @@
       <action issue="LOG4J2-1704" dev="ggregory" type="add">
         Add a Builder to RollingRandomAccessFileAppender and deprecate RollingRandomAccessFileAppender.createAppender().
       </action>
+      <action issue="LOG4J2-1707" dev="ggregory" type="add">
+        Allow TCP Socket Appender to set socket options.
+      </action>
+      <action issue="LOG4J2-1708" dev="ggregory" type="add">
+        Allow Secure Socket Appender to set socket options.
+      </action>
     </release>
     <release version="2.7" date="2016-10-02" description="GA Release 2.7">
       <action issue="LOG4J2-1618" dev="rpopma" type="fix" due-to="Raman Gupta">