Remove unused files
diff --git a/.editorconfig b/.editorconfig
index 8faf628..c013fc3 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,9 +1,28 @@
 root = true
 
+[.editorconfig]
+charset						= utf-8
+end_of_line					= lf
+indent_size					= 4
+indent_style				= tab
+insert_final_newline		= true
+tab_width					= 4
+trim_trailing_whitespace	= true
+
 [*]
 charset						= utf-8
 end_of_line					= lf
 indent_size					= 4
 indent_style				= tab
+insert_final_newline		= true
 tab_width					= 4
 trim_trailing_whitespace	= true
+
+[*.sh]
+charset						= utf-8
+end_of_line					= lf
+indent_size					= 2
+indent_style				= space
+insert_final_newline		= true
+tab_width					= 2
+trim_trailing_whitespace	= true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index df334be..91cfb74 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,13 +7,13 @@
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/src/cmake")
 
 # Find Apache Runtime
-find_package(apr QUIET)
+find_package(APR QUIET)
 # If APR find module sets the cache, the following will do nothing
 find_path(APR_INCLUDE_DIR apr.h PATH_SUFFIXES apr-1)
 find_library(APR_LIBRARIES NAMES libapr-1 apr-1)
 
 # Find Apache Runtime Utilities
-find_package(apr-util QUIET)
+find_package(APR-Util QUIET)
 # If APR-UTIL find module sets the cache, the following will do nothing
 find_path(APR_UTIL_INCLUDE_DIR apu.h PATH_SUFFIXES apr-1)
 find_library(APR_UTIL_LIBRARIES NAMES libaprutil-1 aprutil-1)
diff --git a/autogen.sh b/autogen.sh
index 8a9b561..2ca2925 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -17,8 +17,8 @@
 # Regenerate the files autoconf / automake
 
 case `uname` in
-      (Darwin)        LIBTOOLIZE=glibtoolize  ;;
-      (*)             LIBTOOLIZE=libtoolize   ;;
+  (Darwin)  LIBTOOLIZE=glibtoolize  ;;
+  (*)       LIBTOOLIZE=libtoolize   ;;
 esac
 $LIBTOOLIZE --force --automake --copy
 
diff --git a/configure.bat b/configure.bat
index 1021514..b1101c0 100644
--- a/configure.bat
+++ b/configure.bat
@@ -5,15 +5,15 @@
 REM  The ASF licenses this file to You under the Apache License, Version 2.0
 REM  (the "License"); you may not use this file except in compliance with
 REM  the License.  You may obtain a copy of the License at
-REM 
+REM
 REM       http://www.apache.org/licenses/LICENSE-2.0
-REM 
+REM
 REM  Unless required by applicable law or agreed to in writing, software
 REM  distributed under the License is distributed on an "AS IS" BASIS,
 REM  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 REM  See the License for the specific language governing permissions and
 REM  limitations under the License.
-REM 
-REM 
+REM
+
 copy /Y src\main\include\log4cxx\log4cxx.hw src\main\include\log4cxx\log4cxx.h
 copy /Y src\main\include\log4cxx\private\log4cxx_private.hw src\main\include\log4cxx\private\log4cxx_private.h
diff --git a/release_perform.sh b/release_perform.sh
index 7a3df1b..ff83c0e 100755
--- a/release_perform.sh
+++ b/release_perform.sh
@@ -35,7 +35,7 @@
   # change the working dir. Making available seems easy using symlinks, but "mvn clean" deletes the
   # contents(!) of the linked dirs then. And always copying things around seems a bit unnecessary as
   # well, so I'm using a relocation of the folder for now. The downside is that "mvn clean" ignores
-  # that dir by default...
+  # that dir by default.
   WD_RELEASE="$( pwd)/../log4cxx-next_stable"
   WD_DIST_DEV="$(pwd)/../log4cxx-dist-dev"
 
@@ -56,6 +56,7 @@
 {
   mkdir -p "${WD_DIST_DEV}"
   pushd    "${WD_DIST_DEV}" > /dev/null
+
   if [ ! -d ".svn" ]
   then
     svn co "https://dist.apache.org/repos/dist/dev/logging/log4cxx" .
@@ -65,7 +66,7 @@
 
 function sign_and_copy
 {
-  # Might be a good idea to have another look at the GPG plugin for Maven in the future:
+  # Might be a good idea to have another look at the GPG-plugin for Maven in the future:
   #
   # http://blog.sonatype.com/2010/01/how-to-generate-pgp-signatures-with-maven/
   # http://maven.apache.org/plugins/maven-gpg-plugin/
@@ -78,12 +79,12 @@
     md5sum        "${file}" > "${file}.md5"
     sha512sum     "${file}" > "${file}.sha"
 
-    # No symlinks because those would be treated as is, no hardlinks because it should be safer for
+    # No symlinks because those would be treated as is, no hard-links because it should be safer for
     # commits.
-    cp  --force   "${file}"     "${WD_DIST_DEV}"
-    cp  --force   "${file}.asc" "${WD_DIST_DEV}"
-    cp  --force   "${file}.md5" "${WD_DIST_DEV}"
-    cp  --force   "${file}.sha" "${WD_DIST_DEV}"
+    cp --force "${file}"     "${WD_DIST_DEV}"
+    cp --force "${file}.asc" "${WD_DIST_DEV}"
+    cp --force "${file}.md5" "${WD_DIST_DEV}"
+    cp --force "${file}.sha" "${WD_DIST_DEV}"
   done
 }
 
diff --git a/release_prepare.sh b/release_prepare.sh
index faaeded..e2660d8 100755
--- a/release_prepare.sh
+++ b/release_prepare.sh
@@ -36,9 +36,9 @@
 # This script can be invoked with "next_stable" being the current branch already or with some other
 # and "next_stable" is checked out automatically. If it's invoked with some other branch, release
 # dates, new development version etc. are merged to the branch the script was invoked with. Without
-# another branch those changes need to be done/merged manually to wherever they need to be in the
+# another branch, those changes need to be done/merged manually to wherever they need to be in the
 # end, most likely "master". If only "master" should be supported in the future, merging back into
-# that might be hard coded, currently it isn't to support arbitrary source branches from which a
+# that might be hard-coded, currently it isn't to support arbitrary source branches from which a
 # release gets initiated. If "next_stable" is the starting branch, it's assumed to only create
 # another release based on a former release, without merging things back to anywhere.
 #
diff --git a/release_purge.sh b/release_purge.sh
index 1abfcc8..b6eeb2f 100755
--- a/release_purge.sh
+++ b/release_purge.sh
@@ -16,9 +16,9 @@
 #
 
 ##
-# Purge (some) releases during development of release scripts.
+# Purge (some) releases during development of release-scripts.
 #
-# This script is mainly used during development of the release scripts itself and simply deletes
+# This script is mainly used during development of the release-scripts themself and simply deletes
 # branches and tags created during tests of the release process. Be very careful with execution!
 #
 
@@ -32,7 +32,7 @@
 
 function purge_branch_and_tag
 {
-  git checkout  "release_scripts"
+  git checkout "release_scripts"
 
   git branch -D "next_stable"
   git push --delete "origin" "next_stable"
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 92d8b47..2113a81 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -106,6 +106,7 @@
 			<action issue="LOGCXX-262" type="fix">socketappendertestcase and xmlsocketappendertestcase not run</action>
 			<action issue="LOGCXX-249" type="fix">Console appender crashes if layout is not set</action>
 
+			<action type="add">JSONLayout (https://github.com/apache/logging-log4cxx/pull/13)</action>
 			<action type="update">Behavior of StringHelper::startsWith and endsWith synced</action>
 			<action type="update">Documented C (class) and M (method) log format keywords.</action>
 			<action type="add">Locationinfo for Borland C++ Builder and successors improved</action>
diff --git a/src/cmake/findAPR-Util.cmake b/src/cmake/FindAPR-Util.cmake
similarity index 100%
rename from src/cmake/findAPR-Util.cmake
rename to src/cmake/FindAPR-Util.cmake
diff --git a/src/cmake/findAPR.cmake b/src/cmake/FindAPR.cmake
similarity index 100%
rename from src/cmake/findAPR.cmake
rename to src/cmake/FindAPR.cmake
diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt
index 3571cf5..cdf3034 100644
--- a/src/main/cpp/CMakeLists.txt
+++ b/src/main/cpp/CMakeLists.txt
@@ -67,6 +67,7 @@
   inputstreamreader.cpp
   integer.cpp
   integerpatternconverter.cpp
+  jsonlayout.cpp
   layout.cpp
   level.cpp
   levelmatchfilter.cpp
diff --git a/src/main/cpp/Makefile.am b/src/main/cpp/Makefile.am
index 6da89cb..236a9a6 100644
--- a/src/main/cpp/Makefile.am
+++ b/src/main/cpp/Makefile.am
@@ -72,6 +72,7 @@
         inputstreamreader.cpp \
         integer.cpp \
         integerpatternconverter.cpp \
+        jsonlayout.cpp \
         layout.cpp\
         level.cpp \
         levelmatchfilter.cpp \
diff --git a/src/main/cpp/jsonlayout.cpp b/src/main/cpp/jsonlayout.cpp
new file mode 100644
index 0000000..a2e72c3
--- /dev/null
+++ b/src/main/cpp/jsonlayout.cpp
@@ -0,0 +1,389 @@
+/*
+ * 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.
+ */
+
+#include <log4cxx/logstring.h>
+#include <log4cxx/jsonlayout.h>
+#include <log4cxx/spi/loggingevent.h>
+#include <log4cxx/level.h>
+#include <log4cxx/helpers/optionconverter.h>
+#include <log4cxx/helpers/iso8601dateformat.h>
+#include <log4cxx/helpers/stringhelper.h>
+#include <log4cxx/helpers/transcoder.h>
+
+#include <apr_time.h>
+#include <apr_strings.h>
+#include <string.h>
+
+using namespace log4cxx;
+using namespace log4cxx::helpers;
+using namespace log4cxx::spi;
+
+IMPLEMENT_LOG4CXX_OBJECT(JSONLayout)
+
+
+JSONLayout::JSONLayout() :
+	locationInfo(false),
+	prettyPrint(false),
+	dateFormat(),
+	ppIndentL1(LOG4CXX_STR("  ")),
+	ppIndentL2(LOG4CXX_STR("    "))
+{
+}
+
+
+void JSONLayout::setOption(const LogString& option, const LogString& value)
+{
+	if (StringHelper::equalsIgnoreCase(option,
+			LOG4CXX_STR("LOCATIONINFO"), LOG4CXX_STR("locationinfo")))
+	{
+		setLocationInfo(OptionConverter::toBoolean(value, false));
+	}
+
+	if (StringHelper::equalsIgnoreCase(option,
+			LOG4CXX_STR("PRETTYPRINT"), LOG4CXX_STR("prettyprint")))
+	{
+		setPrettyPrint(OptionConverter::toBoolean(value, false));
+	}
+}
+void JSONLayout::format(LogString& output,
+	const spi::LoggingEventPtr& event,
+	Pool& p) const
+{
+	output.append(LOG4CXX_STR("{"));
+	output.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		output.append(ppIndentL1);
+	}
+
+	appendQuotedEscapedString(output, LOG4CXX_STR("timestamp"));
+	output.append(LOG4CXX_STR(": "));
+	LogString timestamp;
+	dateFormat.format(timestamp, event->getTimeStamp(), p);
+	appendQuotedEscapedString(output, timestamp);
+	output.append(LOG4CXX_STR(","));
+	output.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		output.append(ppIndentL1);
+	}
+
+	appendQuotedEscapedString(output, LOG4CXX_STR("level"));
+	output.append(LOG4CXX_STR(": "));
+	LogString level;
+	event->getLevel()->toString(level);
+	appendQuotedEscapedString(output, level);
+	output.append(LOG4CXX_STR(","));
+	output.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		output.append(ppIndentL1);
+	}
+
+	appendQuotedEscapedString(output, LOG4CXX_STR("logger"));
+	output.append(LOG4CXX_STR(": "));
+	appendQuotedEscapedString(output, event->getLoggerName());
+	output.append(LOG4CXX_STR(","));
+	output.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		output.append(ppIndentL1);
+	}
+
+	appendQuotedEscapedString(output, LOG4CXX_STR("message"));
+	output.append(LOG4CXX_STR(": "));
+	appendQuotedEscapedString(output, event->getMessage());
+
+	appendSerializedMDC(output, event);
+	appendSerializedNDC(output, event);
+
+	if (locationInfo)
+	{
+		output.append(LOG4CXX_STR(","));
+		output.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+		appendSerializedLocationInfo(output, event, p);
+	}
+
+	output.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+	output.append(LOG4CXX_STR("}"));
+	output.append(LOG4CXX_EOL);
+}
+
+void JSONLayout::appendQuotedEscapedString(LogString& buf,
+	const LogString& input) const
+{
+	/* add leading quote */
+	buf.push_back(0x22);
+
+	logchar specialChars[] =
+	{
+		0x08,   /* \b backspace         */
+		0x09,   /* \t tab               */
+		0x0a,   /* \n newline           */
+		0x0c,   /* \f form feed         */
+		0x0d,   /* \r carriage return   */
+		0x22,   /* \" double quote      */
+		0x5c    /* \\ backslash         */
+	};
+
+	size_t start = 0;
+	size_t found = input.find_first_of(specialChars, start);
+
+	while (found != LogString::npos)
+	{
+		if (found > start)
+		{
+			buf.append(input, start, found - start);
+		}
+
+		switch (input[found])
+		{
+			case 0x08:
+				/* \b backspace */
+				buf.push_back(0x5c);
+				buf.push_back('b');
+				break;
+
+			case 0x09:
+				/* \t tab */
+				buf.push_back(0x5c);
+				buf.push_back('t');
+				break;
+
+			case 0x0a:
+				/* \n newline */
+				buf.push_back(0x5c);
+				buf.push_back('n');
+				break;
+
+			case 0x0c:
+				/* \f form feed */
+				buf.push_back(0x5c);
+				buf.push_back('f');
+				break;
+
+			case 0x0d:
+				/* \r carriage return */
+				buf.push_back(0x5c);
+				buf.push_back('r');
+				break;
+
+			case 0x22:
+				/* \" double quote */
+				buf.push_back(0x5c);
+				buf.push_back(0x22);
+				break;
+
+			case 0x5c:
+				/* \\ backslash */
+				buf.push_back(0x5c);
+				buf.push_back(0x5c);
+				break;
+
+			default:
+				buf.push_back(input[found]);
+				break;
+		}
+
+		start = found + 1;
+
+		if (found < input.size())
+		{
+			found = input.find_first_of(specialChars, start);
+		}
+		else
+		{
+			found = LogString::npos;
+		}
+	}
+
+	if (start < input.size())
+	{
+		buf.append(input, start, input.size() - start);
+	}
+
+	/* add trailing quote */
+	buf.push_back(0x22);
+}
+
+void JSONLayout::appendSerializedMDC(LogString& buf,
+	const LoggingEventPtr& event) const
+{
+	LoggingEvent::KeySet keys = event->getMDCKeySet();
+
+	if (keys.empty())
+	{
+		return;
+	}
+
+	buf.append(LOG4CXX_STR(","));
+	buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL1);
+	}
+
+	appendQuotedEscapedString(buf, LOG4CXX_STR("context_map"));
+	buf.append(LOG4CXX_STR(": {"));
+	buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	for (LoggingEvent::KeySet::iterator it = keys.begin();
+		it != keys.end(); ++it)
+	{
+		if (prettyPrint)
+		{
+			buf.append(ppIndentL2);
+		}
+
+		appendQuotedEscapedString(buf, *it);
+		buf.append(LOG4CXX_STR(": "));
+		LogString value;
+		event->getMDC(*it, value);
+		appendQuotedEscapedString(buf, value);
+
+		/* if this isn't the last k:v pair, we need a comma */
+		if (it + 1 != keys.end())
+		{
+			buf.append(LOG4CXX_STR(","));
+			buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+		}
+		else
+		{
+			buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+		}
+	}
+
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL1);
+	}
+
+	buf.append(LOG4CXX_STR("}"));
+}
+
+void JSONLayout::appendSerializedNDC(LogString& buf,
+	const LoggingEventPtr& event) const
+{
+	LogString ndcVal;
+
+	if (!event->getNDC(ndcVal))
+	{
+		return;
+	}
+
+	buf.append(LOG4CXX_STR(","));
+	buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL1);
+	}
+
+	appendQuotedEscapedString(buf, LOG4CXX_STR("context_stack"));
+	buf.append(LOG4CXX_STR(": ["));
+	buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL2);
+	}
+
+	appendQuotedEscapedString(buf, ndcVal);
+	buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL1);
+	}
+
+	buf.append(LOG4CXX_STR("]"));
+}
+
+void JSONLayout::appendSerializedLocationInfo(LogString& buf,
+	const LoggingEventPtr& event, Pool& p) const
+{
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL1);
+	}
+
+	appendQuotedEscapedString(buf, LOG4CXX_STR("location_info"));
+	buf.append(LOG4CXX_STR(": {"));
+	buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+	const LocationInfo& locInfo = event->getLocationInformation();
+
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL2);
+	}
+
+	appendQuotedEscapedString(buf, LOG4CXX_STR("file"));
+	buf.append(LOG4CXX_STR(": "));
+	LOG4CXX_DECODE_CHAR(fileName, locInfo.getFileName());
+	appendQuotedEscapedString(buf, fileName);
+	buf.append(LOG4CXX_STR(","));
+	buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL2);
+	}
+
+	appendQuotedEscapedString(buf, LOG4CXX_STR("line"));
+	buf.append(LOG4CXX_STR(": "));
+	LogString lineNumber;
+	StringHelper::toString(locInfo.getLineNumber(), p, lineNumber);
+	appendQuotedEscapedString(buf, lineNumber);
+	buf.append(LOG4CXX_STR(","));
+	buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL2);
+	}
+
+	appendQuotedEscapedString(buf, LOG4CXX_STR("class"));
+	buf.append(LOG4CXX_STR(": "));
+	LOG4CXX_DECODE_CHAR(className, locInfo.getClassName());
+	appendQuotedEscapedString(buf, className);
+	buf.append(LOG4CXX_STR(","));
+	buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL2);
+	}
+
+	appendQuotedEscapedString(buf, LOG4CXX_STR("method"));
+	buf.append(LOG4CXX_STR(": "));
+	LOG4CXX_DECODE_CHAR(methodName, locInfo.getMethodName());
+	appendQuotedEscapedString(buf, methodName);
+	buf.append(prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
+
+	if (prettyPrint)
+	{
+		buf.append(ppIndentL1);
+	}
+
+	buf.append(LOG4CXX_STR("}"));
+}
+
diff --git a/src/main/include/log4cxx/Makefile.am b/src/main/include/log4cxx/Makefile.am
index 75ef01c..f629b45 100644
--- a/src/main/include/log4cxx/Makefile.am
+++ b/src/main/include/log4cxx/Makefile.am
@@ -35,6 +35,7 @@
     $(top_srcdir)/src/main/include/log4cxx/file.h \
     $(top_srcdir)/src/main/include/log4cxx/hierarchy.h \
     $(top_srcdir)/src/main/include/log4cxx/htmllayout.h \
+    $(top_srcdir)/src/main/include/log4cxx/jsonlayout.h \
     $(top_srcdir)/src/main/include/log4cxx/layout.h \
     $(top_srcdir)/src/main/include/log4cxx/level.h \
     $(top_srcdir)/src/main/include/log4cxx/logger.h \
diff --git a/src/main/include/log4cxx/jsonlayout.h b/src/main/include/log4cxx/jsonlayout.h
new file mode 100644
index 0000000..dd997d1
--- /dev/null
+++ b/src/main/include/log4cxx/jsonlayout.h
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOG4CXX_JSON_LAYOUT_H
+#define _LOG4CXX_JSON_LAYOUT_H
+
+#include <log4cxx/layout.h>
+#include <log4cxx/helpers/iso8601dateformat.h>
+#include <log4cxx/spi/loggingevent.h>
+
+
+
+namespace log4cxx
+{
+/**
+This layout outputs events in a JSON dictionary.
+*/
+class LOG4CXX_EXPORT JSONLayout : public Layout
+{
+	private:
+		// Print no location info by default
+		bool locationInfo; //= false
+		bool prettyPrint; //= false
+
+		helpers::ISO8601DateFormat dateFormat;
+
+	protected:
+
+		LogString ppIndentL1;
+		LogString ppIndentL2;
+
+		void appendQuotedEscapedString(LogString& buf, const LogString& input) const;
+		void appendSerializedMDC(LogString& buf,
+			const spi::LoggingEventPtr& event) const;
+		void appendSerializedNDC(LogString& buf,
+			const spi::LoggingEventPtr& event) const;
+		void appendSerializedLocationInfo(LogString& buf,
+			const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& p) const;
+
+	public:
+		DECLARE_LOG4CXX_OBJECT(JSONLayout)
+		BEGIN_LOG4CXX_CAST_MAP()
+		LOG4CXX_CAST_ENTRY(JSONLayout)
+		LOG4CXX_CAST_ENTRY_CHAIN(Layout)
+		END_LOG4CXX_CAST_MAP()
+
+		JSONLayout();
+
+		/**
+		The <b>LocationInfo</b> option takes a boolean value. By
+		default, it is set to false which means there will be no location
+		information output by this layout. If the the option is set to
+		true, then the file name and line number of the statement
+		at the origin of the log statement will be output.
+		*/
+		inline void setLocationInfo(bool locationInfoFlag)
+		{
+			this->locationInfo = locationInfoFlag;
+		}
+
+
+		/**
+		Returns the current value of the <b>LocationInfo</b> option.
+		*/
+		inline bool getLocationInfo() const
+		{
+			return locationInfo;
+		}
+
+		/**
+		The <b>PrettyPrint</b> option takes a boolean value. By
+		default, it is set to false which means output by this layout will
+		be one line per log event.  If the option is set to true, then
+		then each log event will produce multiple lines, each indented
+		for readability.
+		*/
+		inline void setPrettyPrint(bool prettyPrintFlag)
+		{
+			this->prettyPrint = prettyPrintFlag;
+		}
+
+		/**
+		Returns the current value of the <b>PrettyPrint</b> option.
+		*/
+		inline bool getPrettyPrint() const
+		{
+			return prettyPrint;
+		}
+
+
+		/**
+		Returns the content type output by this layout, i.e "application/json".
+		*/
+		virtual LogString getContentType() const
+		{
+			return LOG4CXX_STR("application/json");
+		}
+
+		/**
+		No options to activate.
+		*/
+		virtual void activateOptions(log4cxx::helpers::Pool& /* p */) {}
+
+		/**
+		Set options
+		*/
+		virtual void setOption(const LogString& option, const LogString& value);
+
+		virtual void format(LogString& output,
+			const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& pool) const;
+
+		/**
+		The JSON layout handles the throwable contained in logging
+		events. Hence, this method return <code>false</code>.  */
+		virtual bool ignoresThrowable() const
+		{
+			return false;
+		}
+
+}; // class JSONLayout
+LOG4CXX_PTR_DEF(JSONLayout);
+}  // namespace log4cxx
+
+
+#endif // _LOG4CXX_JSON_LAYOUT_H
diff --git a/src/test/cpp/CMakeLists.txt b/src/test/cpp/CMakeLists.txt
index 1f632d9..1c359fb 100644
--- a/src/test/cpp/CMakeLists.txt
+++ b/src/test/cpp/CMakeLists.txt
@@ -14,6 +14,7 @@
     filetestcase
     hierarchytest
     hierarchythresholdtestcase
+    jsonlayouttest
     l7dtestcase
     leveltestcase
     loggertestcase
diff --git a/src/test/cpp/Makefile.am b/src/test/cpp/Makefile.am
index 13b82ac..8b6c95d 100644
--- a/src/test/cpp/Makefile.am
+++ b/src/test/cpp/Makefile.am
@@ -168,6 +168,7 @@
     filetestcase.cpp \
     hierarchytest.cpp \
     hierarchythresholdtestcase.cpp \
+    jsonlayouttest.cpp \
     l7dtestcase.cpp \
     leveltestcase.cpp \
     logunit.cpp \
diff --git a/src/test/cpp/jsonlayouttest.cpp b/src/test/cpp/jsonlayouttest.cpp
new file mode 100644
index 0000000..de1d074
--- /dev/null
+++ b/src/test/cpp/jsonlayouttest.cpp
@@ -0,0 +1,481 @@
+/*
+ * 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.
+ */
+
+#include "logunit.h"
+#include <log4cxx/logger.h>
+#include <log4cxx/jsonlayout.h>
+#include <log4cxx/ndc.h>
+#include <log4cxx/mdc.h>
+
+#include <iostream>
+#include <log4cxx/helpers/stringhelper.h>
+
+
+using namespace log4cxx;
+using namespace log4cxx::helpers;
+using namespace log4cxx::spi;
+
+#if defined(__LOG4CXX_FUNC__)
+	#undef __LOG4CXX_FUNC__
+	#define __LOG4CXX_FUNC__ "X::X()"
+#else
+	#error __LOG4CXX_FUNC__ expected to be defined
+#endif
+/**
+ * Test for JSONLayout.
+ *
+ */
+LOGUNIT_CLASS(JSONLayoutTest), public JSONLayout
+{
+	LOGUNIT_TEST_SUITE(JSONLayoutTest);
+	LOGUNIT_TEST(testGetContentType);
+	LOGUNIT_TEST(testIgnoresThrowable);
+	LOGUNIT_TEST(testAppendQuotedEscapedStringWithPrintableChars);
+	LOGUNIT_TEST(testAppendQuotedEscapedStringWithControlChars);
+	LOGUNIT_TEST(testAppendSerializedMDC);
+	LOGUNIT_TEST(testAppendSerializedMDCWithPrettyPrint);
+	LOGUNIT_TEST(testAppendSerializedNDC);
+	LOGUNIT_TEST(testAppendSerializedNDCWithPrettyPrint);
+	LOGUNIT_TEST(testAppendSerializedLocationInfo);
+	LOGUNIT_TEST(testAppendSerializedLocationInfoWithPrettyPrint);
+	LOGUNIT_TEST(testFormat);
+	LOGUNIT_TEST(testFormatWithPrettyPrint);
+	LOGUNIT_TEST(testGetSetLocationInfo);
+	LOGUNIT_TEST_SUITE_END();
+
+
+public:
+	/**
+	 * Clear MDC and NDC before test.
+	 */
+	void setUp()
+	{
+		NDC::clear();
+		MDC::clear();
+	}
+
+	/**
+	 * Clear MDC and NDC after test.
+	 */
+	void tearDown()
+	{
+		setUp();
+	}
+
+
+public:
+	/**
+	 * Tests getContentType.
+	 */
+	void testGetContentType()
+	{
+		LogString expected(LOG4CXX_STR("application/json"));
+		LogString actual(JSONLayout().getContentType());
+		LOGUNIT_ASSERT(expected == actual);
+	}
+
+	/**
+	 * Tests ignoresThrowable.
+	 */
+	void testIgnoresThrowable()
+	{
+		LOGUNIT_ASSERT_EQUAL(false, JSONLayout().ignoresThrowable());
+	}
+
+	/**
+	 * Tests appendQuotedEscapedString with printable characters.
+	 */
+	void testAppendQuotedEscapedStringWithPrintableChars()
+	{
+		LogString s1(LOG4CXX_STR("foo"));	/*  foo */
+		LogString s2;
+		appendQuotedEscapedString(s2, s1);	/*  "foo"  */
+		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("\"foo\""), s2);
+
+		LogString s3;
+		appendQuotedEscapedString(s3, s2);	/*  "\"foo\""  */
+		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("\"\\\"foo\\\"\""), s3);
+
+		LogString t1(LOG4CXX_STR("bar\"baz"));	/*  bar"baz */
+		LogString t2;
+		appendQuotedEscapedString(t2, t1);		/*  "bar\"baz"  */
+		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("\"bar\\\"baz\""), t2);
+
+		LogString t3;
+		appendQuotedEscapedString(t3, t2);		/*  "\"bar\\\"baz\""    */
+		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("\"\\\"bar\\\\\\\"baz\\\"\""), t3);
+	}
+
+	/**
+	 * Tests appendQuotedEscapedString with control characters.
+	 */
+	void testAppendQuotedEscapedStringWithControlChars()
+	{
+		logchar bs[] = {0x08, 0x00};
+		logchar bs_expected[] = {0x22, 0x5c, 'b', 0x22, 0x00};      /* "\b" */
+		LogString bs_escaped;
+
+		appendQuotedEscapedString(bs_escaped, bs);
+		LOGUNIT_ASSERT_EQUAL(bs_expected, bs_escaped);
+
+		logchar tab[] = {0x09, 0x00};
+		logchar tab_expected[] = {0x22, 0x5c, 't', 0x22, 0x00};     /* "\t" */
+		LogString tab_escaped;
+
+		appendQuotedEscapedString(tab_escaped, tab);
+		LOGUNIT_ASSERT_EQUAL(tab_expected, tab_escaped);
+
+		logchar newline[] = {0x0a, 0x00};
+		logchar newline_expected[] = {0x22, 0x5c, 'n', 0x22, 0x00}; /* "\n" */
+		LogString newline_escaped;
+
+		appendQuotedEscapedString(newline_escaped, newline);
+		LOGUNIT_ASSERT_EQUAL(newline_expected, newline_escaped);
+
+		logchar ff[] = {0x0c, 0x00};
+		logchar ff_expected[] = {0x22, 0x5c, 'f', 0x22, 0x00};      /* "\f" */
+		LogString ff_escaped;
+
+		appendQuotedEscapedString(ff_escaped, ff);
+		LOGUNIT_ASSERT_EQUAL(ff_expected, ff_escaped);
+
+		logchar cr[] = {0x0d, 0x00};
+		logchar cr_expected[] = {0x22, 0x5c, 'r', 0x22, 0x00};      /* "\r" */
+		LogString cr_escaped;
+
+		appendQuotedEscapedString(cr_escaped, cr);
+		LOGUNIT_ASSERT_EQUAL(cr_expected, cr_escaped);
+	}
+
+	/**
+	 * Tests appendSerializedMDC.
+	 */
+	void testAppendSerializedMDC()
+	{
+		LoggingEventPtr event1 = new LoggingEvent(LOG4CXX_STR("Logger"),
+			Level::getInfo(),
+			LOG4CXX_STR("A message goes here."),
+			LOG4CXX_LOCATION);
+
+		MDC::put("key1", "value1");
+		MDC::put("key2", "value2");
+
+		LogString output1;
+		LogString expected1 = LOG4CXX_STR(", \"context_map\": { "
+			"\"key1\": \"value1\", \"key2\": \"value2\" }");
+
+		appendSerializedMDC(output1, event1);
+		LOGUNIT_ASSERT_EQUAL(expected1, output1);
+	}
+
+	/**
+	 * Tests appendSerializedMDC with prettyPrint set to true.
+	 */
+	void testAppendSerializedMDCWithPrettyPrint()
+	{
+		LoggingEventPtr event1 = new LoggingEvent(LOG4CXX_STR("Logger"),
+			Level::getInfo(),
+			LOG4CXX_STR("A message goes here."),
+			LOG4CXX_LOCATION);
+
+		MDC::put("key1", "value1");
+		MDC::put("key2", "value2");
+
+		LogString output1;
+		LogString expected1;
+
+		expected1
+			.append(LOG4CXX_STR(","))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL1)
+			.append(LOG4CXX_STR("\"context_map\": {"))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL2)
+			.append(LOG4CXX_STR("\"key1\": \"value1\","))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL2)
+			.append(LOG4CXX_STR("\"key2\": \"value2\""))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL1)
+			.append(LOG4CXX_STR("}"));
+
+		setPrettyPrint(true);
+		appendSerializedMDC(output1, event1);
+
+		LOGUNIT_ASSERT_EQUAL(expected1, output1);
+	}
+
+	/**
+	 * Tests appendSerializedNDC.
+	 */
+	void testAppendSerializedNDC()
+	{
+		LoggingEventPtr event1 = new LoggingEvent(LOG4CXX_STR("Logger"),
+			Level::getInfo(),
+			LOG4CXX_STR("A message goes here."),
+			LOG4CXX_LOCATION);
+
+		NDC::push("one");
+		NDC::push("two");
+		NDC::push("three");
+
+		LogString output1;
+		LogString expected1 = LOG4CXX_STR(", \"context_stack\": [ \"one two three\" ]");
+
+		appendSerializedNDC(output1, event1);
+		LOGUNIT_ASSERT_EQUAL(expected1, output1);
+	}
+
+	/**
+	 * Tests appendSerializedNDC with prettyPrint set to true.
+	 */
+	void testAppendSerializedNDCWithPrettyPrint()
+	{
+		LoggingEventPtr event1 = new LoggingEvent(LOG4CXX_STR("Logger"),
+			Level::getInfo(),
+			LOG4CXX_STR("A message goes here."),
+			LOG4CXX_LOCATION);
+
+		NDC::push("one");
+		NDC::push("two");
+		NDC::push("three");
+
+		LogString output1;
+		LogString expected1;
+
+		expected1
+			.append(LOG4CXX_STR(","))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL1)
+			.append(LOG4CXX_STR("\"context_stack\": ["))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL2)
+			.append(LOG4CXX_STR("\"one two three\""))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL1)
+			.append(LOG4CXX_STR("]"));
+
+		setPrettyPrint(true);
+		appendSerializedNDC(output1, event1);
+
+		LOGUNIT_ASSERT_EQUAL(expected1, output1);
+	}
+
+	/**
+	 * Tests appendSerializedLocationInfo.
+	 */
+	void testAppendSerializedLocationInfo()
+	{
+		Pool p;
+
+		LoggingEventPtr event1 = new LoggingEvent(LOG4CXX_STR("Logger"),
+			Level::getInfo(),
+			LOG4CXX_STR("A message goes here."),
+			spi::LocationInfo("FooFile", "BarFunc", 42));
+
+		LogString output1;
+		LogString expected1;
+
+		expected1
+			.append(LOG4CXX_STR("\"location_info\": { "))
+			.append(LOG4CXX_STR("\"file\": \"FooFile\", "))
+			.append(LOG4CXX_STR("\"line\": \"42\", "))
+			.append(LOG4CXX_STR("\"class\": \"\", "))
+			.append(LOG4CXX_STR("\"method\": \"BarFunc\" }"));
+
+		appendSerializedLocationInfo(output1, event1, p);
+		LOGUNIT_ASSERT_EQUAL(expected1, output1);
+	}
+
+	/**
+	 * Tests appendSerializedLocationInfo with prettyPrint set to true.
+	 */
+	void testAppendSerializedLocationInfoWithPrettyPrint()
+	{
+		Pool p;
+
+		LoggingEventPtr event1 = new LoggingEvent(LOG4CXX_STR("Logger"),
+			Level::getInfo(),
+			LOG4CXX_STR("A message goes here."),
+			spi::LocationInfo("FooFile", "BarFunc", 42));
+
+		LogString output1;
+		LogString expected1;
+
+		expected1
+			.append(ppIndentL1)
+			.append(LOG4CXX_STR("\"location_info\": {"))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL2)
+			.append(LOG4CXX_STR("\"file\": \"FooFile\","))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL2)
+			.append(LOG4CXX_STR("\"line\": \"42\","))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL2)
+			.append(LOG4CXX_STR("\"class\": \"\","))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL2)
+			.append(LOG4CXX_STR("\"method\": \"BarFunc\""))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL1)
+			.append(LOG4CXX_STR("}"));
+
+		setPrettyPrint(true);
+		appendSerializedLocationInfo(output1, event1, p);
+
+		LOGUNIT_ASSERT_EQUAL(expected1, output1);
+	}
+
+	/**
+	 * Tests format.
+	 */
+	void testFormat()
+	{
+		Pool p;
+
+		LoggingEventPtr event1 = new LoggingEvent(LOG4CXX_STR("Logger"),
+			Level::getInfo(),
+			LOG4CXX_STR("A message goes here."),
+			spi::LocationInfo("FooFile", "BarFunc", 42));
+
+		LogString timestamp;
+		helpers::ISO8601DateFormat dateFormat;
+		dateFormat.format(timestamp, event1->getTimeStamp(), p);
+
+		NDC::push("one");
+		NDC::push("two");
+		NDC::push("three");
+
+		MDC::put("key1", "value1");
+		MDC::put("key2", "value2");
+
+		LogString output1;
+		LogString expected1;
+
+		expected1
+			.append(LOG4CXX_STR("{ \"timestamp\": \""))
+			.append(timestamp)
+			.append(LOG4CXX_STR("\", "))
+			.append(LOG4CXX_STR("\"level\": \"INFO\", "))
+			.append(LOG4CXX_STR("\"logger\": \"Logger\", "))
+			.append(LOG4CXX_STR("\"message\": \"A message goes here.\""));
+
+		setLocationInfo(true);
+
+		appendSerializedMDC(expected1, event1);
+		appendSerializedNDC(expected1, event1);
+		expected1.append(LOG4CXX_STR(", "));
+		appendSerializedLocationInfo(expected1, event1, p);
+
+		expected1.append(LOG4CXX_STR(" }"));
+		expected1.append(LOG4CXX_EOL);
+		format(output1, event1, p);
+
+		LOGUNIT_ASSERT_EQUAL(expected1, output1);
+	}
+
+	/**
+	 * Tests format with PrettyPrint set to true.
+	 */
+	void testFormatWithPrettyPrint()
+	{
+		Pool p;
+
+		LoggingEventPtr event1 = new LoggingEvent(LOG4CXX_STR("Logger"),
+			Level::getInfo(),
+			LOG4CXX_STR("A message goes here."),
+			spi::LocationInfo("FooFile", "BarFunc", 42));
+
+		LogString timestamp;
+		helpers::ISO8601DateFormat dateFormat;
+		dateFormat.format(timestamp, event1->getTimeStamp(), p);
+
+		NDC::push("one");
+		NDC::push("two");
+		NDC::push("three");
+
+		MDC::put("key1", "value1");
+		MDC::put("key2", "value2");
+
+		LogString output1;
+		LogString expected1;
+
+		expected1
+			.append(LOG4CXX_STR("{"))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL1)
+			.append(LOG4CXX_STR("\"timestamp\": \""))
+			.append(timestamp)
+			.append(LOG4CXX_STR("\","))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL1)
+			.append(LOG4CXX_STR("\"level\": \"INFO\","))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL1)
+			.append(LOG4CXX_STR("\"logger\": \"Logger\","))
+			.append(LOG4CXX_EOL)
+			.append(ppIndentL1)
+			.append(LOG4CXX_STR("\"message\": \"A message goes here.\""));
+
+		setPrettyPrint(true);
+		setLocationInfo(true);
+
+		appendSerializedMDC(expected1, event1);
+		appendSerializedNDC(expected1, event1);
+		expected1.append(LOG4CXX_STR(","));
+		expected1.append(LOG4CXX_EOL);
+		appendSerializedLocationInfo(expected1, event1, p);
+
+		expected1.append(LOG4CXX_EOL);
+		expected1.append(LOG4CXX_STR("}"));
+		expected1.append(LOG4CXX_EOL);
+		format(output1, event1, p);
+
+		LOGUNIT_ASSERT_EQUAL(expected1, output1);
+	}
+
+	/**
+	 * Tests getLocationInfo and setLocationInfo.
+	 */
+	void testGetSetLocationInfo()
+	{
+		JSONLayout layout;
+		LOGUNIT_ASSERT_EQUAL(false, layout.getLocationInfo());
+		layout.setLocationInfo(true);
+		LOGUNIT_ASSERT_EQUAL(true, layout.getLocationInfo());
+		layout.setLocationInfo(false);
+		LOGUNIT_ASSERT_EQUAL(false, layout.getLocationInfo());
+	}
+
+	/**
+	 * Tests getPrettyPrint and setPrettyPrint.
+	 */
+	void testGetSetPrettyPrint()
+	{
+		JSONLayout layout;
+		LOGUNIT_ASSERT_EQUAL(false, layout.getPrettyPrint());
+		layout.setPrettyPrint(true);
+		LOGUNIT_ASSERT_EQUAL(true, layout.getPrettyPrint());
+		layout.setPrettyPrint(false);
+		LOGUNIT_ASSERT_EQUAL(false, layout.getPrettyPrint());
+	}
+};
+
+
+LOGUNIT_TEST_SUITE_REGISTRATION(JSONLayoutTest);
+