[LOG4J2-2237] Move Jackson-based layouts to their own modules: JSON,
XML, and YAML.

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

Branch: refs/heads/master
Commit: 0eb5212e4ac56030f07e88b9de432977e3808e48
Parents: ec3c623
Author: Gary Gregory <garydgreg...@gmail.com>
Authored: Mon Feb 19 19:09:06 2018 -0700
Committer: Gary Gregory <garydgreg...@gmail.com>
Committed: Mon Feb 19 19:09:06 2018 -0700

----------------------------------------------------------------------
 log4j-bom/pom.xml                               |  24 +
 log4j-core-its/pom.xml                          |  24 +-
 .../log4j/core/appender/HttpAppenderTest.java   | 316 ++++++++++++
 .../appender/JsonCompleteFileAppenderTest.java  | 110 +++++
 .../SecureSocketAppenderSocketOptionsTest.java  | 140 ++++++
 .../appender/SocketAppenderBufferSizeTest.java  |  77 +++
 .../SocketAppenderSocketOptionsTest.java        | 109 +++++
 .../log4j/core/appender/SocketAppenderTest.java | 412 ++++++++++++++++
 .../appender/XmlCompactFileAppenderTest.java    |  82 ++++
 .../XmlCompactFileAppenderValidationTest.java   | 106 ++++
 ...lCompactFileAsyncAppenderValidationTest.java |  83 ++++
 .../appender/XmlCompleteFileAppenderTest.java   | 173 +++++++
 .../core/appender/XmlFileAppenderTest.java      |  76 +++
 .../XmlRandomAccessFileAppenderTest.java        |  90 ++++
 log4j-core/pom.xml                              |   6 -
 .../ContextDataAsEntryListDeserializer.java     |  57 ---
 .../ContextDataAsEntryListSerializer.java       |  58 ---
 .../core/jackson/ContextDataDeserializer.java   |  65 ---
 .../core/jackson/ContextDataSerializer.java     |  64 ---
 .../jackson/ExtendedStackTraceElementMixIn.java |  90 ----
 .../log4j/core/jackson/Initializers.java        |  98 ----
 .../log4j/core/jackson/InstantMixIn.java        |  53 --
 .../log4j/core/jackson/JsonConstants.java       |  35 --
 .../logging/log4j/core/jackson/LevelMixIn.java  |  44 --
 .../jackson/ListOfMapEntryDeserializer.java     |  55 ---
 .../core/jackson/ListOfMapEntrySerializer.java  |  54 --
 .../log4j/core/jackson/Log4jJsonModule.java     |  61 ---
 .../core/jackson/Log4jJsonObjectMapper.java     |  47 --
 .../Log4jStackTraceElementDeserializer.java     |  82 ----
 .../log4j/core/jackson/Log4jXmlModule.java      |  50 --
 .../core/jackson/Log4jXmlObjectMapper.java      |  48 --
 .../log4j/core/jackson/Log4jYamlModule.java     |  59 ---
 .../core/jackson/Log4jYamlObjectMapper.java     |  48 --
 .../log4j/core/jackson/LogEventJsonMixIn.java   | 156 ------
 .../jackson/LogEventWithContextListMixIn.java   | 155 ------
 .../logging/log4j/core/jackson/MapEntry.java    | 110 -----
 .../logging/log4j/core/jackson/MarkerMixIn.java |  76 ---
 .../log4j/core/jackson/MessageSerializer.java   |  47 --
 .../MutableThreadContextStackDeserializer.java  |  51 --
 .../core/jackson/ObjectMessageSerializer.java   |  47 --
 .../core/jackson/SimpleMessageDeserializer.java |  47 --
 .../core/jackson/StackTraceElementMixIn.java    |  62 ---
 .../log4j/core/jackson/ThrowableProxyMixIn.java |  80 ---
 ...rowableProxyWithStacktraceAsStringMixIn.java |  78 ---
 .../ThrowableProxyWithoutStacktraceMixIn.java   |  77 ---
 .../log4j/core/jackson/XmlConstants.java        |  39 --
 .../log4j/core/jackson/package-info.java        |  21 -
 .../core/layout/AbstractJacksonLayout.java      | 350 -------------
 .../logging/log4j/core/layout/GelfLayout.java   |   2 +-
 .../log4j/core/layout/JacksonFactory.java       | 237 ---------
 .../logging/log4j/core/layout/JsonLayout.java   | 293 -----------
 .../logging/log4j/core/layout/XmlLayout.java    | 208 --------
 .../logging/log4j/core/layout/YamlLayout.java   | 206 --------
 .../parser/AbstractJacksonLogEventParser.java   |   4 +-
 .../log4j/core/parser/JsonLogEventParser.java   |  31 --
 .../log4j/core/parser/XmlLogEventParser.java    |  31 --
 .../log4j/core/parser/YamlLogEventParser.java   |  31 --
 .../logging/log4j/MarkerMixInJsonTest.java      |  33 --
 .../apache/logging/log4j/MarkerMixInTest.java   |  94 ----
 .../logging/log4j/MarkerMixInXmlTest.java       |  34 --
 .../logging/log4j/MarkerMixInYamlTest.java      |  34 --
 .../log4j/core/appender/HttpAppenderTest.java   | 316 ------------
 .../appender/JsonCompleteFileAppenderTest.java  | 110 -----
 .../SecureSocketAppenderSocketOptionsTest.java  | 140 ------
 .../appender/SocketAppenderBufferSizeTest.java  |  77 ---
 .../SocketAppenderSocketOptionsTest.java        | 109 -----
 .../log4j/core/appender/SocketAppenderTest.java | 411 ----------------
 .../appender/XmlCompactFileAppenderTest.java    |  81 ---
 .../XmlCompactFileAppenderValidationTest.java   | 106 ----
 ...lCompactFileAsyncAppenderValidationTest.java |  83 ----
 .../appender/XmlCompleteFileAppenderTest.java   | 172 -------
 .../core/appender/XmlFileAppenderTest.java      |  78 ---
 .../XmlRandomAccessFileAppenderTest.java        |  89 ----
 .../log4j/core/impl/ThrowableProxyTest.java     |  18 +-
 .../jackson/JacksonIssue429MyNamesTest.java     | 130 -----
 .../log4j/core/jackson/JacksonIssue429Test.java |  95 ----
 .../log4j/core/jackson/LevelMixInJsonTest.java  |  32 --
 .../log4j/core/jackson/LevelMixInTest.java      | 106 ----
 .../log4j/core/jackson/LevelMixInXmlTest.java   |  35 --
 .../log4j/core/jackson/LevelMixInYamlTest.java  |  32 --
 .../jackson/StackTraceElementMixInTest.java     |  92 ----
 .../ConcurrentLoggingWithJsonLayoutTest.java    | 116 -----
 .../log4j/core/layout/JsonLayoutTest.java       | 487 ------------------
 .../log4j/core/layout/LogEventFixtures.java     |   6 +-
 .../log4j/core/layout/XmlLayoutTest.java        | 387 ---------------
 .../log4j/core/layout/YamlLayoutTest.java       | 380 --------------
 .../core/parser/AbstractLogEventParserTest.java |  59 +++
 .../core/parser/JsonLogEventParserTest.java     | 130 -----
 .../log4j/core/parser/LogEventParserTest.java   |  55 ---
 .../core/parser/XmlLogEventParserTest.java      | 130 -----
 .../core/parser/YamlLogEventParserTest.java     | 126 -----
 .../src/test/resources/log4j2-xml-layout.xml    |  31 ++
 log4j-layout-jackson-json/pom.xml               | 167 +++++++
 .../json/JsonSetupContextInitializer.java       |  51 ++
 .../log4j/jackson/json/Log4jJsonModule.java     |  58 +++
 .../jackson/json/Log4jJsonObjectMapper.java     |  47 ++
 .../jackson/json/layout/JsonJacksonFactory.java |  60 +++
 .../log4j/jackson/json/layout/JsonLayout.java   | 327 +++++++++++++
 .../jackson/json/parser/JsonLogEventParser.java |  32 ++
 .../src/site/manual/index.md                    |  33 ++
 log4j-layout-jackson-json/src/site/site.xml     |  52 ++
 .../json/JacksonIssue429MyNamesTest.java        | 130 +++++
 .../log4j/jackson/json/JacksonIssue429Test.java |  95 ++++
 .../log4j/jackson/json/LevelMixInJsonTest.java  |  34 ++
 .../log4j/jackson/json/MarkerMixInJsonTest.java |  34 ++
 .../json/StackTraceElementJsonMixInTest.java    |  83 ++++
 .../ConcurrentLoggingWithJsonLayoutTest.java    | 117 +++++
 .../jackson/json/layout/JsonLayoutTest.java     | 489 +++++++++++++++++++
 .../json/layout/ThrowableProxyJsonTest.java     |  33 ++
 .../json/parser/JsonLogEventParserTest.java     | 132 +++++
 .../src/test/resources/log4j2-json-layout.xml   |  31 ++
 .../log4j/jackson/xml/Log4jXmlModule.java       |  49 ++
 .../log4j/jackson/xml/Log4jXmlObjectMapper.java |  48 ++
 .../log4j/jackson/xml/XmlInstantMixIn.java      |  56 +++
 .../xml/XmlLogEventWithContextListMixIn.java    |  50 ++
 .../log4j/jackson/xml/XmlMarkerMixIn.java       |  79 +++
 .../jackson/xml/XmlSetupContextInitializer.java |  42 ++
 .../jackson/xml/XmlStackTraceElementMixIn.java  |  39 ++
 .../xml/layout/Log4jXmlPrettyPrinter.java       |  41 ++
 .../jackson/xml/layout/XmlJacksonFactory.java   |  54 ++
 .../log4j/jackson/xml/layout/XmlLayout.java     | 226 +++++++++
 .../jackson/xml/parser/XmlLogEventParser.java   |  32 ++
 log4j-layout-jackson-xml/pom.xml                | 171 +++++++
 .../jackson/xml/AbstractLogEventXmlMixIn.java   | 135 +++++
 .../ContextDataAsEntryListXmlSerializer.java    |  37 ++
 .../xml/ExtendedStackTraceElementXmlMixIn.java  |  68 +++
 .../log4j/jackson/xml/InstantXmlMixIn.java      |  56 +++
 .../log4j/jackson/xml/Log4jXmlModule.java       |  52 ++
 .../log4j/jackson/xml/Log4jXmlObjectMapper.java |  48 ++
 .../xml/LogEventWithContextListXmlMixIn.java    |  48 ++
 .../log4j/jackson/xml/MarkerXmlMixIn.java       |  79 +++
 .../jackson/xml/StackTraceElementXmlMixIn.java  |  40 ++
 ...ableProxyWithStacktraceAsStringXmlMixIn.java |  77 +++
 ...ThrowableProxyWithoutStacktraceXmlMixIn.java |  60 +++
 .../jackson/xml/ThrowableProxyXmlMixIn.java     |  78 +++
 .../logging/log4j/jackson/xml/XmlMapEntry.java  |  41 ++
 .../jackson/xml/XmlSetupContextInitializer.java |  38 ++
 .../xml/layout/Log4jXmlPrettyPrinter.java       |  41 ++
 .../jackson/xml/layout/XmlJacksonFactory.java   |  54 ++
 .../log4j/jackson/xml/layout/XmlLayout.java     | 226 +++++++++
 .../jackson/xml/parser/XmlLogEventParser.java   |  32 ++
 .../src/site/manual/index.md                    |  33 ++
 log4j-layout-jackson-xml/src/site/site.xml      |  52 ++
 .../log4j/jackson/xml/LevelMixInXmlTest.java    |  36 ++
 .../log4j/jackson/xml/MarkerMixInXmlTest.java   |  34 ++
 .../xml/StackTraceElementXmlMixInTest.java      |  82 ++++
 .../ConcurrentLoggingWithXmlLayoutTest.java     | 116 +++++
 .../xml/layout/ThrowableProxyXmlTest.java       |  33 ++
 .../log4j/jackson/xml/layout/XmlLayoutTest.java | 440 +++++++++++++++++
 .../xml/parser/XmlLogEventParserTest.java       | 132 +++++
 .../src/test/resources/log4j2-xml-layout.xml    |  31 ++
 log4j-layout-jackson-yaml/pom.xml               | 171 +++++++
 .../log4j/jackson/yaml/Log4jYamlModule.java     |  59 +++
 .../jackson/yaml/Log4jYamlObjectMapper.java     |  48 ++
 .../yaml/YamlSetupContextInitializer.java       |  47 ++
 .../jackson/yaml/layout/YamlConstants.java      |  35 ++
 .../jackson/yaml/layout/YamlJacksonFactory.java |  68 +++
 .../log4j/jackson/yaml/layout/YamlLayout.java   | 239 +++++++++
 .../jackson/yaml/parser/YamlLogEventParser.java |  32 ++
 .../src/site/manual/index.md                    |  33 ++
 log4j-layout-jackson-yaml/src/site/site.xml     |  52 ++
 .../log4j/jackson/yaml/LevelMixInYamlTest.java  |  34 ++
 .../log4j/jackson/yaml/MarkerMixInYamlTest.java |  34 ++
 .../yaml/StackTraceElementYamlMixInTest.java    |  83 ++++
 .../ConcurrentLoggingWithYamlLayoutTest.java    | 113 +++++
 .../jackson/yaml/layout/YamlLayoutTest.java     | 382 +++++++++++++++
 .../yaml/parser/YamlLogEventParserTest.java     | 128 +++++
 .../src/test/resources/log4j2-yaml-layout.xml   |  31 ++
 log4j-layout-jackson/pom.xml                    | 214 ++++++++
 .../log4j/jackson/AbstractJacksonFactory.java   |  74 +++
 .../log4j/jackson/AbstractJacksonLayout.java    | 351 +++++++++++++
 .../log4j/jackson/AbstractLogEventMixIn.java    |  84 ++++
 .../ContextDataAsEntryListDeserializer.java     |  57 +++
 .../ContextDataAsEntryListSerializer.java       |  67 +++
 .../log4j/jackson/ContextDataDeserializer.java  |  65 +++
 .../log4j/jackson/ContextDataSerializer.java    |  64 +++
 .../jackson/ExtendedStackTraceElementMixIn.java | 100 ++++
 .../logging/log4j/jackson/InstantMixIn.java     |  55 +++
 .../logging/log4j/jackson/JsonConstants.java    |  36 ++
 .../logging/log4j/jackson/LevelMixIn.java       |  44 ++
 .../jackson/ListOfMapEntryDeserializer.java     |  55 +++
 .../log4j/jackson/ListOfMapEntrySerializer.java |  58 +++
 .../Log4jStackTraceElementDeserializer.java     |  82 ++++
 .../log4j/jackson/LogEventJsonMixIn.java        | 146 ++++++
 .../jackson/LogEventWithContextListMixIn.java   | 130 +++++
 .../apache/logging/log4j/jackson/MapEntry.java  | 109 +++++
 .../logging/log4j/jackson/MarkerMixIn.java      |  71 +++
 .../log4j/jackson/MessageSerializer.java        |  47 ++
 .../MutableThreadContextStackDeserializer.java  |  51 ++
 .../log4j/jackson/ObjectMessageSerializer.java  |  47 ++
 .../log4j/jackson/SetupContextInitializer.java  |  38 ++
 .../jackson/SimpleMessageDeserializer.java      |  47 ++
 .../log4j/jackson/SimpleModuleInitializer.java  |  26 +
 .../jackson/StackTraceElementConstants.java     |  30 ++
 .../log4j/jackson/StackTraceElementMixIn.java   |  59 +++
 .../log4j/jackson/ThrowableProxyMixIn.java      |  70 +++
 ...rowableProxyWithStacktraceAsStringMixIn.java |  70 +++
 .../ThrowableProxyWithoutStacktraceMixIn.java   |  69 +++
 .../logging/log4j/jackson/XmlConstants.java     |  39 ++
 .../jackson/layout/AbstractJacksonLayout.java   | 378 ++++++++++++++
 .../logging/log4j/jackson/package-info.java     |  21 +
 log4j-layout-jackson/src/site/manual/index.md   |  33 ++
 log4j-layout-jackson/src/site/site.xml          |  52 ++
 .../log4j/jackson/AbstractMarkerMixInTest.java  |  97 ++++
 .../logging/log4j/jackson/LevelMixInTest.java   | 106 ++++
 .../jackson/ThrowableProxyJacksonTest.java      |  51 ++
 pom.xml                                         |   4 +
 src/changes/changes.xml                         |   3 +
 208 files changed, 11800 insertions(+), 7829 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-bom/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml
index 97021b2..5ee35e8 100644
--- a/log4j-bom/pom.xml
+++ b/log4j-bom/pom.xml
@@ -42,6 +42,30 @@
         <artifactId>log4j-core</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <!--  Commons code for Jackson-based layouts -->
+      <dependency>
+        <groupId>org.apache.logging.log4j</groupId>
+        <artifactId>log4j-layout-jackson</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <!-- Jackson-based JSON layout -->
+      <dependency>
+        <groupId>org.apache.logging.log4j</groupId>
+        <artifactId>log4j-layout-jackson-json</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <!-- Jackson-based XML layout -->
+      <dependency>
+        <groupId>org.apache.logging.log4j</groupId>
+        <artifactId>log4j-layout-jackson-xml</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <!-- Jackson-based YAML layout -->
+      <dependency>
+        <groupId>org.apache.logging.log4j</groupId>
+        <artifactId>log4j-layout-jackson-yaml</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <!-- Legacy Log4j 1.2 API -->
       <dependency>
         <groupId>org.apache.logging.log4j</groupId>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-core-its/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-core-its/pom.xml b/log4j-core-its/pom.xml
index 2a0cec1..513fce3 100644
--- a/log4j-core-its/pom.xml
+++ b/log4j-core-its/pom.xml
@@ -29,13 +29,14 @@
   <description>Integration Tests for the Apache Log4j 
Implementation</description>
   <properties>
     <log4jParentDir>${basedir}/..</log4jParentDir>
-    <docLabel>Core Documentation</docLabel>
-    <projectDir>/core</projectDir>
+    <docLabel>Core Integration Tests Documentation</docLabel>
+    <projectDir>/log4j-core-its</projectDir>
   </properties>
   <dependencies>
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-api</artifactId>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
@@ -46,6 +47,19 @@
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-layout-jackson-json</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-layout-jackson-xml</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
@@ -53,6 +67,12 @@
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
+    <!-- Used for testing HttpAppender -->
+    <dependency>
+      <groupId>com.github.tomakehurst</groupId>
+      <artifactId>wiremock</artifactId>
+      <scope>test</scope>
+    </dependency>
     <!-- Required for AsyncLoggers -->
     <dependency>
       <groupId>com.lmax</groupId>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
new file mode 100644
index 0000000..4e9a07c
--- /dev/null
+++ 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
@@ -0,0 +1,316 @@
+/*
+ * 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 static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.containing;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.put;
+import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static 
com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.lookup.JavaLookup;
+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.TestConstants;
+import org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration;
+import org.apache.logging.log4j.jackson.json.layout.JsonLayout;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.status.StatusData;
+import org.apache.logging.log4j.status.StatusListener;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+
+@Ignore("Fails often on Windows")
+
+/* Fails often on Windows, for example:
+[ERROR] Failed to execute goal 
org.apache.maven.plugins:maven-surefire-plugin:2.20.1:test (default-test) on 
project log4j-core: There are test failures.
+[ERROR]
+[ERROR] Please refer to 
C:\vcs\git\apache\logging\logging-log4j2\log4j-core\target\surefire-reports for 
the individual test results.
+[ERROR] Please refer to dump files (if any exist) [date]-jvmRun[N].dump, 
[date].dumpstream and [date]-jvmRun[N].dumpstream.
+[ERROR] ExecutionException The forked VM terminated without properly saying 
goodbye. VM crash or System.exit called?
+[ERROR] Command was cmd.exe /X /C ""C:\Program 
Files\Java\jdk1.8.0_152\jre\bin\java" -Xms256m -Xmx1024m -jar 
C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112\surefirebooter1486874613063862199.jar
 C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112 
2018-01-23T11-03-18_847-jvmRun6 surefire6375637980242546356tmp 
surefire_441335531705722358735tmp"
+[ERROR] Process Exit Code: 0
+[ERROR] Crashed tests:
+[ERROR] org.apache.logging.log4j.core.appender.HttpAppenderTest
+[ERROR] org.apache.maven.surefire.booter.SurefireBooterForkException: 
ExecutionException The forked VM terminated without properly saying goodbye. VM 
crash or System.exit called?
+[ERROR] Command was cmd.exe /X /C ""C:\Program 
Files\Java\jdk1.8.0_152\jre\bin\java" -Xms256m -Xmx1024m -jar 
C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112\surefirebooter1486874613063862199.jar
 C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112 
2018-01-23T11-03-18_847-jvmRun6 surefire6375637980242546356tmp 
surefire_441335531705722358735tmp"
+[ERROR] Process Exit Code: 0
+[ERROR] Crashed tests:
+[ERROR] org.apache.logging.log4j.core.appender.HttpAppenderTest
+[ERROR]         at 
org.apache.maven.plugin.surefire.booterclient.ForkStarter.awaitResultsDone(ForkStarter.java:496)
+[ERROR]         at 
org.apache.maven.plugin.surefire.booterclient.ForkStarter.runSuitesForkPerTestSet(ForkStarter.java:443)
+[ERROR]         at 
org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:295)
+[ERROR]         at 
org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:246)
+[ERROR]         at 
org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:1124)
+[ERROR]         at 
org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:954)
+[ERROR]         at 
org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:832)
+[ERROR]         at 
org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
+[ERROR]         at 
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
+[ERROR]         at 
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:154)
+[ERROR]         at 
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:146)
+[ERROR]         at 
org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
+[ERROR]         at 
org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
+[ERROR]         at 
org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
+[ERROR]         at 
org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
+[ERROR]         at 
org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:309)
+[ERROR]         at 
org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:194)
+[ERROR]         at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:107)
+[ERROR]         at org.apache.maven.cli.MavenCli.execute(MavenCli.java:955)
+[ERROR]         at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:290)
+[ERROR]         at org.apache.maven.cli.MavenCli.main(MavenCli.java:194)
+[ERROR]         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+[ERROR]         at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
+[ERROR]         at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+[ERROR]         at java.lang.reflect.Method.invoke(Method.java:498)
+[ERROR]         at 
org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
+[ERROR]         at 
org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
+[ERROR]         at 
org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
+[ERROR]         at 
org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
+[ERROR] Caused by: 
org.apache.maven.surefire.booter.SurefireBooterForkException: The forked VM 
terminated without properly saying goodbye. VM crash or System.exit called?
+[ERROR] Command was cmd.exe /X /C ""C:\Program 
Files\Java\jdk1.8.0_152\jre\bin\java" -Xms256m -Xmx1024m -jar 
C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112\surefirebooter1486874613063862199.jar
 C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112 
2018-01-23T11-03-18_847-jvmRun6 surefire6375637980242546356tmp 
surefire_441335531705722358735tmp"
+[ERROR] Process Exit Code: 0
+[ERROR] Crashed tests:
+[ERROR] org.apache.logging.log4j.core.appender.HttpAppenderTest
+[ERROR]         at 
org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:686)
+[ERROR]         at 
org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:535)
+[ERROR]         at 
org.apache.maven.plugin.surefire.booterclient.ForkStarter.access$700(ForkStarter.java:116)
+[ERROR]         at 
org.apache.maven.plugin.surefire.booterclient.ForkStarter$2.call(ForkStarter.java:431)
+[ERROR]         at 
org.apache.maven.plugin.surefire.booterclient.ForkStarter$2.call(ForkStarter.java:408)
+[ERROR]         at java.util.concurrent.FutureTask.run(FutureTask.java:266)
+[ERROR]         at 
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
+[ERROR]         at 
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
+[ERROR]         at java.lang.Thread.run(Thread.java:748)
+[ERROR]
+[ERROR] -> [Help 1]
+[ERROR]
+[ERROR] To see the full stack trace of the errors, re-run Maven with the -e 
switch.
+[ERROR] Re-run Maven using the -X switch to enable full debug logging.
+[ERROR]
+[ERROR] For more information about the errors and possible solutions, please 
read the following articles:
+[ERROR] [Help 1] 
http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
+[ERROR]
+[ERROR] After correcting the problems, you can resume the build with the 
command
+[ERROR]   mvn <goals> -rf :log4j-core
+ */
+public class HttpAppenderTest {
+
+    private static final String LOG_MESSAGE = "Hello, world!";
+
+    private static Log4jLogEvent createLogEvent() {
+        return Log4jLogEvent.newBuilder()
+            .setLoggerName(HttpAppenderTest.class.getName())
+            .setLoggerFqcn(HttpAppenderTest.class.getName())
+            .setLevel(Level.INFO)
+            .setMessage(new SimpleMessage(LOG_MESSAGE))
+            .build();
+    }
+
+    private final ResponseDefinitionBuilder SUCCESS_RESPONSE = 
aResponse().withStatus(201)
+        .withHeader("Content-Type", "application/json")
+        .withBody("{\"status\":\"created\"}");
+
+    private final ResponseDefinitionBuilder FAILURE_RESPONSE = 
aResponse().withStatus(400)
+        .withHeader("Content-Type", "application/json")
+        .withBody("{\"status\":\"error\"}");
+
+    private final JavaLookup JAVA_LOOKUP = new JavaLookup();
+
+    @Rule
+    public LoggerContextRule ctx = new 
LoggerContextRule("HttpAppenderTest.xml");
+
+    @Rule
+    public WireMockRule wireMockRule = new 
WireMockRule(wireMockConfig().dynamicPort().dynamicHttpsPort()
+        .keystorePath(TestConstants.KEYSTORE_FILE)
+        .keystorePassword(String.valueOf(TestConstants.KEYSTORE_PWD()))
+        .keystoreType(TestConstants.KEYSTORE_TYPE));
+
+    @Test
+    public void testAppend() throws Exception {
+        wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
+            .willReturn(SUCCESS_RESPONSE));
+
+        final Appender appender = HttpAppender.newBuilder()
+            .withName("Http")
+            .withLayout(JsonLayout.createDefaultLayout())
+            .setConfiguration(ctx.getConfiguration())
+            .setUrl(new URL("http://localhost:"; + wireMockRule.port() + 
"/test/log4j/"))
+            .build();
+        appender.append(createLogEvent());
+
+        wireMockRule.verify(postRequestedFor(urlEqualTo("/test/log4j/"))
+            .withHeader("Host", containing("localhost"))
+            .withHeader("Content-Type", containing("application/json"))
+            .withRequestBody(containing("\"message\" : \"" + LOG_MESSAGE + 
"\"")));
+    }
+
+    @Test
+    public void testAppendHttps() throws Exception {
+        wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
+            .willReturn(SUCCESS_RESPONSE));
+
+        final Appender appender = HttpAppender.newBuilder()
+            .withName("Http")
+            .withLayout(JsonLayout.createDefaultLayout())
+            .setConfiguration(ctx.getConfiguration())
+            .setUrl(new URL("https://localhost:"; + wireMockRule.httpsPort() + 
"/test/log4j/"))
+            .setSslConfiguration(SslConfiguration.createSSLConfiguration(null,
+                
KeyStoreConfiguration.createKeyStoreConfiguration(TestConstants.KEYSTORE_FILE, 
TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, null),
+                
TrustStoreConfiguration.createKeyStoreConfiguration(TestConstants.TRUSTSTORE_FILE,
 TestConstants.TRUSTSTORE_PWD(), TestConstants.TRUSTSTORE_TYPE, null)))
+            .setVerifyHostname(false)
+            .build();
+        appender.append(createLogEvent());
+
+        wireMockRule.verify(postRequestedFor(urlEqualTo("/test/log4j/"))
+            .withHeader("Host", containing("localhost"))
+            .withHeader("Content-Type", containing("application/json"))
+            .withRequestBody(containing("\"message\" : \"" + LOG_MESSAGE + 
"\"")));
+    }
+
+    @Test
+    public void testAppendMethodPut() throws Exception {
+        wireMockRule.stubFor(put(urlEqualTo("/test/log4j/1234"))
+            .willReturn(SUCCESS_RESPONSE));
+
+        final Appender appender = HttpAppender.newBuilder()
+            .withName("Http")
+            .withLayout(JsonLayout.createDefaultLayout())
+            .setConfiguration(ctx.getConfiguration())
+            .setMethod("PUT")
+            .setUrl(new URL("http://localhost:"; + wireMockRule.port() + 
"/test/log4j/1234"))
+            .build();
+        appender.append(createLogEvent());
+
+        wireMockRule.verify(putRequestedFor(urlEqualTo("/test/log4j/1234"))
+            .withHeader("Host", containing("localhost"))
+            .withHeader("Content-Type", containing("application/json"))
+            .withRequestBody(containing("\"message\" : \"" + LOG_MESSAGE + 
"\"")));
+    }
+
+    @Test
+    public void testAppendCustomHeader() throws Exception {
+        wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
+            .willReturn(SUCCESS_RESPONSE));
+
+        final Appender appender = HttpAppender.newBuilder()
+            .withName("Http")
+            .withLayout(JsonLayout.createDefaultLayout())
+            .setConfiguration(ctx.getConfiguration())
+            .setUrl(new URL("http://localhost:"; + wireMockRule.port() + 
"/test/log4j/"))
+            .setHeaders(new Property[] {
+                Property.createProperty("X-Test", "header value"),
+                Property.createProperty("X-Runtime", "${java:runtime}")
+            })
+            .build();
+        appender.append(createLogEvent());
+
+        wireMockRule.verify(postRequestedFor(urlEqualTo("/test/log4j/"))
+            .withHeader("Host", containing("localhost"))
+            .withHeader("X-Test", equalTo("header value"))
+            .withHeader("X-Runtime", equalTo(JAVA_LOOKUP.getRuntime()))
+            .withHeader("Content-Type", containing("application/json"))
+            .withRequestBody(containing("\"message\" : \"" + LOG_MESSAGE + 
"\"")));
+    }
+
+    volatile StatusData error;
+
+    @Test
+    public void testAppendErrorIgnore() throws Exception {
+        wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
+            .willReturn(FAILURE_RESPONSE));
+
+        StatusLogger.getLogger().registerListener(new StatusListener() {
+            @Override
+            public void log(final StatusData data) {
+                error = data;
+            }
+
+            @Override
+            public Level getStatusLevel() {
+                return Level.ERROR;
+            }
+
+            @Override
+            public void close() throws IOException { }
+        });
+
+        error = null;
+
+        final Appender appender = HttpAppender.newBuilder()
+            .withName("Http")
+            .withLayout(JsonLayout.createDefaultLayout())
+            .setConfiguration(ctx.getConfiguration())
+            .setUrl(new URL("http://localhost:"; + wireMockRule.port() + 
"/test/log4j/"))
+            .build();
+        appender.append(createLogEvent());
+
+        wireMockRule.verify(postRequestedFor(urlEqualTo("/test/log4j/"))
+            .withHeader("Host", containing("localhost"))
+            .withHeader("Content-Type", containing("application/json"))
+            .withRequestBody(containing("\"message\" : \"" + LOG_MESSAGE + 
"\"")));
+
+        assertNotNull(error);
+        assertEquals(Level.ERROR, error.getLevel());
+        assertEquals("Unable to send HTTP in appender [Http]", 
error.getMessage().toString());
+    }
+
+    @Test(expected = AppenderLoggingException.class)
+    public void testAppendError() throws Exception {
+        wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
+            .willReturn(FAILURE_RESPONSE));
+
+        final Appender appender = HttpAppender.newBuilder()
+            .withName("Http")
+            .withLayout(JsonLayout.createDefaultLayout())
+            .setConfiguration(ctx.getConfiguration())
+            .withIgnoreExceptions(false)
+            .setUrl(new URL("http://localhost:"; + wireMockRule.port() + 
"/test/log4j/"))
+            .build();
+        appender.append(createLogEvent());
+    }
+
+    @Test(expected = AppenderLoggingException.class)
+    public void testAppendConnectError() throws Exception {
+        final Appender appender = HttpAppender.newBuilder()
+            .withName("Http")
+            .withLayout(JsonLayout.createDefaultLayout())
+            .setConfiguration(ctx.getConfiguration())
+            .withIgnoreExceptions(false)
+            .setUrl(new 
URL("http://localhost:"+(wireMockRule.port()+1)+"/test/log4j/"))
+            .build();
+        appender.append(createLogEvent());
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
new file mode 100644
index 0000000..4c2da52
--- /dev/null
+++ 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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 static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.util.List;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.core.impl.Log4jLogEventTest;
+import org.apache.logging.log4j.core.selector.ContextSelector;
+import org.apache.logging.log4j.core.selector.CoreContextSelectors;
+import org.apache.logging.log4j.core.time.ClockFactory;
+import org.apache.logging.log4j.junit.CleanFiles;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Tests a "complete" JSON file.
+ */
+@RunWith(Parameterized.class)
+@Category(Layouts.Json.class)
+public class JsonCompleteFileAppenderTest {
+
+    public JsonCompleteFileAppenderTest(final Class<ContextSelector> 
contextSelector) {
+        this.loggerContextRule = new 
LoggerContextRule("JsonCompleteFileAppenderTest.xml", contextSelector);
+        this.cleanFiles = new CleanFiles(logFile);
+        this.ruleChain = 
RuleChain.outerRule(cleanFiles).around(loggerContextRule);
+    }
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ClockFactory.PROPERTY_NAME, 
Log4jLogEventTest.FixedTimeClock.class.getName());
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        System.clearProperty(ClockFactory.PROPERTY_NAME);
+    }
+
+    @Parameters(name = "{0}")
+    public static Class<?>[] getParameters() {
+        return CoreContextSelectors.CLASSES;
+    }
+
+    private final File logFile = new File("target", 
"JsonCompleteFileAppenderTest.log");
+    private final LoggerContextRule loggerContextRule;
+    private final CleanFiles cleanFiles;
+
+    @Rule
+    public RuleChain ruleChain;
+
+    @Test
+    public void testFlushAtEndOfBatch() throws Exception {
+        final Logger logger = this.loggerContextRule.getLogger("com.foo.Bar");
+        final String logMsg = "Message flushed with immediate flush=true";
+        logger.info(logMsg);
+        logger.error(logMsg, new IllegalArgumentException("badarg"));
+        this.loggerContextRule.getLoggerContext().stop(); // stops async thread
+
+        List<String> lines = Files.readAllLines(logFile.toPath(), 
Charset.forName("UTF8"));
+
+        String[] expected = {
+                "[", // equals
+                "{", // equals
+                "  \"thread\" : \"main\",", //
+                "  \"level\" : \"INFO\",", //
+                "  \"loggerName\" : \"com.foo.Bar\",", //
+                "  \"message\" : \"Message flushed with immediate 
flush=true\",", //
+                "  \"endOfBatch\" : false,", //
+                "  \"loggerFqcn\" : 
\"org.apache.logging.log4j.spi.AbstractLogger\",", //
+                "  \"instant\" : {", //
+                "    \"epochSecond\" : 1234567,", //
+                "    \"nanoOfSecond\" : 890000000", //
+                "  },", //
+        };
+        for (int i = 0; i < expected.length; i++) {
+            String line = lines.get(i);
+            assertTrue("line " + i + " incorrect: [" + line + "], does not 
contain: [" + expected[i] + ']', line.contains(expected[i]));
+        }
+        final String location = "testFlushAtEndOfBatch";
+        assertTrue("no location", !lines.get(0).contains(location));
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
new file mode 100644
index 0000000..abee218
--- /dev/null
+++ 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.Assume;
+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 = 
KeyStoreConfiguration.createKeyStoreConfiguration(
+                TestConstants.KEYSTORE_FILE, // file
+                TestConstants.KEYSTORE_PWD(),  // password
+                null, // passwordEnvironmentVariable
+                null, // passwordFile
+                null, // key store type
+                null); // algorithm
+
+        final TrustStoreConfiguration tsc = 
TrustStoreConfiguration.createKeyStoreConfiguration(
+                TestConstants.TRUSTSTORE_FILE, // file
+                TestConstants.TRUSTSTORE_PWD(), // password
+                null, // passwordEnvironmentVariable
+                null, // passwordFile
+                null, // key store type
+                null); // algorithm
+        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(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());
+    }
+
+    @Test
+    public void testSocketTrafficClass() throws IOException {
+        Assume.assumeTrue("Run only on Java 7", 
System.getProperty("java.specification.version").equals("1.7"));
+        Assume.assumeFalse("Do not run on Travis CI", 
"true".equals(System.getenv("TRAVIS")));
+        final SocketAppender appender = 
loggerContextRule.getAppender("socket", SocketAppender.class);
+        final TcpSocketManager manager = (TcpSocketManager) 
appender.getManager();
+        final Socket socket = manager.getSocket();
+        Assert.assertEquals(Rfc1349TrafficClass.IPTOS_LOWCOST.value(), 
socket.getTrafficClass());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java
 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java
new file mode 100644
index 0000000..85b6b17
--- /dev/null
+++ 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import 
org.apache.logging.log4j.core.appender.SocketAppenderTest.TcpSocketTestServer;
+import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.AvailablePortFinder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class SocketAppenderBufferSizeTest {
+
+    private TcpSocketTestServer tcpServer;
+
+    private LoggerContext loggerContext;
+    private Logger logger;
+
+    @Rule
+    public LoggerContextRule loggerContextRule = new 
LoggerContextRule("log4j-empty.xml");
+
+    @Before
+    public void setup() throws Exception {
+        tcpServer = new 
TcpSocketTestServer(AvailablePortFinder.getNextAvailable());
+        tcpServer.start();
+        ThreadContext.clearAll();
+        loggerContext = loggerContextRule.getLoggerContext();
+        logger = 
loggerContext.getLogger(SocketAppenderBufferSizeTest.class.getName());
+    }
+
+    @After
+    public void teardown() {
+        tcpServer.shutdown();
+        loggerContext = null;
+        logger = null;
+        tcpServer.reset();
+        ThreadContext.clearAll();
+    }
+
+    @Test
+    public void testTcpAppenderDefaultEncoderBufferSize() throws Exception {
+        SocketAppenderTest.testTcpAppender(tcpServer, logger, 
Constants.ENCODER_BYTE_BUFFER_SIZE);
+    }
+
+    @Test
+    public void testTcpAppenderLargeEncoderBufferSize() throws Exception {
+        SocketAppenderTest.testTcpAppender(tcpServer, logger, 
Constants.ENCODER_BYTE_BUFFER_SIZE * 100);
+    }
+
+    @Test
+    public void testTcpAppenderSmallestEncoderBufferSize() throws Exception {
+        SocketAppenderTest.testTcpAppender(tcpServer, logger, 1);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
new file mode 100644
index 0000000..030fa80
--- /dev/null
+++ 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.Assume;
+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 (final 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(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());
+    }
+
+    @Test
+    public void testSocketTrafficClass() throws IOException {
+        Assume.assumeTrue("Run only on Java 7", 
System.getProperty("java.specification.version").equals("1.7"));
+        Assume.assumeFalse("Do not run on Travis CI", 
"true".equals(System.getenv("TRAVIS")));
+        final SocketAppender appender = 
loggerContextRule.getAppender("socket", SocketAppender.class);
+        final TcpSocketManager manager = (TcpSocketManager) 
appender.getManager();
+        final Socket socket = manager.getSocket();
+        Assert.assertEquals(Rfc1349TrafficClass.IPTOS_LOWCOST.value(), 
socket.getTrafficClass());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
new file mode 100644
index 0000000..e02590c
--- /dev/null
+++ 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
@@ -0,0 +1,412 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LoggingException;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.net.Protocol;
+import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.Throwables;
+import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper;
+import org.apache.logging.log4j.jackson.json.layout.JsonLayout;
+import org.apache.logging.log4j.test.AvailablePortFinder;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.MappingIterator;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ *
+ */
+public class SocketAppenderTest {
+
+    private static final int PORT = AvailablePortFinder.getNextAvailable();
+    private static final int DYN_PORT = AvailablePortFinder.getNextAvailable();
+    private static final int ERROR_PORT = 
AvailablePortFinder.getNextAvailable();
+
+    private static TcpSocketTestServer tcpServer;
+    private static UdpSocketTestServer udpServer;
+
+    private final LoggerContext context = LoggerContext.getContext();
+    private final Logger logger = 
context.getLogger(SocketAppenderTest.class.getName());
+
+    @BeforeClass
+    public static void setupClass() throws Exception {
+        tcpServer = new TcpSocketTestServer(PORT);
+        tcpServer.start();
+        udpServer = new UdpSocketTestServer();
+        udpServer.start();
+        LoggerContext.getContext().reconfigure();
+        ThreadContext.clearAll();
+    }
+
+    @AfterClass
+    public static void cleanupClass() {
+        tcpServer.shutdown();
+        udpServer.shutdown();
+        ThreadContext.clearAll();
+    }
+
+    @After
+    public void teardown() {
+        ThreadContext.clearAll();
+        removeAndStopAppenders();
+        reset();
+    }
+
+    void removeAndStopAppenders() {
+        final Map<String, Appender> map = logger.getAppenders();
+        for (final Map.Entry<String, Appender> entry : map.entrySet()) {
+            final Appender appender = entry.getValue();
+            logger.removeAppender(appender);
+            appender.stop();
+        }
+    }
+
+    static void reset() {
+        tcpServer.reset();
+        udpServer.reset();
+    }
+
+    @Test
+    public void testTcpAppender1() throws Exception {
+        testTcpAppender(tcpServer, logger, Constants.ENCODER_BYTE_BUFFER_SIZE);
+    }
+
+    @Test
+    @Ignore("WIP Bug when this method runs after testTcpAppender1()")
+    public void testTcpAppender2() throws Exception {
+        testTcpAppender(tcpServer, logger, Constants.ENCODER_BYTE_BUFFER_SIZE);
+    }
+
+    static void testTcpAppender(final TcpSocketTestServer tcpTestServer, final 
Logger logger, final int bufferSize)
+            throws Exception {
+        // @formatter:off
+        final SocketAppender appender = SocketAppender.newBuilder()
+                .withHost("localhost")
+                .withPort(tcpTestServer.getLocalPort())
+                .withReconnectDelayMillis(-1)
+                .withName("test")
+                .withImmediateFail(false)
+                .withBufferSize(bufferSize)
+                
.withLayout(JsonLayout.newBuilder().setProperties(true).build())
+                .build();
+        // @formatter:on
+        appender.start();
+        Assert.assertEquals(bufferSize, 
appender.getManager().getByteBuffer().capacity());
+
+        // set appender on root and set level to debug
+        logger.addAppender(appender);
+        logger.setAdditive(false);
+        logger.setLevel(Level.DEBUG);
+        final String tcKey = "UUID";
+        final String expectedUuidStr = UUID.randomUUID().toString();
+        ThreadContext.put(tcKey, expectedUuidStr);
+        ThreadContext.push(expectedUuidStr);
+        final String expectedExMsg = "This is a test";
+        try {
+            logger.debug("This is a test message");
+            final Throwable child = new LoggingException(expectedExMsg);
+            logger.error("Throwing an exception", child);
+            logger.debug("This is another test message");
+        } finally {
+            ThreadContext.remove(tcKey);
+            ThreadContext.pop();
+        }
+        Thread.sleep(250);
+        LogEvent event = tcpTestServer.getQueue().poll(3, TimeUnit.SECONDS);
+        assertNotNull("No event retrieved", event);
+        assertTrue("Incorrect event", 
event.getMessage().getFormattedMessage().equals("This is a test message"));
+        assertTrue("Message not delivered via TCP", tcpTestServer.getCount() > 
0);
+        assertEquals(expectedUuidStr, event.getContextData().getValue(tcKey));
+        event = tcpTestServer.getQueue().poll(3, TimeUnit.SECONDS);
+        assertNotNull("No event retrieved", event);
+        assertTrue("Incorrect event", 
event.getMessage().getFormattedMessage().equals("Throwing an exception"));
+        assertTrue("Message not delivered via TCP", tcpTestServer.getCount() > 
1);
+        assertEquals(expectedUuidStr, event.getContextStack().pop());
+        assertNotNull(event.getThrownProxy());
+        assertEquals(expectedExMsg, event.getThrownProxy().getMessage());
+    }
+
+    @Test
+    public void testDefaultProtocol() throws Exception {
+        // @formatter:off
+        final SocketAppender appender = SocketAppender.newBuilder()
+                .withPort(tcpServer.getLocalPort())
+                .withReconnectDelayMillis(-1)
+                .withName("test")
+                .withImmediateFail(false)
+                
.withLayout(JsonLayout.newBuilder().setProperties(true).build())
+                .build();
+        // @formatter:on
+        assertNotNull(appender);
+        appender.stop();
+    }
+
+    @Test
+    public void testUdpAppender() throws Exception {
+        try {
+            udpServer.latch.await();
+        } catch (final InterruptedException ex) {
+            ex.printStackTrace();
+        }
+
+        // @formatter:off
+        final SocketAppender appender = SocketAppender.newBuilder()
+                .withProtocol(Protocol.UDP)
+                .withPort(tcpServer.getLocalPort())
+                .withReconnectDelayMillis(-1)
+                .withName("test")
+                .withImmediateFail(false)
+                
.withLayout(JsonLayout.newBuilder().setProperties(true).build())
+                .build();
+        // @formatter:on
+        appender.start();
+
+        // set appender on root and set level to debug
+        logger.addAppender(appender);
+        logger.setAdditive(false);
+        logger.setLevel(Level.DEBUG);
+        logger.debug("This is a udp message");
+        final LogEvent event = udpServer.getQueue().poll(3, TimeUnit.SECONDS);
+        assertNotNull("No event retrieved", event);
+        assertTrue("Incorrect event", 
event.getMessage().getFormattedMessage().equals("This is a udp message"));
+        assertTrue("Message not delivered via UDP", udpServer.getCount() > 0);
+    }
+
+    @Test
+    public void testTcpAppenderDeadlock() throws Exception {
+
+        // @formatter:off
+        final SocketAppender appender = SocketAppender.newBuilder()
+                .withHost("localhost")
+                .withPort(DYN_PORT)
+                .withReconnectDelayMillis(100)
+                .withName("test")
+                .withImmediateFail(false)
+                
.withLayout(JsonLayout.newBuilder().setProperties(true).build())
+                .build();
+        // @formatter:on
+        appender.start();
+        // set appender on root and set level to debug
+        logger.addAppender(appender);
+        logger.setAdditive(false);
+        logger.setLevel(Level.DEBUG);
+
+        final TcpSocketTestServer tcpSocketServer = new 
TcpSocketTestServer(DYN_PORT);
+        try {
+            tcpSocketServer.start();
+
+            logger.debug("This message is written because a deadlock never.");
+
+            final LogEvent event = tcpSocketServer.getQueue().poll(3, 
TimeUnit.SECONDS);
+            assertNotNull("No event retrieved", event);
+        } finally {
+            tcpSocketServer.shutdown();
+        }
+    }
+
+    @Test
+    public void testTcpAppenderNoWait() throws Exception {
+        // @formatter:off
+        final SocketAppender appender = SocketAppender.newBuilder()
+                .withHost("localhost")
+                .withPort(ERROR_PORT)
+                .withReconnectDelayMillis(100)
+                .withName("test")
+                .withImmediateFail(false)
+                .withIgnoreExceptions(false)
+                
.withLayout(JsonLayout.newBuilder().setProperties(true).build())
+                .build();
+        // @formatter:on
+        appender.start();
+        // set appender on root and set level to debug
+        logger.addAppender(appender);
+        logger.setAdditive(false);
+        logger.setLevel(Level.DEBUG);
+
+        try {
+            logger.debug("This message is written because a deadlock never.");
+            fail("No Exception was thrown");
+        } catch (final Exception ex) {
+            // TODO: move exception to @Test(expect = Exception.class)
+            // Failure is expected.
+            // ex.printStackTrace();
+        }
+    }
+
+    public static class UdpSocketTestServer extends Thread {
+
+        private final DatagramSocket sock;
+        private boolean shutdown = false;
+        private Thread thread;
+        private final CountDownLatch latch = new CountDownLatch(1);
+        private volatile int count = 0;
+        private final BlockingQueue<LogEvent> queue;
+        private final ObjectMapper objectMapper = new Log4jJsonObjectMapper();
+
+        public UdpSocketTestServer() throws IOException {
+            this.sock = new DatagramSocket(PORT);
+            this.queue = new ArrayBlockingQueue<>(10);
+        }
+
+        public void reset() {
+            queue.clear();
+            count = 0;
+        }
+
+        public void shutdown() {
+            this.shutdown = true;
+            thread.interrupt();
+            try {
+                thread.join(100);
+            } catch (InterruptedException ie) {
+                System.out.println("Unable to stop server");
+            }
+        }
+
+        @Override
+        public void run() {
+            this.thread = Thread.currentThread();
+            final byte[] bytes = new byte[4096];
+            final DatagramPacket packet = new DatagramPacket(bytes, 
bytes.length);
+            try {
+                while (!shutdown) {
+                    latch.countDown();
+                    sock.receive(packet);
+                    ++count;
+                    final LogEvent event = 
objectMapper.readValue(packet.getData(), Log4jLogEvent.class);
+                    queue.add(event);
+                }
+            } catch (final Throwable e) {
+                e.printStackTrace();
+                if (!shutdown) {
+                    Throwables.rethrow(e);
+                }
+            }
+        }
+
+        public int getCount() {
+            return count;
+        }
+
+        public BlockingQueue<LogEvent> getQueue() {
+            return queue;
+        }
+    }
+
+    public static class TcpSocketTestServer extends Thread {
+
+        private final ServerSocket serverSocket;
+        private volatile boolean shutdown = false;
+        private volatile int count = 0;
+        private final BlockingQueue<LogEvent> queue;
+        private final ObjectMapper objectMapper = new Log4jJsonObjectMapper();
+
+        @SuppressWarnings("resource")
+        public TcpSocketTestServer(final int port) throws IOException {
+            this(new ServerSocket(port));
+        }
+
+        public TcpSocketTestServer(final ServerSocket serverSocket) {
+            this.serverSocket = serverSocket;
+            this.queue = new ArrayBlockingQueue<>(10);
+        }
+
+        public int getLocalPort() {
+            return serverSocket.getLocalPort();
+        }
+
+        public void reset() {
+            queue.clear();
+            count = 0;
+        }
+
+        public void shutdown() {
+            this.shutdown = true;
+            interrupt();
+            try {
+                this.join(100);
+            } catch (InterruptedException ie) {
+                System.out.println("Unable to stop server");
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                try (final Socket socket = serverSocket.accept()) {
+                    if (socket != null) {
+                        final InputStream is = socket.getInputStream();
+                        while (!shutdown) {
+                            final MappingIterator<LogEvent> mappingIterator = 
objectMapper.readerFor(Log4jLogEvent.class).readValues(is);
+                            while (mappingIterator.hasNextValue()) {
+                                queue.add(mappingIterator.nextValue());
+                                ++count;
+                            }
+                        }
+                    }
+                }
+            } catch (final EOFException eof) {
+                // Socket is closed.
+            } catch (final Exception e) {
+                if (!shutdown) {
+                    Throwables.rethrow(e);
+                }
+            }
+        }
+
+        public BlockingQueue<LogEvent> getQueue() {
+            return queue;
+        }
+
+        public int getCount() {
+            return count;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java
 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java
new file mode 100644
index 0000000..eea989a
--- /dev/null
+++ 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.appender;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.core.CoreLoggerContexts;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * Tests a "compact" XML file, no extra spaces or end of lines.
+ */
+@Category(Layouts.Xml.class)
+public class XmlCompactFileAppenderTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
+                "XmlCompactFileAppenderTest.xml");
+    }
+
+    @Test
+    public void testFlushAtEndOfBatch() throws Exception {
+        final File file = new File("target", "XmlCompactFileAppenderTest.log");
+        file.delete();
+        final Logger log = LogManager.getLogger("com.foo.Bar");
+        final String logMsg = "Message flushed with immediate flush=false";
+        log.info(logMsg);
+        CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
+
+        String line1;
+        try (final BufferedReader reader = new BufferedReader(new 
FileReader(file))) {
+            line1 = reader.readLine();
+        } finally {
+            file.delete();
+        }
+        assertNotNull("line1", line1);
+        final String msg1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+        assertTrue("line1 incorrect: [" + line1 + "], does not contain: [" + 
msg1 + ']', line1.contains(msg1));
+
+        final String msg2 = "<Events 
xmlns=\"http://logging.apache.org/log4j/2.0/events\";>";
+        assertTrue("line1 incorrect: [" + line1 + "], does not contain: [" + 
msg2 + ']', line1.contains(msg2));
+
+        final String msg3 = "<Event ";
+        assertTrue("line1 incorrect: [" + line1 + "], does not contain: [" + 
msg3 + ']', line1.contains(msg3));
+
+        final String msg4 = logMsg;
+        assertTrue("line1 incorrect: [" + line1 + "], does not contain: [" + 
msg4 + ']', line1.contains(msg4));
+
+        final String location = "testFlushAtEndOfBatch";
+        assertTrue("no location", !line1.contains(location));
+
+        assertTrue(line1.indexOf('\r') == -1);
+        assertTrue(line1.indexOf('\n') == -1);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderValidationTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderValidationTest.java
 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderValidationTest.java
new file mode 100644
index 0000000..9b4da79
--- /dev/null
+++ 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderValidationTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.File;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.xml.XMLConstants;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.xml.sax.SAXException;
+
+/**
+ * Tests XML validation for a "compact" XML file, no extra spaces or end of 
lines.
+ */
+@Ignore
+@Category(Layouts.Xml.class)
+public class XmlCompactFileAppenderValidationTest {
+
+    private LoggerContext loggerContext;
+
+    @Before
+    public void before() {
+        this.loggerContext = 
Configurator.initialize(XmlCompactFileAppenderValidationTest.class.getName(),
+                
"target/test-classes/XmlCompactFileAppenderValidationTest.xml");
+    }
+
+    @After
+    public void after() {
+        // Just in case, an @Test blew up
+        Configurator.shutdown(this.loggerContext);
+    }
+
+    @Test
+    public void validateXmlSchemaThrowable() throws Exception {
+        final File file = new File("target", 
"XmlCompactFileAppenderValidationTest.log.xml");
+        file.delete();
+        final Logger log = LogManager.getLogger("com.foo.Bar");
+        try {
+            throw new IllegalArgumentException("IAE");
+        } catch (final IllegalArgumentException e) {
+            log.warn("Message 1", e);
+        }
+        Configurator.shutdown(this.loggerContext);
+        this.validateXmlSchema(file);
+    }
+
+    @Test
+    public void validateXmlSchema() throws Exception {
+        final File file = new File("target", 
"XmlCompactFileAppenderValidationTest.log.xml");
+        file.delete();
+        final Logger log = LogManager.getLogger("com.foo.Bar");
+        log.warn("Message 1");
+        log.info("Message 2");
+        log.debug("Message 3");
+        Configurator.shutdown(this.loggerContext);
+        this.validateXmlSchema(file);
+    }
+
+    @Test
+    public void validateXmlNoEvents() throws Exception {
+        final File file = new File("target", 
"XmlCompactFileAppenderValidationTest.log.xml");
+        file.delete();
+        Configurator.shutdown(this.loggerContext);
+        this.validateXmlSchema(file);
+    }
+
+    private void validateXmlSchema(final File file) throws SAXException, 
IOException {
+        final URL schemaFile = 
this.getClass().getClassLoader().getResource("Log4j-events.xsd");
+        final Source xmlFile = new StreamSource(file);
+        final SchemaFactory schemaFactory = 
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        final Schema schema = schemaFactory.newSchema(schemaFile);
+        final Validator validator = schema.newValidator();
+        validator.validate(xmlFile);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAsyncAppenderValidationTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAsyncAppenderValidationTest.java
 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAsyncAppenderValidationTest.java
new file mode 100644
index 0000000..1e048b1
--- /dev/null
+++ 
b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAsyncAppenderValidationTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.File;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.xml.XMLConstants;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.core.CoreLoggerContexts;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.xml.sax.SAXException;
+
+/**
+ * Tests XML validation for a "compact" XML file, no extra spaces or end of 
lines.
+ */
+@Ignore
+@Category(Layouts.Xml.class)
+public class XmlCompactFileAsyncAppenderValidationTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
+                "XmlCompactFileAsyncAppenderValidationTest.xml");
+    }
+
+    @Test
+    public void validateXmlSchemaSimple() throws Exception {
+        final File file = new File("target", 
"XmlCompactFileAsyncAppenderValidationTest.log.xml");
+        file.delete();
+        final Logger log = LogManager.getLogger("com.foo.Bar");
+        log.warn("Message 1");
+        log.info("Message 2");
+        log.debug("Message 3");
+        CoreLoggerContexts.stopLoggerContext(file); // stop async thread
+        this.validateXmlSchema(file);
+    }
+
+    @Test
+    public void validateXmlSchemaNoEvents() throws Exception {
+        final File file = new File("target", 
"XmlCompactFileAsyncAppenderValidationTest.log.xml");
+        file.delete();
+        CoreLoggerContexts.stopLoggerContext(file); // stop async thread
+        this.validateXmlSchema(file);
+    }
+
+    private void validateXmlSchema(final File file) throws SAXException, 
IOException {
+        final URL schemaFile = 
this.getClass().getClassLoader().getResource("Log4j-events.xsd");
+        final Source xmlFile = new StreamSource(file);
+        final SchemaFactory schemaFactory = 
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        final Schema schema = schemaFactory.newSchema(schemaFile);
+        final Validator validator = schema.newValidator();
+        validator.validate(xmlFile);
+    }
+
+}

Reply via email to