First version

git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers@943816 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/log4j12-api/LICENSE b/log4j12-api/LICENSE
new file mode 100644
index 0000000..6279e52
--- /dev/null
+++ b/log4j12-api/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 1999-2005 The Apache Software Foundation
+
+   Licensed 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.
diff --git a/log4j12-api/NOTICE b/log4j12-api/NOTICE
new file mode 100644
index 0000000..6233b56
--- /dev/null
+++ b/log4j12-api/NOTICE
@@ -0,0 +1,5 @@
+Apache log4j Enhanced PatternLayout for log4j 1.2.x
+Copyright 2007 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
diff --git a/log4j12-api/pom.xml b/log4j12-api/pom.xml
new file mode 100644
index 0000000..adf0fdc
--- /dev/null
+++ b/log4j12-api/pom.xml
@@ -0,0 +1,48 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.logging</groupId>
+    <artifactId>log4j2</artifactId>
+    <version>1.99.0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.apache.logging</groupId>
+  <artifactId>log4j12-api</artifactId>
+  <packaging>jar</packaging>
+  <name>Log4J Compatibility API</name>
+  <description>The Log4J Compatibility API</description>
+</build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.3.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+ <distributionManagement>
+    <site>
+      <id>apache.website</id>
+      <url>scp://people.apache.org/home/carnold/public_html/log4j/companions/pattern-layout</url>
+    </site>
+  </distributionManagement>
+
+</project>
+
diff --git a/log4j2-api/pom.xml b/log4j2-api/pom.xml
new file mode 100644
index 0000000..f152033
--- /dev/null
+++ b/log4j2-api/pom.xml
@@ -0,0 +1,47 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.logging</groupId>
+    <artifactId>log4j2</artifactId>
+    <version>1.99.0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.apache.logging</groupId>
+  <artifactId>log4j2-api</artifactId>
+  <packaging>jar</packaging>
+  <name>Log4J API</name>
+  <description>The Log4J API</description>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.3.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+ <distributionManagement>
+    <site>
+      <id>apache.website</id>
+      <url>scp://people.apache.org/home/carnold/public_html/log4j/companions/pattern-layout</url>
+    </site>
+  </distributionManagement>
+
+</project>
+
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/Level.java b/log4j2-api/src/main/java/org/apache/logging/log4j/Level.java
new file mode 100644
index 0000000..c8e076e
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/Level.java
@@ -0,0 +1,105 @@
+/*
+ * 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;
+
+/**
+ * Levels used for identifying the severity of an event. Levels are organized from most specific to least:<br>
+ * OFF<br>
+ * FATAL<br>
+ * ERROR<br>
+ * WARN<br>
+ * INFO<br>
+ * DEBUG<br>
+ * TRACE<br>
+ *
+ * Typically, configuring a level in a filter or on a logger will cause logging events of that level and those
+ * that are more specific to pass through the filter.
+ * A special level, ALL, is guaranteed to capture all levels when used in logging configurations.
+ */
+public enum Level {
+    OFF(0), FATAL(1), ERROR(2), WARN(3), INFO(4), DEBUG(5), TRACE(6), ALL(Integer.MAX_VALUE);
+
+    private final int intLevel;
+
+    private Level(int val) {
+        intLevel = val;
+    }
+
+    /**
+     * Convert the string passed as argument to a level. If the
+     * conversion fails, then this method returns {@link #DEBUG}.
+     *
+     * @return the Level associate with the String.
+     */
+    public static Level toLevel(String sArg) {
+        return toLevel(sArg, DEBUG);
+    }
+
+    /**
+     * Convert the string passed as argument to a level. If the
+     * conversion fails, then this method returns the value of
+     * <code>defaultLevel</code>.
+     */
+    public static Level toLevel(String sArg, Level defaultLevel) {
+        if (sArg == null) {
+            return defaultLevel;
+        }
+
+        Level level = valueOf(sArg);
+        return (level == null) ? defaultLevel : level;
+    }
+
+    /**
+     * Compares the specified Level against this one.
+     * @param level The level to check.
+     * @return True if the passed Level is more general or the same as this Level.
+     */
+    public boolean greaterOrEqual(Level level) {
+        return (intLevel <= level.intLevel);
+    }
+
+    /**
+     * Compares the specified Level against this one.
+     * @param level The level to check.
+     * @return True if the passed Level is more general or the same as this Level.
+     */
+    public boolean greaterOrEqual(int level) {
+        return (intLevel <= level);
+    }
+
+    /**
+     * Compares the specified Level against this one.
+     * @param level The level to check.
+     * @return True if the passed Level is more specific or the same as this Level.
+     */
+    public boolean lessOrEqual(Level level) {
+        return (intLevel <= level.intLevel);
+    }
+
+    /**
+     * Compares the specified Level against this one.
+     * @param level The level to check.
+     * @return True if the passed Level is more specific or the same as this Level.
+     */
+    public boolean lessOrEqual(int level) {
+        return (intLevel <= level);
+    }
+
+    public int intLevel() {
+        return intLevel;
+    }
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/LogManager.java b/log4j2-api/src/main/java/org/apache/logging/log4j/LogManager.java
new file mode 100644
index 0000000..8eb6ad5
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/LogManager.java
@@ -0,0 +1,123 @@
+package org.apache.logging.log4j;
+
+import org.apache.logging.log4j.internal.StatusLogger;
+import org.apache.logging.log4j.spi.LoggerContext;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * The anchor point for the logging system.
+ */
+public final class LogManager {
+
+    private static final String LOGGER_RESOURCE = "META-INF/log4j-provider.xml";
+    private static final String LOG_MANAGER_CLASS = "LoggerContextClass";
+    private static final String API_VERSION = "Log4jAPIVersion";
+    private static final String[] COMPATIBLE_API_VERSIONS = {
+        "1.99.0"
+    };
+
+    private static LoggerContext manager;
+
+    private static Logger logger = StatusLogger.getLogger();
+
+    /**
+     * Prevent instantiation
+     */
+    private LogManager() {
+    }
+
+
+    /**
+     * Scans the classpath to find all logging implementation. Currently, only one will
+     * be used but this could be extended to allow multiple implementations to be used.
+     */
+    static {
+        ClassLoader cl = findClassLoader();
+        List<LoggerContext> managers = new ArrayList<LoggerContext>();
+
+        Enumeration enumResources = null;
+        try {
+            enumResources = cl.getResources(LOGGER_RESOURCE);
+        }
+        catch (IOException e) {
+            logger.fatal("Unable to locate " + LOGGER_RESOURCE, e);
+        }
+
+        if (enumResources != null) {
+            while (enumResources.hasMoreElements()) {
+                Properties props = new Properties();
+                URL url = (URL) enumResources.nextElement();
+                try {
+                    props.loadFromXML(url.openStream());
+                } catch (IOException ioe) {
+                    logger.error("Unable to read " + url.toString(), ioe);
+                }
+                if (!validVersion(props.getProperty(API_VERSION))) {
+                    continue;
+                }
+                String className = props.getProperty(LOG_MANAGER_CLASS);
+                if (className != null) {
+                    try {
+                        Class clazz = Class.forName(className);
+                        managers.add((LoggerContext) clazz.newInstance());
+                    } catch (ClassNotFoundException cnfe) {
+                        logger.error("Unable to locate class " + className + " specified in " + url.toString(), cnfe);
+                    } catch (InstantiationException ie) {
+                        logger.error("Unable to create class " + className + " specified in " + url.toString(), ie);
+                    } catch (IllegalAccessException iae) {
+                        logger.error("Unable to create class " + className + " specified in " + url.toString(), iae);
+                    } catch (Exception e) {
+                        logger.error("Unable to create class " + className + " specified in " + url.toString(), e);
+                        e.printStackTrace();
+                    }
+                }
+            }
+            if (managers.size() != 1) {
+                logger.fatal("Unable to locate a logging implementation");
+            } else {
+                manager = managers.get(0);
+            }
+        } else {
+            logger.fatal("Unable to locate a logging implementation");
+        }
+    }
+
+    /**
+     * Return a Logger with the specified name.
+     *
+     * @param name The logger name.
+     * @return The Logger.
+     */
+    public static Logger getLogger(String name) {
+        return manager.getLogger(name);
+    }
+
+    public static LoggerContext getContext() {
+        return manager;
+    }
+
+    private static ClassLoader findClassLoader() {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            cl = LogManager.class.getClassLoader();
+        }
+
+        return cl;
+    }
+
+    private static boolean validVersion(String version) {
+        for (String v : COMPATIBLE_API_VERSIONS) {
+            if (version.startsWith(v)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/Logger.java b/log4j2-api/src/main/java/org/apache/logging/log4j/Logger.java
new file mode 100644
index 0000000..5b52382
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/Logger.java
@@ -0,0 +1,612 @@
+/*
+* 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;
+
+import org.apache.logging.log4j.message.Message;
+
+/**
+ * This is the central class in the log4j package. Most logging
+ * operations, except configuration, are done through this class.
+ */
+public interface Logger {
+
+  static Marker FLOW_MARKER = Marker.getMarker("FLOW");
+  static Marker ENTRY_MARKER = Marker.getMarker("ENTRY", FLOW_MARKER);
+  static Marker EXIT_MARKER = Marker.getMarker("EXIT", FLOW_MARKER);
+
+  static Marker EXCEPTION_MARKER = Marker.getMarker("EXCEPTION");
+  static Marker THROWING_MARKER = Marker.getMarker("THROWING", EXCEPTION_MARKER);
+  static Marker CATCHING_MARKER = Marker.getMarker("CATCHING", EXCEPTION_MARKER);
+
+  /**
+   * Log entry to a method.
+   * @param params The parameters to the method.
+   */
+  void entry(Object... params);
+
+  /**
+   * Log exit from a method.
+   */
+  void exit();
+
+  /**
+   * Log exiting from a method with the result.
+   * @param result The result being returned from the method call.
+   */
+  void exit(Object result);
+
+  /**
+   * Log an exception or error to be thrown.
+   * @param t The Throwable.
+   */
+  void throwing(Throwable t);
+
+  /**
+   * Log an exception or error to be thrown.
+   * @param level The logging Level.
+   * @param t The Throwable.
+   */
+  void throwing(Level level, Throwable t);
+
+  /**
+   * Log an exception or error that has been caught.
+   * @param t The Throwable.
+   */
+  void catching(Throwable t);
+
+  /**
+   * Log an exception or error that has been caught.
+   * @param level The logging Level.
+   * @param t The Throwable.
+   */
+  void catching(Level level, Throwable t);
+
+  /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#TRACE TRACE} level.
+   *
+   * @param message the message object to log.
+   */
+  void trace(String message);
+
+  /**
+   * Log a message at the <code>TRACE</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   * <p/>
+   * <p>
+   * See {@link #debug(String)} form for more detailed information.
+   * </p>
+   *
+   * @param message the message object to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void trace(String message, Throwable t);
+
+  /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#TRACE TRACE} level.
+   *
+   * @param message the message object to log.
+   */
+  void trace(Object message);
+
+  /**
+   * Log a message at the <code>TRACE</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   * <p/>
+   * <p>
+   * See {@link #debug(String)} form for more detailed information.
+   * </p>
+   *
+   * @param message the message object to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void trace(Object message, Throwable t);
+
+  /**
+   * Log a message with parameters at the <code>TRACE</code> level.
+   * @param message the message to log.
+   * @param params parameters to the message.
+   */
+  void trace(String message, Object... params);
+
+  /**
+   * Check whether this Logger is enabled for the TRACE  Level.
+   *
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         TRACE, <code>false</code> otherwise.
+   */
+  boolean isTraceEnabled();
+
+  /**
+   * Check whether this Logger is enabled for the TRACE  Level.
+   *
+   * @param marker The marker data specific to this log statement.
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         TRACE, <code>false</code> otherwise.
+   */
+  boolean isTraceEnabled(Marker marker);
+
+  /**
+   * Log a message with the specific Marker at the TRACE level.
+   *
+   * @param msg the message string to be logged
+   */
+  void trace(Message msg);
+
+  /**
+   * Log a message with the specific Marker at the TRACE level.
+   *
+   * @param msg the message string to be logged
+   * @param t   A Throwable or null.
+   */
+  void trace(Message msg, Throwable t);
+
+  /**
+   * Log a message with the specific Marker at the TRACE level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   */
+  void trace(Marker marker, Message msg);
+
+  /**
+   * Log a message with the specific Marker at the TRACE level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   * @param t      A Throwable or null.
+   */
+  void trace(Marker marker, Message msg, Throwable t);
+
+  /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#DEBUG DEBUG} level.
+   *
+   * @param message the message object to log.
+   */
+  void debug(String message);
+
+  /**
+   * Log a message at the <code>DEBUG</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   *
+   * @param message the message to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void debug(String message, Throwable t);
+
+  /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#DEBUG DEBUG} level.
+   *
+   * @param message the message object to log.
+   */
+  void debug(Object message);
+
+  /**
+   * Log a message at the <code>DEBUG</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   *
+   * @param message the message to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void debug(Object message, Throwable t);
+
+  /**
+   * Log a message with parameters at the <code>DEBUG</code> level.
+   * @param message the message to log.
+   * @param params parameters to the message.
+   */
+  void debug(String message, Object... params);
+
+  /**
+   * Check whether this Logger is enabled for the DEBUG Level.
+   *
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         DEBUG, <code>false</code> otherwise.
+   */
+  boolean isDebugEnabled();
+
+  /**
+   * Check whether this Logger is enabled for the DEBUG Level.
+   *
+   * @param marker The marker data specific to this log statement.
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         DEBUG, <code>false</code> otherwise.
+   */
+  boolean isDebugEnabled(Marker marker);
+
+  /**
+   * Log a message with the specific Marker at the DEBUG level.
+   *
+   * @param msg the message string to be logged
+   */
+  void debug(Message msg);
+
+  /**
+   * Log a message with the specific Marker at the DEBUG level.
+   *
+   * @param msg the message string to be logged
+   * @param t   A Throwable or null.
+   */
+  void debug(Message msg, Throwable t);
+
+  /**
+   * Log a message with the specific Marker at the DEBUG level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   */
+  void debug(Marker marker, Message msg);
+
+  /**
+   * Log a message with the specific Marker at the DEBUG level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   * @param t      A Throwable or null.
+   */
+  void debug(Marker marker, Message msg, Throwable t);
+
+  /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#INFO INFO} level.
+   *
+   * @param message the message object to log.
+   */
+  void info(String message);
+
+  /**
+   * Log a message at the <code>INFO</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   *
+   * @param message the message object to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void info(String message, Throwable t);
+
+  /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#INFO INFO} level.
+   *
+   * @param message the message object to log.
+   */
+  void info(Object message);
+
+  /**
+   * Log a message at the <code>INFO</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   *
+   * @param message the message object to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void info(Object message, Throwable t);
+
+  /**
+   * Log a message with parameters at the <code>INFO</code> level.
+   * @param message the message to log.
+   * @param params parameters to the message.
+   */
+  void info(String message, Object... params);
+
+  /**
+   * Check whether this Logger is enabled for the INFO Level.
+   *
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         INFO, <code>false</code> otherwise.
+   */
+  boolean isInfoEnabled();
+
+  /**
+   * Check whether this Logger is enabled for the INFO Level.
+   *
+   * @param marker The marker data specific to this log statement.
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         INFO, <code>false</code> otherwise.
+   */
+  boolean isInfoEnabled(Marker marker);
+
+  /**
+   * Log a message with the specific Marker at the TRACE level.
+   *
+   * @param msg the message string to be logged
+   */
+  void info(Message msg);
+
+  /**
+   * Log a message with the specific Marker at the INFO level.
+   *
+   * @param msg the message string to be logged
+   * @param t   A Throwable or null.
+   */
+  void info(Message msg, Throwable t);
+
+  /**
+   * Log a message with the specific Marker at the INFO level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   */
+  void info(Marker marker, Message msg);
+
+  /**
+   * Log a message with the specific Marker at the INFO level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   * @param t      A Throwable or null.
+   */
+  void info(Marker marker, Message msg, Throwable t);
+
+ /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#WARN WARN} level.
+   *
+   * @param message the message object to log.
+   */
+  void warn(String message);
+
+  /**
+   * Log a message at the <code>WARN</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   *
+   * @param message the message object to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void warn(String message, Throwable t);
+
+ /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#WARN WARN} level.
+   *
+   * @param message the message object to log.
+   */
+  void warn(Object message);
+
+  /**
+   * Log a message at the <code>WARN</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   *
+   * @param message the message object to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void warn(Object message, Throwable t);
+
+  /**
+   * Log a message with parameters at the <code>WARN</code> level.
+   * @param message the message to log.
+   * @param params parameters to the message.
+   */
+  void warn(String message, Object... params);
+
+  /**
+   * Check whether this Logger is enabled for the WARN Level.
+   *
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         WARN, <code>false</code> otherwise.
+   */
+  boolean isWarnEnabled();
+
+  /**
+   * Check whether this Logger is enabled for the WARN Level.
+   *
+   * @param marker The marker data specific to this log statement.
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         WARN, <code>false</code> otherwise.
+   */
+  boolean isWarnEnabled(Marker marker);
+
+  /**
+   * Log a message with the specific Marker at the WARN level.
+   *
+   * @param msg the message string to be logged
+   */
+  void warn(Message msg);
+
+  /**
+   * Log a message with the specific Marker at the WARN level.
+   *
+   * @param msg the message string to be logged
+   * @param t   A Throwable or null.
+   */
+  void warn(Message msg, Throwable t);
+
+  /**
+   * Log a message with the specific Marker at the WARN level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   */
+  void warn(Marker marker, Message msg);
+
+  /**
+   * Log a message with the specific Marker at the WARN level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   * @param t      A Throwable or null.
+   */
+  void warn(Marker marker, Message msg, Throwable t);
+
+  /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#ERROR ERROR} level.
+   *
+   * @param message the message object to log.
+   */
+  void error(String message);
+
+  /**
+   * Log a message at the <code>ERROR</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   *
+   * @param message the message object to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void error(String message, Throwable t);
+
+  /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#ERROR ERROR} level.
+   *
+   * @param message the message object to log.
+   */
+  void error(Object message);
+
+  /**
+   * Log a message at the <code>ERROR</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   *
+   * @param message the message object to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void error(Object message, Throwable t);
+
+  /**
+   * Log a message with parameters at the <code>ERROR</code> level.
+   * @param message the message to log.
+   * @param params parameters to the message.
+   */
+  void error(String message, Object... params);
+
+  /**
+   * Check whether this Logger is enabled for the ERROR Level.
+   *
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         ERROR, <code>false</code> otherwise.
+   */
+  boolean isErrorEnabled();
+
+  /**
+   * Check whether this Logger is enabled for the ERROR Level.
+   *
+   * @param marker The marker data specific to this log statement.
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         ERROR, <code>false</code> otherwise.
+   */
+  boolean isErrorEnabled(Marker marker);
+
+  /**
+   * Log a message with the specific Marker at the ERROR level.
+   *
+   * @param msg the message string to be logged
+   */
+  void error(Message msg);
+
+  /**
+   * Log a message with the specific Marker at the ERROR level.
+   *
+   * @param msg the message string to be logged
+   * @param t   A Throwable or null.
+   */
+  void error(Message msg, Throwable t);
+
+  /**
+   * Log a message with the specific Marker at the ERROR level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   */
+  void error(Marker marker, Message msg);
+
+  /**
+   * Log a message with the specific Marker at the ERROR level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   * @param t      A Throwable or null.
+   */
+  void error(Marker marker, Message msg, Throwable t);
+
+  /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#FATAL FATAL} level.
+   *
+   * @param message the message object to log.
+   */
+  void fatal(String message);
+
+  /**
+   * Log a message at the <code>FATAL</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   *
+   * @param message the message object to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void fatal(String message, Throwable t);
+
+    /**
+   * Log a message object with the {@link org.apache.logging.log4j.Level#FATAL FATAL} level.
+   *
+   * @param message the message object to log.
+   */
+  void fatal(Object message);
+
+  /**
+   * Log a message at the <code>FATAL</code> level including the
+   * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+   *
+   * @param message the message object to log.
+   * @param t       the exception to log, including its stack trace.
+   */
+  void fatal(Object message, Throwable t);
+  /**
+   * Log a message with parameters at the <code>FATAL</code> level.
+   * @param message the message to log.
+   * @param params parameters to the message.
+   */
+  void fatal(String message, Object... params);
+
+  /**
+   * Check whether this Logger is enabled for the FATAL Level.
+   *
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         FATAL, <code>false</code> otherwise.
+   */
+  boolean isFatalEnabled();
+
+  /**
+   * Check whether this Logger is enabled for the FATAL Level.
+   *
+   * @param marker The marker data specific to this log statement.
+   * @return boolean - <code>true</code> if this Logger is enabled for level
+   *         FATAL, <code>false</code> otherwise.
+   */
+  boolean isFatalEnabled(Marker marker);
+
+  /**
+   * Log a message with the specific Marker at the FATAL level.
+   *
+   * @param msg the message string to be logged
+   */
+  void fatal(Message msg);
+
+  /**
+   * Log a message with the specific Marker at the FATAL level.
+   *
+   * @param msg the message string to be logged
+   * @param t   A Throwable or null.
+   */
+  void fatal(Message msg, Throwable t);
+
+  /**
+   * Log a message with the specific Marker at the FATAL level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   */
+  void fatal(Marker marker, Message msg);
+
+  /**
+   * Log a message with the specific Marker at the FATAL level.
+   *
+   * @param marker the marker data specific to this log statement
+   * @param msg    the message string to be logged
+   * @param t      A Throwable or null.
+   */
+  void fatal(Marker marker, Message msg, Throwable t);
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/MDC.java b/log4j2-api/src/main/java/org/apache/logging/log4j/MDC.java
new file mode 100644
index 0000000..1291dff
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/MDC.java
@@ -0,0 +1,113 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * The MDC class is similar to the {@link NDC} class except that it is
+ * based on a map instead of a stack. It provides <em>mapped
+ * diagnostic contexts</em>. A <em>Mapped Diagnostic Context</em>, or
+ * MDC in short, is an instrument for distinguishing interleaved log
+ * output from different sources. Log output is typically interleaved
+ * when a server handles multiple clients near-simultaneously.
+ * <p/>
+ * <p><b><em>The MDC is managed on a per thread basis</em></b>. A
+ * child thread automatically inherits a <em>copy</em> of the mapped
+ * diagnostic context of its parent.
+ */
+public final class MDC {
+
+    private static ThreadLocal<Map<String, Object>> LOCAL =
+        new InheritableThreadLocal<Map<String, Object>>() {
+            protected Map<String, Object> initialValue() {
+                return new HashMap<String, Object>();
+            }
+
+            protected Map<String, Object> childValue(Map<String, Object> parentValue) {
+                return parentValue == null ? null : new HashMap<String, Object>(parentValue);
+            }
+        };
+
+
+    private MDC() {
+
+    }
+
+    /**
+     * Put a context value (the <code>o</code> parameter) as identified
+     * with the <code>key</code> parameter into the current thread's
+     * context map.
+     * <p/>
+     * <p>If the current thread does not have a context map it is
+     * created as a side effect.
+     * @param key The key name.
+     * @param value The key value.
+     */
+    public static void put(String key, Object value) {
+        LOCAL.get().put(key, value);
+    }
+
+    /**
+     * Get the context identified by the <code>key</code> parameter.
+     * <p/>
+     * <p>This method has no side effects.
+     * @param key The key to locate.
+     * @return The value of the object or null.
+     */
+    public static Object get(String key) {
+        return LOCAL.get().get(key);
+    }
+
+    /**
+     * Remove the the context identified by the <code>key</code>
+     * parameter.
+     * @param key The key to remove.
+     */
+    public static void remove(String key) {
+        LOCAL.get().remove(key);
+    }
+
+    /**
+     * Clear the context.
+     */
+    public static void clear() {
+        LOCAL.get().clear();
+    }
+
+    /**
+     * Determine if the key is in the context.
+     * @param key The key to locate.
+     * @return True if the key is in the context, false otherwise.
+     */
+    public static boolean containsKey(String key) {
+        return LOCAL.get().containsKey(key);
+    }
+
+    /**
+     * Get the current thread's MDC as a hashtable. This method is
+     * intended to be used internally.
+     * @return a copy of the context.
+     */
+    public static Map<String, Object> getContext() {
+        return new HashMap<String, Object>(LOCAL.get());
+    }
+
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/Marker.java b/log4j2-api/src/main/java/org/apache/logging/log4j/Marker.java
new file mode 100644
index 0000000..7c82bb2
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/Marker.java
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+import java.io.Serializable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ *
+ */
+public class Marker implements Serializable {
+
+  private static ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<String, Marker>();
+
+  public static Marker getMarker(String name) {
+    return markerMap.putIfAbsent(name, new Marker(name));
+  }
+
+  public static Marker getMarker(String name, String parent) {
+    Marker parentMarker = markerMap.get(parent);
+    if (parentMarker == null) {
+      throw new IllegalArgumentException("Parent Marker " + parent + " has not been defined");
+    }
+    return getMarker(name, parentMarker);
+  }
+
+  public static Marker getMarker(String name, Marker parent) {
+    return markerMap.putIfAbsent(name, new Marker(name, parent));
+  }
+
+  private String name;
+  private Marker parent;
+
+  private Marker(String name) {
+    this.name = name;
+  }
+
+  private Marker(String name, Marker parent) {
+    this.name = name;
+    this.parent = parent;
+  }
+
+  public String getName() {
+    return this.name;
+  }
+
+  public Marker getParent() {
+    return this.parent;
+  }
+
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/NDC.java b/log4j2-api/src/main/java/org/apache/logging/log4j/NDC.java
new file mode 100644
index 0000000..e18456e
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/NDC.java
@@ -0,0 +1,404 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.internal.StatusLogger;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * The NDC class implements <i>nested diagnostic contexts</i> as
+ * defined by Neil Harrison in the article "Patterns for Logging
+ * Diagnostic Messages" part of the book "<i>Pattern Languages of
+ * Program Design 3</i>" edited by Martin et al.
+ * <p/>
+ * <p>A Nested Diagnostic Context, or NDC in short, is an instrument
+ * to distinguish interleaved log output from different sources. Log
+ * output is typically interleaved when a server handles multiple
+ * clients near-simultaneously.
+ * <p/>
+ * <p>Interleaved log output can still be meaningful if each log entry
+ * from different contexts had a distinctive stamp. This is where NDCs
+ * come into play.
+ * <p/>
+ * <p><em><b>Note that NDCs are managed on a per thread
+ * basis</b></em>. NDC operations such as {@link #push push}, {@link
+ * #pop}, {@link #clear}, {@link #getDepth} and {@link #setMaxDepth}
+ * affect the NDC of the <em>current</em> thread only. NDCs of other
+ * threads remain unaffected.
+ * <p/>
+ * <p>For example, a servlet can build a per client request NDC
+ * consisting the clients host name and other information contained in
+ * the the request. <em>Cookies</em> are another source of distinctive
+ * information. To build an NDC one uses the {@link #push push}
+ * operation. Simply put,
+ * <p/>
+ * <p><ul>
+ * <li>Contexts can be nested.
+ * <p/>
+ * <p><li>When entering a context, call <code>NDC.push</code>. As a
+ * side effect, if there is no nested diagnostic context for the
+ * current thread, this method will create it.
+ * <p/>
+ * <p><li>When leaving a context, call <code>NDC.pop</code>.
+ * <p/>
+ * <p><li><b>When exiting a thread make sure to call {@link #remove
+ * NDC.remove()}</b>.
+ * </ul>
+ * <p/>
+ * <p>There is no penalty for forgetting to match each
+ * <code>push</code> operation with a corresponding <code>pop</code>,
+ * except the obvious mismatch between the real application context
+ * and the context set in the NDC.
+ * <p/>
+ * <p>Heavy duty systems should call the {@link #remove} method when
+ * leaving the run method of a thread. This ensures that the memory
+ * used by the thread can be freed by the Java garbage
+ * collector. There is a mechanism to lazily remove references to dead
+ * threads. In practice, this means that you can be a little sloppy
+ * and sometimes forget to call {@link #remove} before exiting a
+ * thread.
+ * <p/>
+ * <p>A thread may inherit the nested diagnostic context of another
+ * (possibly parent) thread using the {@link #inherit inherit}
+ * method. A thread may obtain a copy of its NDC with the {@link
+ * #cloneStack cloneStack} method and pass the reference to any other
+ * thread, in particular to a child.
+ */
+public class NDC {
+
+    // The synchronized keyword is not used in this class. This may seem
+    // dangerous, especially since the class will be used by
+    // multiple-threads. In particular, all threads share the same
+    // hashtable (the "ht" variable). This is OK since java hashtables
+    // are thread safe. Same goes for Stacks.
+
+    // More importantly, when inheriting diagnostic contexts the child
+    // thread is handed a clone of the parent's NDC.  It follows that
+    // each thread has its own NDC (i.e. stack).
+
+    private static Logger logger = StatusLogger.getLogger();
+
+    static ConcurrentMap<Thread, Stack<Object>> ht = new ConcurrentHashMap<Thread, Stack<Object>>();
+
+    static int pushCounter = 0; // the number of times push has been called
+    // after the latest call to lazyRemove
+
+    // The number of times we allow push to be called before we call lazyRemove
+    // 5 is a relatively small number. As such, lazyRemove is not called too
+    // frequently. We thus avoid the cost of creating an Enumeration too often.
+    // The higher this number, the longer is the avarage period for which all
+    // logging calls in all threads are blocked.
+    static final int REAP_THRESHOLD = 5;
+
+    // No instances allowed.
+
+    private NDC() {
+    }
+
+    /**
+     * Get NDC stack for current thread.
+     *
+     * @return NDC stack for current thread.
+     */
+    private static Stack<Object> getCurrentStack() {
+        if (ht != null) {
+            return (Stack<Object>) ht.get(Thread.currentThread());
+        }
+        return null;
+    }
+
+
+    /**
+     * Clear any nested diagnostic information if any. This method is
+     * useful in cases where the same thread can be potentially used
+     * over and over in different unrelated contexts.
+     * <p/>
+     * <p>This method is equivalent to calling the {@link #setMaxDepth}
+     * method with a zero <code>maxDepth</code> argument.
+     *
+     * @since 0.8.4c
+     */
+    public static void clear() {
+        Stack stack = getCurrentStack();
+        if (stack != null) {
+            stack.setSize(0);
+        }
+    }
+
+
+    /**
+     * Clone the diagnostic context for the current thread.
+     * <p/>
+     * <p>Internally a diagnostic context is represented as a stack.  A
+     * given thread can supply the stack (i.e. diagnostic context) to a
+     * child thread so that the child can inherit the parent thread's
+     * diagnostic context.
+     * <p/>
+     * <p>The child thread uses the {@link #inherit inherit} method to
+     * inherit the parent's diagnostic context.
+     *
+     * @return Stack A clone of the current thread's  diagnostic context.
+     */
+    public static Stack<Object> cloneStack() {
+        Stack stack = getCurrentStack();
+        if (stack == null) {
+            return null;
+        } else {
+            return (Stack<Object>) stack.clone();
+        }
+    }
+
+
+    /**
+     * Inherit the diagnostic context of another thread.
+     * <p/>
+     * <p>The parent thread can obtain a reference to its diagnostic
+     * context using the {@link #cloneStack} method.  It should
+     * communicate this information to its child so that it may inherit
+     * the parent's diagnostic context.
+     * <p/>
+     * <p>The parent's diagnostic context is cloned before being
+     * inherited. In other words, once inherited, the two diagnostic
+     * contexts can be managed independently.
+     * <p/>
+     * <p>In java, a child thread cannot obtain a reference to its
+     * parent, unless it is directly handed the reference. Consequently,
+     * there is no client-transparent way of inheriting diagnostic
+     * contexts. Do you know any solution to this problem?
+     *
+     * @param stack The diagnostic context of the parent thread.
+     */
+    public static void inherit(Stack<Object> stack) {
+        if (stack != null) {
+            ht.put(Thread.currentThread(), stack);
+        }
+    }
+
+
+    /**
+     * <font color="#FF4040"><b>Never use this method directly.
+     */
+    public static String get() {
+        Stack<Object> s = getCurrentStack();
+        if (s != null && !s.isEmpty()) {
+            return ((DiagnosticContext) s.peek()).fullMessage;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the current nesting depth of this diagnostic context.
+     *
+     * @see #setMaxDepth
+     * @since 0.7.5
+     */
+    public static int getDepth() {
+        Stack<Object> stack = getCurrentStack();
+        if (stack == null) {
+            return 0;
+        } else {
+            return stack.size();
+        }
+    }
+
+    private static void lazyRemove() {
+        if (ht == null) {
+            return;
+        }
+
+        Vector<Thread> v;
+
+        // Avoid calling clean-up too often.
+        if (++pushCounter <= REAP_THRESHOLD) {
+            return; // We release the lock ASAP.
+        } else {
+            pushCounter = 0; // OK let's do some work.
+        }
+
+        int misses = 0;
+        v = new Vector<Thread>();
+        Iterator<Thread> iter = ht.keySet().iterator();
+        // We give up after 4 straight missses. That is 4 consecutive
+        // inspected threads in 'ht' that turn out to be alive.
+        // The higher the proportion on dead threads in ht, the higher the
+        // chances of removal.
+        while (iter.hasNext() && (misses <= 4)) {
+            Thread t = iter.next();
+            if (t.isAlive()) {
+                misses++;
+            } else {
+                misses = 0;
+                v.addElement(t);
+            }
+        }
+
+        int size = v.size();
+        for (int i = 0; i < size; i++) {
+            Thread t = v.elementAt(i);
+            logger.debug("Lazy NDC removal for thread [{}] ({}).", t.getName(), ht.size());
+            ht.remove(t);
+        }
+    }
+
+    /**
+     * Clients should call this method before leaving a diagnostic
+     * context.
+     * <p/>
+     * <p>The returned value is the value that was pushed last. If no
+     * context is available, then the empty string "" is returned.
+     *
+     * @return String The innermost diagnostic context.
+     */
+    public static String pop() {
+        Stack<Object> stack = getCurrentStack();
+        if (stack != null && !stack.isEmpty()) {
+            return ((DiagnosticContext) stack.pop()).message;
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * Looks at the last diagnostic context at the top of this NDC
+     * without removing it.
+     * <p/>
+     * <p>The returned value is the value that was pushed last. If no
+     * context is available, then the empty string "" is returned.
+     *
+     * @return String The innermost diagnostic context.
+     */
+    public static String peek() {
+        Stack<Object> stack = getCurrentStack();
+        if (stack != null && !stack.isEmpty()) {
+            return ((DiagnosticContext) stack.peek()).message;
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * Push new diagnostic context information for the current thread.
+     * <p/>
+     * <p>The contents of the <code>message</code> parameter is
+     * determined solely by the client.
+     *
+     * @param message The new diagnostic context information.
+     */
+    public static void push(String message) {
+        Stack<Object> stack = getCurrentStack();
+
+        if (stack == null) {
+            DiagnosticContext dc = new DiagnosticContext(message, null);
+            stack = new Stack<Object>();
+            Thread key = Thread.currentThread();
+            ht.put(key, stack);
+            stack.push(dc);
+        } else if (stack.isEmpty()) {
+            DiagnosticContext dc = new DiagnosticContext(message, null);
+            stack.push(dc);
+        } else {
+            DiagnosticContext parent = (DiagnosticContext) stack.peek();
+            stack.push(new DiagnosticContext(message, parent));
+        }
+    }
+
+    /**
+     * Remove the diagnostic context for this thread.
+     * <p/>
+     * <p>Each thread that created a diagnostic context by calling
+     * {@link #push} should call this method before exiting. Otherwise,
+     * the memory used by the <b>thread</b> cannot be reclaimed by the
+     * VM.
+     * <p/>
+     * <p>As this is such an important problem in heavy duty systems and
+     * because it is difficult to always guarantee that the remove
+     * method is called before exiting a thread, this method has been
+     * augmented to lazily remove references to dead threads. In
+     * practice, this means that you can be a little sloppy and
+     * occasionally forget to call {@link #remove} before exiting a
+     * thread. However, you must call <code>remove</code> sometime. If
+     * you never call it, then your application is sure to run out of
+     * memory.
+     */
+    public static void remove() {
+        if (ht != null) {
+            ht.remove(Thread.currentThread());
+
+            // Lazily remove dead-thread references in ht.
+            lazyRemove();
+        }
+    }
+
+    /**
+     * Set maximum depth of this diagnostic context. If the current
+     * depth is smaller or equal to <code>maxDepth</code>, then no
+     * action is taken.
+     * <p/>
+     * <p>This method is a convenient alternative to multiple {@link
+     * #pop} calls. Moreover, it is often the case that at the end of
+     * complex call sequences, the depth of the NDC is
+     * unpredictable. The <code>setMaxDepth</code> method circumvents
+     * this problem.
+     * <p/>
+     * <p>For example, the combination
+     * <pre>
+     * void foo() {
+     * &nbsp;  int depth = NDC.getDepth();
+     * <p/>
+     * &nbsp;  ... complex sequence of calls
+     * <p/>
+     * &nbsp;  NDC.setMaxDepth(depth);
+     * }
+     * </pre>
+     * <p/>
+     * ensures that between the entry and exit of foo the depth of the
+     * diagnostic stack is conserved.
+     *
+     * @see #getDepth
+     * @param maxDepth The maximum depth of the stack.
+     */
+    public static void setMaxDepth(int maxDepth) {
+        Stack<Object> stack = getCurrentStack();
+        if (stack != null && maxDepth < stack.size()) {
+            stack.setSize(maxDepth);
+        }
+    }
+
+    // =====================================================================
+
+    private static class DiagnosticContext {
+
+        String fullMessage;
+        String message;
+
+        DiagnosticContext(String message, DiagnosticContext parent) {
+            this.message = message;
+            if (parent != null) {
+                fullMessage = parent.fullMessage + ' ' + message;
+            } else {
+                fullMessage = message;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusConsoleListener.java b/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusConsoleListener.java
new file mode 100644
index 0000000..e9398fc
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusConsoleListener.java
@@ -0,0 +1,70 @@
+/*
+ * 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.internal;
+
+import org.apache.logging.log4j.Level;
+
+/**
+ *
+ */
+public class StatusConsoleListener implements StatusListener {
+
+    private static final String STATUS_LEVEL = "org.apache.logging.log4j.StatusLevel";
+
+    private Level level = Level.FATAL;
+
+    private String[] filters = null;
+
+    public StatusConsoleListener() {
+        String str = System.getProperty(STATUS_LEVEL);
+        if (str != null) {
+            level = Level.toLevel(str, Level.FATAL);
+        }
+    }
+
+    public StatusConsoleListener(Level level) {
+        this.level = level;
+    }
+
+    public void setLevel(Level level) {
+        this.level = level;
+    }
+
+    public void log(StatusData data) {
+        if (data.getLevel().greaterOrEqual(level) && !filtered(data)) {
+            System.out.println(data.getFormattedStatus());
+        }
+    }
+
+    public void setFilters(String[] filters) {
+        this.filters = filters;
+    }
+
+    private boolean filtered(StatusData data) {
+        if (filters == null) {
+            return false;
+        }
+        String caller = data.getStackTraceElement().getClassName();
+        for (String filter : filters) {
+            if (caller.startsWith(filter)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusData.java b/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusData.java
new file mode 100644
index 0000000..f5674af
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusData.java
@@ -0,0 +1,95 @@
+/*
+ * 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.internal;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.message.Message;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ *
+ */
+public class StatusData {
+
+    private final long timestamp;
+
+    private final StackTraceElement caller;
+
+    private final Level level;
+
+    private final Message msg;
+
+    private final Throwable throwable;
+
+
+    public StatusData(StackTraceElement caller, Level level, Message msg, Throwable t) {
+        this.timestamp = System.currentTimeMillis();
+        this.caller = caller;
+        this.level = level;
+        this.msg = msg;
+        this.throwable = t;
+    }
+
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    public StackTraceElement getStackTraceElement() {
+        return caller;
+    }
+
+    public Level getLevel() {
+        return level;
+    }
+
+    public Message getMessage() {
+        return msg;
+    }
+
+    public Throwable getThrowable() {
+        return throwable;
+    }
+
+    public String getFormattedStatus() {
+        StringBuilder sb = new StringBuilder();
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
+        sb.append(format.format(new Date(timestamp)));       
+        sb.append(" ");
+        sb.append(level.toString());
+        sb.append(" ");
+        sb.append(msg.getFormattedMessage());
+        Object[] params = msg.getParameters();
+        Throwable t;
+        if (throwable == null && params != null && params[params.length -1] instanceof Throwable ) {
+            t = (Throwable) params[params.length - 1];
+        } else {
+            t = throwable;
+        }
+        if (t != null) {
+            sb.append(" ");
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            t.printStackTrace(new PrintStream(baos));
+            sb.append(baos.toString());
+        }
+        return sb.toString();
+    }
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusListener.java b/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusListener.java
new file mode 100644
index 0000000..bdfa309
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusListener.java
@@ -0,0 +1,9 @@
+package org.apache.logging.log4j.internal;
+
+/**
+ *
+ */
+public interface StatusListener {
+
+    void log(StatusData data);   
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusLogger.java b/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusLogger.java
new file mode 100644
index 0000000..d150124
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/internal/StatusLogger.java
@@ -0,0 +1,202 @@
+/*
+ * 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.internal;
+
+import org.apache.logging.log4j.spi.AbstractLogger;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.message.Message;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ *
+ */
+public class StatusLogger extends AbstractLogger {
+
+    private static final String NOT_AVAIL = "?";
+
+    // private static final String FQCN = AbstractLogger.class.getName();
+
+    private static StatusLogger statusLogger = new StatusLogger();
+
+    private Logger logger = null;
+
+    private CopyOnWriteArrayList<StatusListener> listeners = new CopyOnWriteArrayList<StatusListener>();
+    private ReentrantReadWriteLock listenersLock = new ReentrantReadWriteLock();
+
+    private List<StatusData> messages = new ArrayList<StatusData>();
+    private ReentrantLock msgLock = new ReentrantLock();
+
+    private StatusLogger() {
+    }
+
+    public static StatusLogger getLogger() {
+        return statusLogger;
+    }
+
+    public void registerListener(StatusListener listener) {
+        listenersLock.writeLock().lock();
+        try {
+            listeners.add(listener);
+        } finally {
+            listenersLock.writeLock().unlock();
+        }
+    }
+
+    public void removeListener(StatusListener listener) {
+        listenersLock.writeLock().lock();
+        try {
+            listeners.remove(listener);
+        } finally {
+            listenersLock.writeLock().unlock();
+        }
+    }
+
+    public void reset() {
+        listeners.clear();
+        clear();
+    }
+
+    public List<StatusData> getStatusData() {
+        msgLock.lock();
+        try {
+            return new ArrayList<StatusData>(messages);
+        } finally {
+            msgLock.unlock();
+        }
+    }
+
+    public void clear() {
+        msgLock.lock();
+        try {
+            messages.clear();
+        } finally {
+            msgLock.unlock();
+        }
+    }
+
+    /*
+    @Override
+    protected String getFQCN() {
+        return FQCN;
+    } */
+
+    @Override
+    public void log(Marker marker, String fqcn, Level level, Message msg, Throwable t) {
+        StackTraceElement element = null;
+        if (fqcn != null) {
+            element = getStackTraceElement(fqcn, Thread.currentThread().getStackTrace());
+        }
+        StatusData data = new StatusData(element, level, msg, t);
+        msgLock.lock();
+        try {
+            messages.add(data);
+        } finally {
+            msgLock.unlock();
+        }
+        for (StatusListener listener : listeners) {
+            listener.log(data);
+        }
+    }
+
+    private StackTraceElement getStackTraceElement(String fqcn, StackTraceElement[] stackTrace) {
+        if (fqcn == null) {
+            return null;
+        }
+        boolean next = false;
+        for (StackTraceElement element : stackTrace) {
+            if (next) {
+                return element;
+            }
+            String className = element.getClassName();
+            if (fqcn.equals(className)) {
+                next = true;
+            } else if (NOT_AVAIL.equals(className)) {
+                break;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String data) {
+        return isEnabled(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String data, Throwable t) {
+        return isEnabled(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String data, Object p1) {
+        return isEnabled(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String data, Object p1, Object p2) {
+        return isEnabled(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String data, Object p1, Object p2, Object p3) {
+        return isEnabled(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String data, Object p1, Object p2, Object p3,
+                                Object... params) {
+        return isEnabled(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, Object data, Throwable t) {
+        return isEnabled(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, Message data, Throwable t) {
+        return isEnabled(level, marker);
+    }
+
+    protected boolean isEnabled(Level level, Marker marker) {
+        if (logger == null) {
+            return true;
+        }
+        switch (level) {
+            case FATAL:
+                return logger.isFatalEnabled(marker);
+            case TRACE:
+                return logger.isTraceEnabled(marker);
+            case DEBUG:
+                return logger.isDebugEnabled(marker);
+            case INFO:
+                return logger.isInfoEnabled(marker);
+            case WARN:
+                return logger.isWarnEnabled(marker);
+            case ERROR:
+                return logger.isErrorEnabled(marker);
+        }
+        return false;
+    }
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/message/Message.java b/log4j2-api/src/main/java/org/apache/logging/log4j/message/Message.java
new file mode 100644
index 0000000..f886bae
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/message/Message.java
@@ -0,0 +1,42 @@
+/*
+ * 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.message;
+
+import java.io.Serializable;
+
+/**
+ * An interface for various Message implementations that can be logged.
+ */
+public interface Message extends Serializable {
+  /**
+   * Returns the Message formatted as a String.
+   * @return The message String.
+   */
+  String getFormattedMessage();
+
+  /**
+   * Returns the format portion of the Message
+   * @return
+   */
+  String getMessageFormat();
+
+  /**
+   * Returns parameter values, if any.
+   * @return An array of parameter values or null.
+   */
+  Object[] getParameters();
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java b/log4j2-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
new file mode 100644
index 0000000..b8e1bf3
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.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.message;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+/**
+ * Handles messages that contain an Object.
+ */
+public class ObjectMessage implements Message, Serializable {
+
+    private transient Object obj;
+
+    public ObjectMessage(Object obj) {
+        this.obj = obj;
+    }
+
+    public String getFormattedMessage() {
+        return obj.toString();
+    }
+
+    public String getMessageFormat() {
+        return obj.toString();
+    }
+
+    public Object[] getParameters() {
+        return new Object[]{obj};
+    }
+
+
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        ObjectMessage that = (ObjectMessage) o;
+
+        return !(obj != null ? !obj.equals(that.obj) : that.obj != null);
+    }
+
+    public int hashCode() {
+        return obj != null ? obj.hashCode() : 0;
+    }
+
+    public String toString() {
+        return "ObjectMessage[obj=" + obj.toString() + "]";
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+        if (obj instanceof Serializable) {
+            out.writeObject(obj);
+        } else {
+            out.writeObject(obj.toString());
+        }
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        obj = in.readObject();
+    }
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java b/log4j2-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java
new file mode 100644
index 0000000..a6fed8c
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java
@@ -0,0 +1,509 @@
+/*
+ * 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.message;
+
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Handles messages that consist of a format string containing '{}' to represent each replaceable token, and
+ * the parameters.
+ *
+ * This class was originally written for Lillith (http://mac.freshmeat.net/projects/lilith-viewer) by
+ * Joern Huxhorn where it is licensed under the LGPL. It has been relicensed here with his permission
+ * providing that this attribution remain.
+ */
+public class ParameterizedMessage implements Message, Serializable {
+  private static final long serialVersionUID = -665975803997290697L;
+
+  private String messagePattern;
+  private String[] stringArgs;
+  private transient Object[] argArray;
+  private transient String formattedMessage;
+  private transient Throwable throwable;
+
+  public ParameterizedMessage() {
+    this(null, null, null);
+  }
+
+  public ParameterizedMessage(String messagePattern, String[] stringArgs, Throwable throwable) {
+    this.messagePattern = messagePattern;
+    this.stringArgs = stringArgs;
+    this.throwable = throwable;
+  }
+
+  /**
+   * <p>This method returns a ParameterizedMessage which contains the arguments converted to String
+   * as well as an optional Throwable.</p>
+   * <p/>
+   * <p>If the last argument is a Throwable and is NOT used up by a placeholder in the message pattern it is returned
+   * in ParameterizedMessage.getThrowable() and won't be contained in the created String[].<br/>
+   * If it is used up ParameterizedMessage.getThrowable() will return null even if the last argument was a Throwable!</p>
+   *
+   * @param messagePattern the message pattern that to be checked for placeholders.
+   * @param arguments      the argument array to be converted.
+   * @return a ParameterizedMessage containing the messagePattern, converted arguments and, optionally, a Throwable.
+   */
+  public ParameterizedMessage(String messagePattern, Object[] arguments) {
+    this.messagePattern = messagePattern;
+    if (arguments == null) {
+      return;
+    }
+    parseArguments(arguments);
+  }
+
+  public ParameterizedMessage(String messagePattern, Object arg) {
+    this(messagePattern, new Object[] {arg});
+  }
+
+  public ParameterizedMessage(String messagePattern, Object arg1, Object arg2) {
+    this(messagePattern, new Object[] {arg1, arg2});
+  }
+
+  private void parseArguments(Object[] arguments) {
+    int argsCount = countArgumentPlaceholders(messagePattern);
+    int resultArgCount = arguments.length;
+    if (argsCount < arguments.length) {
+      if (arguments[arguments.length - 1] instanceof Throwable) {
+        throwable = (Throwable) arguments[arguments.length - 1];
+        resultArgCount--;
+      }
+    }
+    argArray = new Object[resultArgCount];
+    for (int i=0; i < resultArgCount; ++i) {
+      argArray[i] = arguments[i];
+    }
+
+    if (argsCount == 1 && throwable == null && arguments.length > 1) {
+      // special case
+      stringArgs = new String[1];
+      stringArgs[0] = deepToString(arguments);
+    }
+    else {
+      stringArgs = new String[resultArgCount];
+      for (int i = 0; i < stringArgs.length; i++) {
+        stringArgs[i] = deepToString(arguments[i]);
+      }
+    }
+  }
+
+  public String getFormattedMessage() {
+    if (formattedMessage == null) {
+      formatMessage();
+    }
+    return formattedMessage;
+  }
+
+  public String getMessageFormat() {
+    return messagePattern;
+  }
+
+  public void setMessageFormat(String messagePattern) {
+    this.messagePattern = messagePattern;
+    this.formattedMessage = null;
+  }
+
+  public Object[] getParameters() {
+    if (argArray != null) {
+      return argArray;
+    }
+    return stringArgs;
+  }
+
+  public void setParameters(String[] parameters) {
+    this.stringArgs = parameters;
+    this.formattedMessage = null;
+  }
+
+  public void setParameters(Object[] parameters) {
+    parseArguments(parameters);
+    this.formattedMessage = null;
+  }
+
+  public void setThrowable(Throwable throwable) {
+    this.throwable = throwable;
+  }
+
+  /**
+   * Returns the Throwable that was given as the last argument, if any.
+   * It will not survive serialization.
+   *
+   * @return the Throwable, if any.
+   */
+  public Throwable getThrowable() {
+    return throwable;
+  }
+
+  private void formatMessage() {
+    if (formattedMessage == null) {
+      formattedMessage = format(messagePattern, stringArgs);
+    }
+  }
+
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ParameterizedMessage that = (ParameterizedMessage) o;
+
+    if (messagePattern != null ? !messagePattern.equals(that.messagePattern) : that.messagePattern != null) {
+      return false;
+    }
+    if (!Arrays.equals(stringArgs, that.stringArgs)) return false;
+    //if (throwable != null ? !throwable.equals(that.throwable) : that.throwable != null) return false;
+
+    return true;
+  }
+
+  public int hashCode() {
+    int result = messagePattern != null ? messagePattern.hashCode() : 0;
+    result = 31 * result + (stringArgs != null ? Arrays.hashCode(stringArgs) : 0);
+    return result;
+  }
+
+  private static final char DELIM_START = '{';
+  private static final char DELIM_STOP = '}';
+  private static final char ESCAPE_CHAR = '\\';
+
+  public static final String RECURSION_PREFIX = "[...";
+  public static final String RECURSION_SUFFIX = "...]";
+
+  public static final String ERROR_PREFIX = "[!!!";
+  public static final String ERROR_SEPARATOR = "=>";
+  public static final String ERROR_MSG_SEPARATOR = ":";
+  public static final String ERROR_SUFFIX = "!!!]";
+
+  /**
+   * Replace placeholders in the given messagePattern with arguments.
+   *
+   * @param messagePattern the message pattern containing placeholders.
+   * @param arguments      the arguments to be used to replace placeholders.
+   * @return the formatted message.
+   */
+  public static String format(String messagePattern, Object[] arguments) {
+    if (messagePattern == null || arguments == null || arguments.length == 0) {
+      return messagePattern;
+    }
+
+    StringBuilder result = new StringBuilder();
+    int escapeCounter = 0;
+    int currentArgument = 0;
+    for (int i = 0; i < messagePattern.length(); i++) {
+      char curChar = messagePattern.charAt(i);
+      if (curChar == ESCAPE_CHAR) {
+        escapeCounter++;
+      }
+      else {
+        if (curChar == DELIM_START) {
+          if (i < messagePattern.length() - 1) {
+            if (messagePattern.charAt(i + 1) == DELIM_STOP) {
+              // write escaped escape chars
+              int escapedEscapes = escapeCounter / 2;
+              for (int j = 0; j < escapedEscapes; j++) {
+                result.append(ESCAPE_CHAR);
+              }
+
+              if (escapeCounter % 2 == 1) {
+                // i.e. escaped
+                // write escaped escape chars
+                result.append(DELIM_START);
+                result.append(DELIM_STOP);
+              }
+              else {
+                // unescaped
+                if (currentArgument < arguments.length) {
+                  result.append(arguments[currentArgument]);
+                }
+                else {
+                  result.append(DELIM_START).append(DELIM_STOP);
+                }
+                currentArgument++;
+              }
+              i++;
+              escapeCounter = 0;
+              continue;
+            }
+          }
+        }
+        // any other char beside ESCAPE or DELIM_START/STOP-combo
+        // write unescaped escape chars
+        if (escapeCounter > 0) {
+          for (int j = 0; j < escapeCounter; j++) {
+            result.append(ESCAPE_CHAR);
+          }
+          escapeCounter = 0;
+        }
+        result.append(curChar);
+      }
+    }
+    return result.toString();
+  }
+
+  /**
+   * Counts the number of unescaped placeholders in the given messagePattern.
+   *
+   * @param messagePattern the message pattern to be analyzed.
+   * @return the number of unescaped placeholders.
+   */
+  public static int countArgumentPlaceholders(String messagePattern) {
+    if (messagePattern == null) {
+      return 0;
+    }
+
+    int delim = messagePattern.indexOf(DELIM_START);
+
+    if (delim == -1) {
+      // special case, no placeholders at all.
+      return 0;
+    }
+    int result = 0;
+    boolean isEscaped = false;
+    for (int i = 0; i < messagePattern.length(); i++) {
+      char curChar = messagePattern.charAt(i);
+      if (curChar == ESCAPE_CHAR) {
+        isEscaped = !isEscaped;
+      }
+      else if (curChar == DELIM_START) {
+        if (!isEscaped) {
+          if (i < messagePattern.length() - 1) {
+            if (messagePattern.charAt(i + 1) == DELIM_STOP) {
+              result++;
+              i++;
+            }
+          }
+        }
+        isEscaped = false;
+      }
+      else {
+        isEscaped = false;
+      }
+    }
+    return result;
+  }
+
+  public static String deepToString(Object o) {
+    if (o == null) {
+      return null;
+    }
+    if (o instanceof String) {
+      return (String) o;
+    }
+    StringBuilder str = new StringBuilder();
+    Set dejaVu = new HashSet(); // that's actually a neat name ;)
+    recursiveDeepToString(o, str, dejaVu);
+    return str.toString();
+  }
+
+  /**
+   * This method performs a deep toString of the given Object.
+   * Primitive arrays are converted using their respective Arrays.toString methods while
+   * special handling is implemented for "container types", i.e. Object[], Map and Collection because those could
+   * contain themselves.
+   * <p/>
+   * dejaVu is used in case of those container types to prevent an endless recursion.
+   * <p/>
+   * It should be noted that neither AbstractMap.toString() nor AbstractCollection.toString() implement such a behavior.
+   * They only check if the container is directly contained in itself, but not if a contained container contains the
+   * original one. Because of that, Arrays.toString(Object[]) isn't safe either.
+   * Confusing? Just read the last paragraph again and check the respective toString() implementation.
+   * <p/>
+   * This means, in effect, that logging would produce a usable output even if an ordinary System.out.println(o)
+   * would produce a relatively hard-to-debug StackOverflowError.
+   *
+   * @param o      the Object to convert into a String
+   * @param str    the StringBuilder that o will be appended to
+   * @param dejaVu a list of container identities that were already used.
+   */
+  private static void recursiveDeepToString(Object o, StringBuilder str, Set dejaVu) {
+    if (o == null) {
+      str.append("null");
+      return;
+    }
+    if (o instanceof String) {
+      str.append(o);
+      return;
+    }
+
+    Class oClass = o.getClass();
+    if (oClass.isArray()) {
+      if (oClass == byte[].class) {
+        str.append(Arrays.toString((byte[]) o));
+      }
+      else if (oClass == short[].class) {
+        str.append(Arrays.toString((short[]) o));
+      }
+      else if (oClass == int[].class) {
+        str.append(Arrays.toString((int[]) o));
+      }
+      else if (oClass == long[].class) {
+        str.append(Arrays.toString((long[]) o));
+      }
+      else if (oClass == float[].class) {
+        str.append(Arrays.toString((float[]) o));
+      }
+      else if (oClass == double[].class) {
+        str.append(Arrays.toString((double[]) o));
+      }
+      else if (oClass == boolean[].class) {
+        str.append(Arrays.toString((boolean[]) o));
+      }
+      else if (oClass == char[].class) {
+        str.append(Arrays.toString((char[]) o));
+      }
+      else {
+        // special handling of container Object[]
+        String id = identityToString(o);
+        if (dejaVu.contains(id)) {
+          str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
+        }
+        else {
+          dejaVu.add(id);
+          Object[] oArray = (Object[]) o;
+          str.append("[");
+          boolean first = true;
+          for (int i = 0; i < oArray.length; ++i) {
+            Object current = oArray[i];
+            if (first) {
+              first = false;
+            }
+            else {
+              str.append(", ");
+            }
+            recursiveDeepToString(current, str, new HashSet(dejaVu));
+          }
+          str.append("]");
+        }
+        //str.append(Arrays.deepToString((Object[]) o));
+      }
+    }
+    else if (o instanceof Map) {
+      // special handling of container Map
+      String id = identityToString(o);
+      if (dejaVu.contains(id)) {
+        str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
+      }
+      else {
+        dejaVu.add(id);
+        Map oMap = (Map) o;
+        str.append("{");
+        boolean isFirst = true;
+        Iterator iter = oMap.entrySet().iterator();
+        while (iter.hasNext()) {
+          Map.Entry current = (Map.Entry) iter.next();
+          if (isFirst) {
+            isFirst = false;
+          }
+          else {
+            str.append(", ");
+          }
+          Object key = current.getKey();
+          Object value = current.getValue();
+          recursiveDeepToString(key, str, new HashSet(dejaVu));
+          str.append("=");
+          recursiveDeepToString(value, str, new HashSet(dejaVu));
+        }
+        str.append("}");
+      }
+    }
+    else if (o instanceof Collection) {
+      // special handling of container Collection
+      String id = identityToString(o);
+      if (dejaVu.contains(id)) {
+        str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
+      }
+      else {
+        dejaVu.add(id);
+        Collection oCol = (Collection) o;
+        str.append("[");
+        boolean isFirst = true;
+        Iterator iter = oCol.iterator();
+        while (iter.hasNext()) {
+          Object current = iter.next();
+          if (isFirst) {
+            isFirst = false;
+          }
+          else {
+            str.append(", ");
+          }
+          recursiveDeepToString(current, str, new HashSet(dejaVu));
+        }
+        str.append("]");
+      }
+    }
+    else if (o instanceof Date) {
+      Date date = (Date) o;
+      SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+      // I'll leave it like this for the moment... this could probably be optimized using ThreadLocal...
+      str.append(format.format(date));
+    }
+    else {
+      // it's just some other Object, we can only use toString().
+      try {
+        str.append(o.toString());
+      }
+      catch (Throwable t) {
+        str.append(ERROR_PREFIX);
+        str.append(identityToString(o));
+        str.append(ERROR_SEPARATOR);
+        String msg = t.getMessage();
+        String className = t.getClass().getName();
+        str.append(className);
+        if (!className.equals(msg)) {
+          str.append(ERROR_MSG_SEPARATOR);
+          str.append(msg);
+        }
+        str.append(ERROR_SUFFIX);
+      }
+    }
+  }
+
+  /**
+   * This method returns the same as if Object.toString() would not have been
+   * overridden in obj.
+   * <p/>
+   * Note that this isn't 100% secure as collisions can always happen with hash codes.
+   * <p/>
+   * Copied from Object.hashCode():
+   * As much as is reasonably practical, the hashCode method defined by
+   * class <tt>Object</tt> does return distinct integers for distinct
+   * objects. (This is typically implemented by converting the internal
+   * address of the object into an integer, but this implementation
+   * technique is not required by the
+   * Java<font size="-2"><sup>TM</sup></font> programming language.)
+   *
+   * @param obj the Object that is to be converted into an identity string.
+   * @return the identity string as also defined in Object.toString()
+   */
+  public static String identityToString(Object obj) {
+    if (obj == null) {
+      return null;
+    }
+    return obj.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(obj));
+  }
+
+  public String toString() {
+    return "ParameterizedMessage[messagePattern=" + messagePattern + ", stringArgs=" +
+        Arrays.toString(stringArgs) + ", throwable=" + throwable + "]";
+  }
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java b/log4j2-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java
new file mode 100644
index 0000000..9758f96
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java
@@ -0,0 +1,65 @@
+/*
+ * 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.message;
+
+import java.io.Serializable;
+
+/**
+ * The simplest possible implementation of Message. It just returns the String given as the constructor argument.
+ */
+public class SimpleMessage implements Message, Serializable {
+  private static final long serialVersionUID = -8398002534962715992L;
+
+  private final String message;
+
+  public SimpleMessage() {
+    this(null);
+  }
+
+  public SimpleMessage(String message) {
+    this.message = message;
+  }
+
+  public String getFormattedMessage() {
+    return message;
+  }
+
+  public String getMessageFormat() {
+    return message;
+  }
+
+  public Object[] getParameters() {
+    return null;
+  }
+
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    SimpleMessage that = (SimpleMessage) o;
+
+    return !(message != null ? !message.equals(that.message) : that.message != null);
+  }
+
+  public int hashCode() {
+    return message != null ? message.hashCode() : 0;
+  }
+
+  public String toString() {
+    return "SimpleMessage[message=" + message + "]";
+  }
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/message/StructuredDataId.java b/log4j2-api/src/main/java/org/apache/logging/log4j/message/StructuredDataId.java
new file mode 100644
index 0000000..52e0b46
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/message/StructuredDataId.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.message;
+
+import java.io.Serializable;
+
+/**
+ *
+ */
+
+/**
+ * The StructuredData identifier
+ */
+public class StructuredDataId implements Serializable {
+    private static final long serialVersionUID = 9031746276396249990L;
+
+    public static StructuredDataId TIME_QUALITY = new StructuredDataId("timeQuality", null,
+        new String[]{"tzKnown", "isSynced", "syncAccuracy"});
+    public static StructuredDataId ORIGIN = new StructuredDataId("origin", null,
+        new String[]{"ip", "enterpriseId", "software", "swVersion"});
+    public static StructuredDataId META = new StructuredDataId("meta", null,
+        new String[]{"sequenceId", "sysUpTime", "language"});
+
+    public static final int RESERVED = -1;
+
+    private final String name;
+    private final int enterpriseNumber;
+    private final String[] required;
+    private final String[] optional;
+
+    protected StructuredDataId(String name, String[] required, String[] optional) {
+        int index = -1;
+        if (name != null) {
+            if (name.length() > 32) {
+                throw new IllegalArgumentException("Length of id exceeds maximum of 32 characters: " + name);
+            }
+            index = name.indexOf("@");
+        }
+
+        if (index > 0) {
+            this.name = name.substring(0, index);
+            this.enterpriseNumber = Integer.parseInt(name.substring(index + 1));
+        } else {
+            this.name = name;
+            this.enterpriseNumber = RESERVED;
+        }
+        this.required = required;
+        this.optional = optional;
+    }
+
+    /**
+     * A Constructor that helps conformance to RFC 5424.
+     *
+     * @param name             The name portion of the id.
+     * @param enterpriseNumber The enterprise number.
+     * @param required         The list of keys that are required for this id.
+     * @param optional         The list of keys that are optional for this id.
+     */
+    public StructuredDataId(String name, int enterpriseNumber, String[] required, String[] optional) {
+        if (name == null) {
+            throw new IllegalArgumentException("No structured id name was supplied");
+        }
+        if (enterpriseNumber <= 0) {
+            throw new IllegalArgumentException("No enterprise number was supplied");
+        }
+        this.name = name;
+        this.enterpriseNumber = enterpriseNumber;
+        String id = enterpriseNumber < 0 ? name : name + "@" + enterpriseNumber;
+        if (id.length() > 32) {
+            throw new IllegalArgumentException("Length of id exceeds maximum of 32 characters: " + id);
+        }
+        this.required = required;
+        this.optional = optional;
+    }
+
+    public StructuredDataId makeId(StructuredDataId id) {
+        if (id == null) {
+            return this;
+        }
+        return makeId(id.getName(), id.getEnterpriseNumber());
+    }
+
+    public StructuredDataId makeId(String defaultId, int enterpriseNumber) {
+        String id;
+        String[] req;
+        String[] opt;
+        if (enterpriseNumber <= 0) {
+            return this;
+        }
+        if (this.name != null) {
+            id = this.name;
+            req = this.required;
+            opt = this.optional;
+        } else {
+            id = defaultId;
+            req = null;
+            opt = null;
+        }
+
+        return new StructuredDataId(id, enterpriseNumber, req, opt);
+    }
+
+    public String[] getRequired() {
+        return required;
+    }
+
+    public String[] getOptional() {
+        return optional;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getEnterpriseNumber() {
+        return enterpriseNumber;
+    }
+
+    public boolean isReserved() {
+        return enterpriseNumber <= 0;
+    }
+
+    public String toString() {
+        return isReserved() ? name : name + "@" + enterpriseNumber;
+    }
+}
\ No newline at end of file
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java b/log4j2-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java
new file mode 100644
index 0000000..095cf49
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java
@@ -0,0 +1,233 @@
+/*
+ * 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.message;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Represents a Message that conforms to RFC 5424 (http://tools.ietf.org/html/rfc5424).
+ */
+public class StructuredDataMessage implements Message, Serializable {
+    private static final long serialVersionUID = 1703221292892071920L;
+
+    public static final String FULL = "full";
+
+    private Map data = new HashMap();
+
+    private StructuredDataId id;
+
+    private String message;
+
+    private String type;
+
+    public StructuredDataMessage(final String id, final String msg, final String type) {
+        this.id = new StructuredDataId(id, null, null);
+        this.message = msg;
+        this.type = type;
+    }
+
+    public StructuredDataMessage(final StructuredDataId id, final String msg, final String type) {
+        this.id = id;
+        this.message = msg;
+        this.type = type;
+    }
+
+    protected StructuredDataMessage() {
+
+    }
+
+    public StructuredDataId getId() {
+        return id;
+    }
+
+    protected void setId(String id) {
+        this.id = new StructuredDataId(id, null, null);
+    }
+
+    protected void setId(StructuredDataId id) {
+        this.id = id;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    protected void setType(String type) {
+        if (type.length() > 32) {
+            throw new IllegalArgumentException("Structured data type exceeds maximum length of 32 characters: " + type);
+        }
+        this.type = type;
+    }
+
+    public Object[] getParameters() {
+        return data.values().toArray();
+    }
+
+    public String getMessageFormat() {
+        return message;
+    }
+
+    protected void setMessageFormat(String msg) {
+        this.message = msg;
+    }
+
+    public Map getData() {
+        return Collections.unmodifiableMap(data);
+    }
+
+    public void clear() {
+        data.clear();
+    }
+
+    public void put(String key, String value) {
+        if (value == null) {
+            throw new IllegalArgumentException("No value provided for key " + key);
+        }
+        if (value.length() > 32) {
+            throw new IllegalArgumentException("Structured data values are limited to 32 characters. key: " + key +
+                " value: " + value);
+        }
+        data.put(key, value);
+    }
+
+    public void putAll(Map map) {
+        data.putAll(map);
+    }
+
+    public String get(String key) {
+        return (String) data.get(key);
+    }
+
+    public String remove(String key) {
+        return (String) data.remove(key);
+    }
+
+    /**
+     * Format the Structured data as described in RFC 5424.
+     *
+     * @return The formatted String.
+     */
+    public final String asString() {
+        return asString(FULL, null);
+    }
+
+    /**
+     * Format the Structured data as described in RFC 5424.
+     *
+     * @param format The format identifier. Ignored in this implementation.
+     * @return The formatted String.
+     */
+    public String asString(String format) {
+        return asString(format, null);
+    }
+
+    /**
+     * Format the Structured data as described in RFC 5424.
+     *
+     * @param format           "full" will include the type and message. null will return only the STRUCTURED-DATA as
+     *                         described in RFC 5424
+     * @param structuredDataId The SD-ID as described in RFC 5424. If null the value in the StructuredData
+     *                         will be used.
+     * @return The formatted String.
+     */
+    public final String asString(String format, StructuredDataId structuredDataId) {
+        StringBuffer sb = new StringBuffer();
+        boolean full = FULL.equals(format);
+        if (full) {
+            String type = getType();
+            if (type == null) {
+                return sb.toString();
+            }
+            sb.append(getType()).append(" ");
+        }
+        StructuredDataId id = getId();
+        if (id != null) {
+            id = id.makeId(structuredDataId);
+        } else {
+            id = structuredDataId;
+        }
+        if (id == null || id.getName() == null) {
+            return sb.toString();
+        }
+        sb.append("[");
+        sb.append(id);
+        appendMap(getData(), sb);
+        sb.append("]");
+        if (full) {
+            String msg = getMessageFormat();
+            if (msg != null) {
+                sb.append(" ").append(msg);
+            }
+        }
+        return sb.toString();
+    }
+
+    public String getFormattedMessage() {
+        return asString(FULL, null);
+    }
+
+    private void appendMap(Map map, StringBuffer sb) {
+        Iterator iter = map.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            sb.append(" ");
+            sb.append(entry.getKey()).append("=\"").append(entry.getValue()).append("\"");
+        }
+    }
+
+    public String toString() {
+        return asString((String) null);
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        StructuredDataMessage that = (StructuredDataMessage) o;
+
+        if (data != null ? !data.equals(that.data) : that.data != null) {
+            return false;
+        }
+        if (type != null ? !type.equals(that.type) : that.type != null) {
+            return false;
+        }
+        if (id != null ? !id.equals(that.id) : that.id != null) {
+            return false;
+        }
+        if (message != null ? !message.equals(that.message) : that.message != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result = data != null ? data.hashCode() : 0;
+        result = 31 * result + (type != null ? type.hashCode() : 0);
+        result = 31 * result + (id != null ? id.hashCode() : 0);
+        result = 31 * result + (message != null ? message.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java b/log4j2-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
new file mode 100644
index 0000000..7eb9373
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
@@ -0,0 +1,1018 @@
+/*
+ * 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.spi;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.ObjectMessage;
+import org.apache.logging.log4j.message.ParameterizedMessage;
+import org.apache.logging.log4j.message.SimpleMessage;
+
+/**
+ *
+ */
+public abstract class AbstractLogger implements Logger {
+
+    protected String getFQCN() {
+        return AbstractLogger.class.getName();
+    }
+
+    /**
+     * Log entry to a method.
+     *
+     * @param params The parameters to the method.
+     */
+    public void entry(Object... params) {
+        if (isEnabled(Level.TRACE, Logger.ENTRY_MARKER, (Object)null, null)) {
+            log(Logger.ENTRY_MARKER, getFQCN(), Level.TRACE, entryMsg(params.length, params), null);
+        }
+    }
+
+    /**
+     * Log exit from a method.
+     */
+    public void exit() {
+        if (isEnabled(Level.TRACE, Logger.EXIT_MARKER, (Object)null, null)) {
+            log(Logger.EXIT_MARKER, getFQCN(), Level.TRACE, exitMsg(null), null);
+        }
+    }
+
+    /**
+     * Log exiting from a method with the result.
+     *
+     * @param result The result being returned from the method call.
+     */
+    public void exit(Object result) {
+        if (isEnabled(Level.TRACE, Logger.EXIT_MARKER, (Object)null, null)) {
+            log(Logger.EXIT_MARKER, getFQCN(), Level.TRACE, exitMsg(result), null);
+        }
+    }
+
+    /**
+     * Log an exception or error to be thrown.
+     *
+     * @param t The Throwable.
+     */
+    public void throwing(Throwable t) {
+        if (isEnabled(Level.ERROR, Logger.THROWING_MARKER, (Object)null, null)) {
+            log(Logger.THROWING_MARKER, getFQCN(), Level.ERROR, new SimpleMessage("throwing"), t);
+        }
+    }
+
+
+    /**
+     * Log an exception or error to be thrown.
+     *
+     * @param level The logging Level.
+     * @param t     The Throwable.
+     */
+    public void throwing(Level level, Throwable t) {
+        if (isEnabled(level, Logger.THROWING_MARKER, (Object)null, null)) {
+            log(Logger.THROWING_MARKER, getFQCN(), level, new SimpleMessage("throwing"), t);
+        }
+    }
+
+    /**
+     * Log an exception or error that has been caught.
+     *
+     * @param t The Throwable.
+     */
+    public void catching(Throwable t) {
+        if (isEnabled(Level.DEBUG, Logger.THROWING_MARKER, (Object)null, null)) {
+            log(Logger.THROWING_MARKER, getFQCN(), Level.DEBUG, new SimpleMessage("catching"), t);
+        }
+    }
+
+    /**
+     * Log an exception or error that has been caught.
+     *
+     * @param level The logging Level.
+     * @param t     The Throwable.
+     */
+    public void catching(Level level, Throwable t) {
+        if (isEnabled(level, Logger.THROWING_MARKER, (Object)null, null)) {
+            log(Logger.THROWING_MARKER, getFQCN(), level, new SimpleMessage("catching"), t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#TRACE TRACE} level.
+     *
+     * @param message the message object to log.
+     */
+    public void trace(String message) {
+        if (isEnabled(Level.TRACE, null, message)) {
+            log(null, getFQCN(), Level.TRACE, new SimpleMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>TRACE</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     * <p/>
+     * <p>
+     * See {@link #debug(String)} form for more detailed information.
+     * </p>
+     *
+     * @param message the message object to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void trace(String message, Throwable t) {
+        if (isEnabled(Level.TRACE, null, message, t)) {
+            log(null, getFQCN(), Level.TRACE, new SimpleMessage(message), t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#TRACE TRACE} level.
+     *
+     * @param message the message object to log.
+     */
+    public void trace(Object message) {
+        if (isEnabled(Level.TRACE, null, message, null)) {
+            log(null, getFQCN(), Level.TRACE, new ObjectMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>TRACE</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     * <p/>
+     * <p>
+     * See {@link #debug(String)} form for more detailed information.
+     * </p>
+     *
+     * @param message the message object to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void trace(Object message, Throwable t) {
+        if (isEnabled(Level.TRACE, null, message, t)) {
+            log(null, getFQCN(), Level.TRACE, new ObjectMessage(message), t);
+        }
+    }
+
+    /**
+     * Log a message with parameters at the <code>TRACE</code> level.
+     *
+     * @param message the message to log.
+     * @param params  parameters to the message.
+     */
+    public void trace(String message, Object... params) {
+        if (isEnabled(Level.TRACE, null, message, params)) {
+            log(null, getFQCN(), Level.TRACE, new ParameterizedMessage(message, params), null);
+        }
+    }
+
+    /**
+     * Check whether this Logger is enabled for the TRACE  Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         TRACE, <code>false</code> otherwise.
+     */
+    public boolean isTraceEnabled() {
+        return isEnabled(Level.TRACE, null, (Object)null, null);
+    }
+
+    /**
+     * Check whether this Logger is enabled for the TRACE  Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         TRACE, <code>false</code> otherwise.
+     */
+    public boolean isTraceEnabled(Marker marker) {
+        return isEnabled(Level.TRACE, marker, (Object)null, null);
+    }
+
+    /**
+     * Log a message with the specific Marker at the TRACE level.
+     *
+     * @param msg the message string to be logged
+     */
+    public void trace(Message msg) {
+        if (isEnabled(Level.TRACE, null, msg, null)) {
+            log(null, getFQCN(), Level.TRACE, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the TRACE level.
+     *
+     * @param msg the message string to be logged
+     * @param t   A Throwable or null.
+     */
+    public void trace(Message msg, Throwable t) {
+        if (isEnabled(Level.TRACE, null, msg, t)) {
+            log(null, getFQCN(), Level.TRACE, msg, t);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the TRACE level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     */
+    public void trace(Marker marker, Message msg) {
+        if (isEnabled(Level.TRACE, marker, msg, null)) {
+            log(marker, getFQCN(), Level.TRACE, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the TRACE level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     * @param t      A Throwable or null.
+     */
+    public void trace(Marker marker, Message msg, Throwable t) {
+        if (isEnabled(Level.TRACE, marker, msg, t)) {
+            log(marker, getFQCN(), Level.TRACE, msg, t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#DEBUG DEBUG} level.
+     *
+     * @param message the message object to log.
+     */
+    public void debug(String message) {
+        if (isEnabled(Level.DEBUG, null, message)) {
+            log(null, getFQCN(), Level.DEBUG, new SimpleMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>DEBUG</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     * @param message the message to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void debug(String message, Throwable t) {
+        if (isEnabled(Level.DEBUG, null, message, t)) {
+            log(null, getFQCN(), Level.DEBUG, new SimpleMessage(message), t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#DEBUG DEBUG} level.
+     *
+     * @param message the message object to log.
+     */
+    public void debug(Object message) {
+        if (isEnabled(Level.DEBUG, null, message, null)) {
+            log(null, getFQCN(), Level.DEBUG, new ObjectMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>DEBUG</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     * @param message the message to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void debug(Object message, Throwable t) {
+        if (isEnabled(Level.DEBUG, null, message, t)) {
+            log(null, getFQCN(), Level.DEBUG, new ObjectMessage(message), t);
+        }
+    }
+    /**
+     * Log a message with parameters at the <code>DEBUG</code> level.
+     *
+     * @param message the message to log.
+     * @param params  parameters to the message.
+     */
+    public void debug(String message, Object... params) {
+        if (isEnabled(Level.DEBUG, null, message, params)) {
+            log(null, getFQCN(), Level.DEBUG, new ParameterizedMessage(message, params), null);
+        }
+    }
+
+    /**
+     * Check whether this Logger is enabled for the DEBUG Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         DEBUG, <code>false</code> otherwise.
+     */
+    public boolean isDebugEnabled() {
+        return isEnabled(Level.DEBUG, null, null);
+    }
+
+    /**
+     * Check whether this Logger is enabled for the DEBUG Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         DEBUG, <code>false</code> otherwise.
+     */
+    public boolean isDebugEnabled(Marker marker) {
+        return isEnabled(Level.DEBUG, marker, (Object)null, null);
+    }
+
+    /**
+     * Log a message with the specific Marker at the DEBUG level.
+     *
+     * @param msg the message string to be logged
+     */
+    public void debug(Message msg) {
+        if (isEnabled(Level.TRACE, null, msg, null)) {
+            log(null, getFQCN(), Level.TRACE, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the DEBUG level.
+     *
+     * @param msg the message string to be logged
+     * @param t   A Throwable or null.
+     */
+    public void debug(Message msg, Throwable t) {
+        if (isEnabled(Level.TRACE, null, msg, t)) {
+            log(null, getFQCN(), Level.TRACE, msg, t);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the DEBUG level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     */
+    public void debug(Marker marker, Message msg) {
+        if (isEnabled(Level.DEBUG, marker, msg, null)) {
+            log(marker, getFQCN(), Level.DEBUG, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the DEBUG level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     * @param t      A Throwable or null.
+     */
+    public void debug(Marker marker, Message msg, Throwable t) {
+        if (isEnabled(Level.DEBUG, marker, msg, t)) {
+            log(marker, getFQCN(), Level.DEBUG, msg, t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#INFO INFO} level.
+     *
+     * @param message the message object to log.
+     */
+    public void info(String message) {
+        if (isEnabled(Level.INFO, null, message)) {
+            log(null, getFQCN(), Level.INFO, new SimpleMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>INFO</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     * @param message the message object to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void info(String message, Throwable t) {
+        if (isEnabled(Level.INFO, null, message, t)) {
+            log(null, getFQCN(), Level.INFO, new SimpleMessage(message), t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#INFO INFO} level.
+     *
+     * @param message the message object to log.
+     */
+    public void info(Object message) {
+        if (isEnabled(Level.INFO, null, message, null)) {
+            log(null, getFQCN(), Level.INFO, new ObjectMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>INFO</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     * @param message the message object to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void info(Object message, Throwable t) {
+        if (isEnabled(Level.INFO, null, message, t)) {
+            log(null, getFQCN(), Level.INFO, new ObjectMessage(message), t);
+        }
+    }
+
+    /**
+     * Log a message with parameters at the <code>INFO</code> level.
+     *
+     * @param message the message to log.
+     * @param params  parameters to the message.
+     */
+    public void info(String message, Object... params) {
+        if (isEnabled(Level.INFO, null, message, params)) {
+            log(null, getFQCN(), Level.INFO, new ParameterizedMessage(message, params), null);
+        }
+    }
+
+    /**
+     * Check whether this Logger is enabled for the INFO Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         INFO, <code>false</code> otherwise.
+     */
+    public boolean isInfoEnabled() {
+        return isEnabled(Level.INFO, null, (Object)null, null);
+    }
+
+    /**
+     * Check whether this Logger is enabled for the INFO Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         INFO, <code>false</code> otherwise.
+     */
+    public boolean isInfoEnabled(Marker marker) {
+        return isEnabled(Level.INFO, marker, (Object) null, null);
+    }
+
+    /**
+     * Log a message with the specific Marker at the TRACE level.
+     *
+     * @param msg the message string to be logged
+     */
+    public void info(Message msg) {
+        if (isEnabled(Level.INFO, null, msg, null)) {
+            log(null, getFQCN(), Level.INFO, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the INFO level.
+     *
+     * @param msg the message string to be logged
+     * @param t   A Throwable or null.
+     */
+    public void info(Message msg, Throwable t) {
+        if (isEnabled(Level.INFO, null, msg, t)) {
+            log(null, getFQCN(), Level.INFO, msg, t);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the INFO level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     */
+    public void info(Marker marker, Message msg) {
+        if (isEnabled(Level.INFO, null, msg, null)) {
+            log(marker, getFQCN(), Level.INFO, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the INFO level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     * @param t      A Throwable or null.
+     */
+    public void info(Marker marker, Message msg, Throwable t) {
+        if (isEnabled(Level.INFO, marker, msg, t)) {
+            log(marker, getFQCN(), Level.INFO, msg, t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#WARN WARN} level.
+     *
+     * @param message the message object to log.
+     */
+    public void warn(String message) {
+        if (isEnabled(Level.WARN, null, message)) {
+            log(null, getFQCN(), Level.WARN, new SimpleMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>WARN</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     * @param message the message object to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void warn(String message, Throwable t) {
+        if (isEnabled(Level.WARN, null, message, t)) {
+            log(null, getFQCN(), Level.DEBUG, new SimpleMessage(message), t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#WARN WARN} level.
+     *
+     * @param message the message object to log.
+     */
+    public void warn(Object message) {
+        if (isEnabled(Level.WARN, null, message, null)) {
+            log(null, getFQCN(), Level.WARN, new ObjectMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>WARN</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     * @param message the message object to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void warn(Object message, Throwable t) {
+        if (isEnabled(Level.WARN, null, message, t)) {
+            log(null, getFQCN(), Level.DEBUG, new ObjectMessage(message), t);
+        }
+    }
+
+    /**
+     * Log a message with parameters at the <code>WARN</code> level.
+     *
+     * @param message the message to log.
+     * @param params  parameters to the message.
+     */
+    public void warn(String message, Object... params) {
+        if (isEnabled(Level.WARN, null, message, params)) {
+            log(null, getFQCN(), Level.WARN, new ParameterizedMessage(message, params), null);
+        }
+    }
+
+    /**
+     * Check whether this Logger is enabled for the WARN Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         WARN, <code>false</code> otherwise.
+     */
+    public boolean isWarnEnabled() {
+        return isEnabled(Level.WARN, null, (Object)null, null);
+    }
+
+    /**
+     * Check whether this Logger is enabled for the WARN Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         WARN, <code>false</code> otherwise.
+     */
+    public boolean isWarnEnabled(Marker marker) {
+        return isEnabled(Level.WARN, marker, (Object)null, null);
+    }
+
+    /**
+     * Log a message with the specific Marker at the WARN level.
+     *
+     * @param msg the message string to be logged
+     */
+    public void warn(Message msg) {
+        if (isEnabled(Level.WARN, null, msg, null)) {
+            log(null, getFQCN(), Level.WARN, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the WARN level.
+     *
+     * @param msg the message string to be logged
+     * @param t   A Throwable or null.
+     */
+    public void warn(Message msg, Throwable t) {
+        if (isEnabled(Level.WARN, null, msg, t)) {
+            log(null, getFQCN(), Level.WARN, msg, t);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the WARN level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     */
+    public void warn(Marker marker, Message msg) {
+        if (isEnabled(Level.WARN, null, msg, null)) {
+            log(marker, getFQCN(), Level.WARN, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the WARN level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     * @param t      A Throwable or null.
+     */
+    public void warn(Marker marker, Message msg, Throwable t) {
+        if (isEnabled(Level.WARN, marker, msg, t)) {
+            log(marker, getFQCN(), Level.WARN, msg, t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#ERROR ERROR} level.
+     *
+     * @param message the message object to log.
+     */
+    public void error(String message) {
+        if (isEnabled(Level.ERROR, null, message)) {
+            log(null, getFQCN(), Level.ERROR, new SimpleMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>ERROR</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     * @param message the message object to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void error(String message, Throwable t) {
+        if (isEnabled(Level.ERROR, null, message, t)) {
+            log(null, getFQCN(), Level.ERROR, new SimpleMessage(message), t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#ERROR ERROR} level.
+     *
+     * @param message the message object to log.
+     */
+    public void error(Object message) {
+        if (isEnabled(Level.ERROR, null, message, null)) {
+            log(null, getFQCN(), Level.ERROR, new ObjectMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>ERROR</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     * @param message the message object to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void error(Object message, Throwable t) {
+        if (isEnabled(Level.ERROR, null, message, t)) {
+            log(null, getFQCN(), Level.ERROR, new ObjectMessage(message), t);
+        }
+    }
+
+    /**
+     * Log a message with parameters at the <code>ERROR</code> level.
+     *
+     * @param message the message to log.
+     * @param params  parameters to the message.
+     */
+    public void error(String message, Object... params) {
+        if (isEnabled(Level.ERROR, null, message, params)) {
+            log(null, getFQCN(), Level.ERROR, new ParameterizedMessage(message, params), null);
+        }
+    }
+
+    /**
+     * Check whether this Logger is enabled for the ERROR Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         ERROR, <code>false</code> otherwise.
+     */
+    public boolean isErrorEnabled() {
+        return isEnabled(Level.ERROR, null, (Object)null, null);
+    }
+
+    /**
+     * Check whether this Logger is enabled for the ERROR Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         ERROR, <code>false</code> otherwise.
+     */
+    public boolean isErrorEnabled(Marker marker) {
+        return isEnabled(Level.ERROR, marker, (Object)null, null);
+    }
+
+    /**
+     * Log a message with the specific Marker at the ERROR level.
+     *
+     * @param msg the message string to be logged
+     */
+    public void error(Message msg) {
+        if (isEnabled(Level.ERROR, null, msg, null)) {
+            log(null, getFQCN(), Level.ERROR, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the ERROR level.
+     *
+     * @param msg the message string to be logged
+     * @param t   A Throwable or null.
+     */
+    public void error(Message msg, Throwable t) {
+        if (isEnabled(Level.ERROR, null, msg, t)) {
+            log(null, getFQCN(), Level.ERROR, msg, t);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the ERROR level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     */
+    public void error(Marker marker, Message msg) {
+        if (isEnabled(Level.ERROR, null, msg, null)) {
+            log(null, getFQCN(), Level.ERROR, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the ERROR level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     * @param t      A Throwable or null.
+     */
+    public void error(Marker marker, Message msg, Throwable t) {
+        if (isEnabled(Level.TRACE, marker, msg, t)) {
+            log(marker, getFQCN(), Level.TRACE, msg, t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#FATAL FATAL} level.
+     *
+     * @param message the message object to log.
+     */
+    public void fatal(String message) {
+        if (isEnabled(Level.FATAL, null, message)) {
+            log(null, getFQCN(), Level.FATAL, new SimpleMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>FATAL</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     * @param message the message object to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void fatal(String message, Throwable t) {
+        if (isEnabled(Level.FATAL, null, message, t)) {
+            log(null, getFQCN(), Level.FATAL, new SimpleMessage(message), t);
+        }
+    }
+
+    /**
+     * Log a message object with the {@link org.apache.logging.log4j.Level#FATAL FATAL} level.
+     *
+     * @param message the message object to log.
+     */
+    public void fatal(Object message) {
+        if (isEnabled(Level.FATAL, null, message, null)) {
+            log(null, getFQCN(), Level.FATAL, new ObjectMessage(message), null);
+        }
+    }
+
+    /**
+     * Log a message at the <code>FATAL</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     * @param message the message object to log.
+     * @param t       the exception to log, including its stack trace.
+     */
+    public void fatal(Object message, Throwable t) {
+        if (isEnabled(Level.FATAL, null, message, t)) {
+            log(null, getFQCN(), Level.FATAL, new ObjectMessage(message), t);
+        }
+    }
+    /**
+     * Log a message with parameters at the <code>FATAL</code> level.
+     *
+     * @param message the message to log.
+     * @param params  parameters to the message.
+     */
+    public void fatal(String message, Object... params) {
+        if (isEnabled(Level.FATAL, null, message, params)) {
+            log(null, getFQCN(), Level.FATAL, new ParameterizedMessage(message, params), null);
+        }
+    }
+
+    /**
+     * Check whether this Logger is enabled for the FATAL Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         FATAL, <code>false</code> otherwise.
+     */
+    public boolean isFatalEnabled() {
+        return isEnabled(Level.ERROR, null, (Object)null, null);
+    }
+
+    /**
+     * Check whether this Logger is enabled for the FATAL Level.
+     *
+     * @return boolean - <code>true</code> if this Logger is enabled for level
+     *         FATAL, <code>false</code> otherwise.
+     */
+    public boolean isFatalEnabled(Marker marker) {
+        return isEnabled(Level.FATAL, marker, (Object)null, null);
+    }
+
+    /**
+     * Log a message with the specific Marker at the FATAL level.
+     *
+     * @param msg the message string to be logged
+     */
+    public void fatal(Message msg) {
+        if (isEnabled(Level.FATAL, null, msg, null)) {
+            log(null, getFQCN(), Level.FATAL, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the FATAL level.
+     *
+     * @param msg the message string to be logged
+     * @param t   A Throwable or null.
+     */
+    public void fatal(Message msg, Throwable t) {
+        if (isEnabled(Level.FATAL, null, msg, t)) {
+            log(null, getFQCN(), Level.FATAL, msg, t);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the FATAL level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     */
+    public void fatal(Marker marker, Message msg) {
+        if (isEnabled(Level.FATAL, null, msg, null)) {
+            log(null, getFQCN(), Level.FATAL, msg, null);
+        }
+    }
+
+    /**
+     * Log a message with the specific Marker at the FATAL level.
+     *
+     * @param marker the marker data specific to this log statement
+     * @param msg    the message string to be logged
+     * @param t      A Throwable or null.
+     */
+    public void fatal(Marker marker, Message msg, Throwable t) {
+        if (isEnabled(Level.FATAL, marker, msg, t)) {
+            log(marker, getFQCN(), Level.FATAL, msg, t);
+        }
+    }
+
+    /**
+     * Log a message with location information.
+     *
+     * @param marker The Marker
+     * @param fqcn   The fully qualified class name of the <b>caller</b>
+     * @param level  The logging level
+     * @param data   The Message.
+     * @param t      A Throwable or null.
+     */
+    protected abstract void log(Marker marker, String fqcn, Level level, Message data, Throwable t);
+
+    /*
+     * Instead of one single method with Object... declared the following methods explicitly specify
+     * parameters because they perform dramatically better than having the JVM convert them to an
+     * array.
+     */
+
+    /**
+     * Determine if logging is enabled.
+     * @param level The logging Level to check.
+     * @param marker A Marker or null.
+     * @param data The message.
+     * @return True if logging is enabled, false otherwise.
+     */
+    protected abstract boolean isEnabled(Level level, Marker marker, String data);
+
+    /**
+     * Determine if logging is enabled.
+     * @param level The logging Level to check.
+     * @param marker A Marker or null.
+     * @param data The message.
+     * @param t A Throwable.
+     * @return True if logging is enabled, false otherwise.
+     */
+    protected abstract boolean isEnabled(Level level, Marker marker, String data, Throwable t);
+
+    /**
+     * Determine if logging is enabled.
+     * @param level The logging Level to check.
+     * @param marker A Marker or null.
+     * @param data The message.
+     * @param p1 The first parameter.
+     * @return True if logging is enabled, false otherwise.
+     */
+    protected abstract boolean isEnabled(Level level, Marker marker, String data, Object p1);
+
+    /**
+     * Determine if logging is enabled.
+     * @param level The logging Level to check.
+     * @param marker A Marker or null.
+     * @param data The message.
+     * @param p1 The first parameter.
+     * @param p2 The second parameter.
+     * @return True if logging is enabled, false otherwise.
+     */
+    protected abstract boolean isEnabled(Level level, Marker marker, String data, Object p1, Object p2);
+
+    /**
+     * Determine if logging is enabled.
+     * @param level The logging Level to check.
+     * @param marker A Marker or null.
+     * @param data The message.
+     * @param p1 The first parameter.
+     * @param p2 The second parameter.
+     * @param p3 The third parameter.
+     * @return True if logging is enabled, false otherwise.
+     */
+    protected abstract boolean isEnabled(Level level, Marker marker, String data, Object p1, Object p2, Object p3);
+
+
+    /**
+     * Determine if logging is enabled.
+     * @param level The logging Level to check.
+     * @param marker A Marker or null.
+     * @param data The message.
+     * @param p1 The first parameter.
+     * @param p2 The second parameter.
+     * @param p3 The third parameter.
+     * @param params More message parameters.
+     * @return True if logging is enabled, false otherwise.
+     */
+    protected abstract boolean isEnabled(Level level, Marker marker, String data, Object p1, Object p2,
+                                         Object p3, Object... params);
+
+    /**
+     * Determine if logging is enabled.
+     * @param level The logging Level to check.
+     * @param marker A Marker or null.
+     * @param data The message.
+     * @param t A Throwable.
+     * @return True if logging is enabled, false otherwise.
+     */
+    protected abstract boolean isEnabled(Level level, Marker marker, Object data, Throwable t);
+
+    /**
+     * Determine if logging is enabled.
+     * @param level The logging Level to check.
+     * @param marker A Marker or null.
+     * @param data The Message.
+     * @param t A Throwable.
+     * @return True if logging is enabled, false otherwise.
+     */
+    protected abstract boolean isEnabled(Level level, Marker marker, Message data, Throwable t);
+
+    private Message entryMsg(int count, Object... params) {
+        if (count == 0) {
+            return new SimpleMessage(" entry");
+        }
+        StringBuilder sb = new StringBuilder(" entry parms(");
+        int i = 0;
+        for (Object parm : params) {
+            if (parm != null) {
+                sb.append(parm.toString());
+            } else {
+                sb.append("null");
+            }
+            if (++i < params.length) {
+                sb.append(", ");
+            }
+        }
+        sb.append(")");
+        return new SimpleMessage(sb.toString());
+    }
+
+    private Message exitMsg(Object result) {
+        if (result == null) {
+            return new SimpleMessage(" exit");
+        }
+        return new SimpleMessage(" exit with (" + result + ")");
+    }
+}
diff --git a/log4j2-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java b/log4j2-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
new file mode 100644
index 0000000..d15ba1e
--- /dev/null
+++ b/log4j2-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
@@ -0,0 +1,11 @@
+package org.apache.logging.log4j.spi;
+
+import org.apache.logging.log4j.Logger;
+
+/**
+ *
+ */
+public interface LoggerContext {
+
+    Logger getLogger(String name);
+}
diff --git a/log4j2-api/src/main/resources/LICENSE b/log4j2-api/src/main/resources/LICENSE
new file mode 100644
index 0000000..6279e52
--- /dev/null
+++ b/log4j2-api/src/main/resources/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 1999-2005 The Apache Software Foundation
+
+   Licensed 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.
diff --git a/log4j2-api/src/main/resources/NOTICE b/log4j2-api/src/main/resources/NOTICE
new file mode 100644
index 0000000..6233b56
--- /dev/null
+++ b/log4j2-api/src/main/resources/NOTICE
@@ -0,0 +1,5 @@
+Apache log4j Enhanced PatternLayout for log4j 1.2.x
+Copyright 2007 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
diff --git a/log4j2-api/src/test/java/org/apache/logging/log4j/LoggerTest.java b/log4j2-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
new file mode 100644
index 0000000..c02b2f8
--- /dev/null
+++ b/log4j2-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.message.StructuredDataMessage;
+import org.junit.Test;
+
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ *
+ */
+public class LoggerTest {
+
+    Logger logger = LogManager.getLogger("LoggerTest");
+    @Test
+    public void basicFlow() {
+        logger.entry();
+        logger.exit();
+    }
+
+    @Test
+    public void throwing() {
+        logger.throwing(new IllegalArgumentException("Test Exception"));
+    }
+
+    @Test
+    public void catching() {
+        try {
+            throw new NullPointerException();
+        } catch (Exception e) {
+            logger.catching(e);
+        }
+    }
+
+    @Test
+    public void debug() {
+        logger.debug("Debug message");
+    }
+
+    @Test
+    public void debugObject() {
+        logger.debug(new Date());
+    }
+
+    @Test
+    public void debugWithParms() {
+        logger.debug("Hello, {}", "World");
+    }
+
+    @Test
+    public void mdc() {
+
+        MDC.put("TestYear", new Integer(2010));
+        logger.debug("Debug message");
+        MDC.clear();
+        logger.debug("Debug message");
+    }
+
+    @Test
+    public void structuredData() {
+        MDC.put("loginId", "JohnDoe");
+        MDC.put("ipAddress", "192.168.0.120");
+        MDC.put("locale", Locale.US.getDisplayName());
+        StructuredDataMessage msg = new StructuredDataMessage("Audit@18060", "Transfer Complete", "Transfer");
+        msg.put("ToAccount", "123456");
+        msg.put("FromAccount", "123457");
+        msg.put("Amount", "200.00");
+        logger.info(Marker.getMarker("EVENT"), msg);
+        MDC.clear();
+    }
+}
diff --git a/log4j2-api/src/test/java/org/apache/logging/log4j/SimpleLogger.java b/log4j2-api/src/test/java/org/apache/logging/log4j/SimpleLogger.java
new file mode 100644
index 0000000..0a36e73
--- /dev/null
+++ b/log4j2-api/src/test/java/org/apache/logging/log4j/SimpleLogger.java
@@ -0,0 +1,105 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.spi.AbstractLogger;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Map;
+
+/**
+ *
+ */
+public class SimpleLogger extends AbstractLogger {
+    @Override
+    protected String getFQCN() {
+        return SimpleLogger.class.getName();
+    }
+
+    @Override
+    public void log(Marker marker, String fqcn, Level level, Message msg, Throwable throwable) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(" ");
+        sb.append(level.toString());
+        sb.append(" ");
+        sb.append(msg.getFormattedMessage());
+        Map<String, Object> mdc = MDC.getContext();
+        if (mdc.size() > 0) {
+            sb.append(" ");
+            sb.append(mdc.toString());
+            sb.append(" ");
+        }
+        Object[] params = msg.getParameters();
+        Throwable t;
+        if (throwable == null && params != null && params[params.length -1] instanceof Throwable ) {
+            t = (Throwable) params[params.length - 1];
+        } else {
+            t = throwable;
+        }
+        if (t != null) {
+            sb.append(" ");
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            t.printStackTrace(new PrintStream(baos));
+            sb.append(baos.toString());
+        }
+        System.out.println(sb.toString());
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Object p1, Object p2, Object p3,
+                                Object...params) {
+        return true;
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg) {
+        return true;
+    }
+
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Throwable t) {
+        return true;
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Object p1) {
+        return true;
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Object p1, Object p2) {
+        return true;
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Object p1, Object p2, Object p3) {
+        return true;
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, Object msg, Throwable t) {
+        return true;
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, Message msg, Throwable t) {
+        return true;
+    }
+}
diff --git a/log4j2-api/src/test/java/org/apache/logging/log4j/SimpleLoggerContext.java b/log4j2-api/src/test/java/org/apache/logging/log4j/SimpleLoggerContext.java
new file mode 100644
index 0000000..7123d1f
--- /dev/null
+++ b/log4j2-api/src/test/java/org/apache/logging/log4j/SimpleLoggerContext.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.spi.LoggerContext;
+
+/**
+ *
+ */
+public class SimpleLoggerContext implements LoggerContext {
+    private Logger logger = new SimpleLogger();
+
+    public Logger getLogger(String name) {
+        return logger;
+    }
+}
diff --git a/log4j2-api/src/test/resources/META-INF/log4j-provider.xml b/log4j2-api/src/test/resources/META-INF/log4j-provider.xml
new file mode 100644
index 0000000..5fbcf63
--- /dev/null
+++ b/log4j2-api/src/test/resources/META-INF/log4j-provider.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+    <entry key="LoggerContextClass">org.apache.logging.log4j.SimpleLoggerContext</entry>
+    <entry key="Log4jAPIVersion">1.99.0</entry>
+</properties>
\ No newline at end of file
diff --git a/log4j2-core/LICENSE b/log4j2-core/LICENSE
new file mode 100644
index 0000000..6279e52
--- /dev/null
+++ b/log4j2-core/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 1999-2005 The Apache Software Foundation
+
+   Licensed 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.
diff --git a/log4j2-core/NOTICE b/log4j2-core/NOTICE
new file mode 100644
index 0000000..6233b56
--- /dev/null
+++ b/log4j2-core/NOTICE
@@ -0,0 +1,5 @@
+Apache log4j Enhanced PatternLayout for log4j 1.2.x
+Copyright 2007 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
diff --git a/log4j2-core/build.xml b/log4j2-core/build.xml
new file mode 100644
index 0000000..5b987de
--- /dev/null
+++ b/log4j2-core/build.xml
@@ -0,0 +1,123 @@
+<!--
+ 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.
+
+-->
+
+<!--
+
+This is a minimal build file to support Gump.
+Use of Maven to build this component is recommended.
+
+-->
+<project default="test">
+    <!--  use build.properties file or command line to override these properties  -->
+    <property file="build.properties"/>
+	
+	<!--  project details  -->
+    <property name="project.name" value="apache-log4j-experimental-pattern-layout"/>
+    <property name="project.title" value="Enhanced Pattern Layout Component for log4j X"/>
+    <property name="project.version" value="0.1-SNAPSHOT"/>
+    <property name="project.jar" value="${project.name}-${project.version}.jar"/>
+    
+    <!--  Location of local Maven 2 repository   -->
+    <property name="m2_repo" location="${user.home}/.m2/repository"/>
+
+	<!--  Versions for dependencies   -->
+    <property name="log4j.version" value="1.2.14"/>
+    <property name="junit.version" value="4.3.1"/>
+    <property name="oro.version" value="2.0.8"/>
+	
+	<!--  Dependency locations - assumed to be in Maven 2 repository   -->
+    <property name="junit.jar" 
+       location="${m2_repo}/junit/junit/${junit.version}/junit-${junit.version}.jar"/>
+    <property name="log4j.jar" 
+       location="${m2_repo}/log4j/log4j/${log4j.version}/log4j-${log4j.version}.jar"/>
+    <property name="oro.jar" 
+       location="${m2_repo}/oro/oro/${oro.version}/oro-${oro.version}.jar"/>
+       
+
+    <!--   Java compiler settings   -->
+    <property name="javac.source" value="1.5"/>
+    <property name="javac.target" value="1.5"/>
+    <property name="javac.deprecation" value="true"/>
+    <property name="javac.debug" value="true"/>
+       
+    <target name="init"/>
+    
+    <target name="clean" depends="init" description="Clean up generated files">
+    	<delete dir="target"/>
+    </target>
+    
+    
+    <target name="compile" depends="init" description="Compile implementation files">
+        <mkdir dir="target/classes"/>
+    	<javac destdir="target/classes"
+           srcdir="src/main/java"
+    	   deprecation="${javac.deprecation}"
+    	   debug="${javac.debug}"
+    	   target="${javac.target}"
+    	   source="${javac.source}"
+    	   classpath="${log4j.jar}"/>
+    	<copy todir="target/classes">
+    	    <fileset dir="src/main/resources"/>
+    	</copy>
+    </target>
+    
+    <target name="jar" depends="compile" description="Create jar">
+    	<jar destfile="target/${project.jar}"
+    	     basedir="target/classes">
+    	  	<manifest>
+    			<attribute name="Built-By" value="${user.name}"/>
+    			<section name="common">
+      				<attribute name="Specification-Title" value="${project.title}"/>
+      				<attribute name="Specification-Version" value="${project.version}"/>
+      				<attribute name="Specification-Vendor" value="Apache Software Foundation"/>
+      				<attribute name="Implementation-Title" value="${project.title}"/>
+      				<attribute name="Implementation-Version" value="${project.version}"/> 
+      				<attribute name="Implementation-Vendor" value="Apache Software Foundation"/>
+    			</section>
+    		</manifest>    	     
+    	</jar>
+    </target>    
+
+    <target name="test-compile" depends="compile" description="Compile test files">
+        <mkdir dir="target/test-classes"/>
+    	<javac destdir="target/test-classes"
+           srcdir="src/test/java"
+    	   deprecation="${javac.deprecation}"
+    	   debug="${javac.debug}"
+    	   target="${javac.target}"
+    	   source="${javac.source}"
+    	   classpath="${log4j.jar}:${junit.jar}:target/classes:${oro.jar}"/>
+    	<copy todir="target/test-classes">
+    		<fileset dir="src/test/resources"/>
+    	</copy>
+    </target>    
+
+
+    <target name="test" depends="test-compile" description="Run unit tests">
+    	<junit printsummary="yes">
+    	    <classpath path="target/test-classes:target/classes:${log4j.jar}:${oro.jar}"/>
+    		<batchtest>
+    			<fileset dir="src/test/java/">
+    				<include name="**/*TestCase.java"/>
+    				<include name="**/*Test.java"/>
+    			</fileset>
+    	    </batchtest>
+    	    <formatter type="plain" usefile="false"/>
+    	</junit>
+    </target>    
+</project>
diff --git a/log4j2-core/output/PatternParser_mdc b/log4j2-core/output/PatternParser_mdc
new file mode 100644
index 0000000..5c64114
--- /dev/null
+++ b/log4j2-core/output/PatternParser_mdc
@@ -0,0 +1,12 @@
+starting mdc pattern test
+empty mdc, no key specified in pattern : {}
+empty mdc, key1 in pattern : 
+empty mdc, key2 in pattern : 
+empty mdc, key3 in pattern : 
+empty mdc, key1, key2, and key3 in pattern : ,,
+filled mdc, no key specified in pattern : {key1=value1, key2=value2}
+filled mdc, key1 in pattern : value1
+filled mdc, key2 in pattern : value2
+filled mdc, key3 in pattern : 
+filled mdc, key1, key2, and key3 in pattern : value1,value2,
+finished mdc pattern test
diff --git a/log4j2-core/output/filtered b/log4j2-core/output/filtered
new file mode 100644
index 0000000..c7104dc
--- /dev/null
+++ b/log4j2-core/output/filtered
@@ -0,0 +1,12 @@
+starting mdc pattern test
+empty mdc, no key specified in pattern : {}
+empty mdc, key1 in pattern : 
+empty mdc, key2 in pattern : 
+empty mdc, key3 in pattern : 
+empty mdc, key1, key2, and key3 in pattern : ,,
+filled mdc, no key specified in pattern : {{key1,value1}{key2,value2}}
+filled mdc, key1 in pattern : value1
+filled mdc, key2 in pattern : value2
+filled mdc, key3 in pattern : 
+filled mdc, key1, key2, and key3 in pattern : value1,value2,
+finished mdc pattern test
diff --git a/log4j2-core/output/patternLayout.mdc.2 b/log4j2-core/output/patternLayout.mdc.2
new file mode 100644
index 0000000..ba7cd80
--- /dev/null
+++ b/log4j2-core/output/patternLayout.mdc.2
@@ -0,0 +1,12 @@
+starting mdc pattern test
+empty mdc, no key specified in pattern : {}
+empty mdc, key1 in pattern : 
+empty mdc, key2 in pattern : 
+empty mdc, key3 in pattern : 
+empty mdc, key1, key2, and key3 in pattern : ,,
+filled mdc, no key specified in pattern : {{key2,value2}{key1,value1}}
+filled mdc, key1 in pattern : value1
+filled mdc, key2 in pattern : value2
+filled mdc, key3 in pattern : 
+filled mdc, key1, key2, and key3 in pattern : value1,value2,
+finished mdc pattern test
diff --git a/log4j2-core/output/patternLayout16.log b/log4j2-core/output/patternLayout16.log
new file mode 100644
index 0000000..055b59c
--- /dev/null
+++ b/log4j2-core/output/patternLayout16.log
@@ -0,0 +1,145 @@
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 0
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 0
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 1
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 1
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 2
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 2
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 3
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 3
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 4
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 4
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 5
+java.lang.Exception: Just testing
+	at org.apache.log4j.PatternLayoutTestCase.common(PatternLayoutTestCase.java:431)
+	at org.apache.log4j.PatternLayoutTestCase.test16(PatternLayoutTestCase.java:394)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at junit.framework.TestCase.runTest(TestCase.java:168)
+	at junit.framework.TestCase.runBare(TestCase.java:134)
+	at junit.framework.TestResult$1.protect(TestResult.java:110)
+	at junit.framework.TestResult.runProtected(TestResult.java:128)
+	at junit.framework.TestResult.run(TestResult.java:113)
+	at junit.framework.TestCase.run(TestCase.java:124)
+	at junit.framework.TestSuite.runTest(TestSuite.java:232)
+	at junit.framework.TestSuite.run(TestSuite.java:227)
+	at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:76)
+	at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
+	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
+	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
+	at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
+	at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 6
+java.lang.Exception: Just testing
+	at org.apache.log4j.PatternLayoutTestCase.common(PatternLayoutTestCase.java:431)
+	at org.apache.log4j.PatternLayoutTestCase.test16(PatternLayoutTestCase.java:394)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at junit.framework.TestCase.runTest(TestCase.java:168)
+	at junit.framework.TestCase.runBare(TestCase.java:134)
+	at junit.framework.TestResult$1.protect(TestResult.java:110)
+	at junit.framework.TestResult.runProtected(TestResult.java:128)
+	at junit.framework.TestResult.run(TestResult.java:113)
+	at junit.framework.TestCase.run(TestCase.java:124)
+	at junit.framework.TestSuite.runTest(TestSuite.java:232)
+	at junit.framework.TestSuite.run(TestSuite.java:227)
+	at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:76)
+	at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
+	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
+	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
+	at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
+	at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 7
+java.lang.Exception: Just testing
+	at org.apache.log4j.PatternLayoutTestCase.common(PatternLayoutTestCase.java:431)
+	at org.apache.log4j.PatternLayoutTestCase.test16(PatternLayoutTestCase.java:394)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at junit.framework.TestCase.runTest(TestCase.java:168)
+	at junit.framework.TestCase.runBare(TestCase.java:134)
+	at junit.framework.TestResult$1.protect(TestResult.java:110)
+	at junit.framework.TestResult.runProtected(TestResult.java:128)
+	at junit.framework.TestResult.run(TestResult.java:113)
+	at junit.framework.TestCase.run(TestCase.java:124)
+	at junit.framework.TestSuite.runTest(TestSuite.java:232)
+	at junit.framework.TestSuite.run(TestSuite.java:227)
+	at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:76)
+	at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
+	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
+	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
+	at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
+	at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 8
+java.lang.Exception: Just testing
+	at org.apache.log4j.PatternLayoutTestCase.common(PatternLayoutTestCase.java:431)
+	at org.apache.log4j.PatternLayoutTestCase.test16(PatternLayoutTestCase.java:394)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at junit.framework.TestCase.runTest(TestCase.java:168)
+	at junit.framework.TestCase.runBare(TestCase.java:134)
+	at junit.framework.TestResult$1.protect(TestResult.java:110)
+	at junit.framework.TestResult.runProtected(TestResult.java:128)
+	at junit.framework.TestResult.run(TestResult.java:113)
+	at junit.framework.TestCase.run(TestCase.java:124)
+	at junit.framework.TestSuite.runTest(TestSuite.java:232)
+	at junit.framework.TestSuite.run(TestSuite.java:227)
+	at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:76)
+	at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
+	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
+	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
+	at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
+	at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)
+2009-11-20 07:53:32Z 2009-11-20 01:53:32-0600 - Message 9
+java.lang.Exception: Just testing
+	at org.apache.log4j.PatternLayoutTestCase.common(PatternLayoutTestCase.java:431)
+	at org.apache.log4j.PatternLayoutTestCase.test16(PatternLayoutTestCase.java:394)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at junit.framework.TestCase.runTest(TestCase.java:168)
+	at junit.framework.TestCase.runBare(TestCase.java:134)
+	at junit.framework.TestResult$1.protect(TestResult.java:110)
+	at junit.framework.TestResult.runProtected(TestResult.java:128)
+	at junit.framework.TestResult.run(TestResult.java:113)
+	at junit.framework.TestCase.run(TestCase.java:124)
+	at junit.framework.TestSuite.runTest(TestSuite.java:232)
+	at junit.framework.TestSuite.run(TestSuite.java:227)
+	at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:76)
+	at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
+	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
+	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
+	at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
+	at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)
diff --git a/log4j2-core/output/temp b/log4j2-core/output/temp
new file mode 100644
index 0000000..19e258a
--- /dev/null
+++ b/log4j2-core/output/temp
@@ -0,0 +1 @@
+DEBUG - Hello World {{key2,va12}{key1,va11}}
diff --git a/log4j2-core/pom.xml b/log4j2-core/pom.xml
new file mode 100644
index 0000000..48a4515
--- /dev/null
+++ b/log4j2-core/pom.xml
@@ -0,0 +1,53 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.logging</groupId>
+    <artifactId>log4j2</artifactId>
+    <version>1.99.0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.apache.logging</groupId>
+  <artifactId>log4j2-core</artifactId>
+  <packaging>jar</packaging>
+  <name>Enhanced Pattern Layout Experiments</name>
+  <description>Experiments on Pattern Layout.</description>
+  <url>http://logging.apache.org/log4j/experimental</url>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.3.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging</groupId>
+      <artifactId>log4j2-api</artifactId>
+      <version>1.99.0-SNAPSHOT</version>
+    </dependency>
+	<dependency>
+      <groupId>oro</groupId>
+      <artifactId>oro</artifactId>
+      <version>2.0.8</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>
+
diff --git a/log4j2-core/src/changes/changes.xml b/log4j2-core/src/changes/changes.xml
new file mode 100644
index 0000000..3dc188b
--- /dev/null
+++ b/log4j2-core/src/changes/changes.xml
Binary files differ
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/Appender.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/Appender.java
new file mode 100644
index 0000000..92e73d6
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/Appender.java
@@ -0,0 +1,128 @@
+/*
+ * 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;
+
+import java.util.List;
+
+/**
+ *
+ */
+public interface Appender {
+    /**
+     * Add a filter to the end of the filter list.
+     *
+     * @param filter The Filter to add.
+     */
+    void addFilter(Filter filter);
+
+    /**
+     * Returns the head Filter. The Filters are organized in a linked list
+     * and so all Filters on this Appender are available through the result.
+     *
+     * @return the head Filter or null, if no Filters are present
+     */
+    Filter getFilter();
+
+    /**
+     * Clear the list of filters by removing all the filters in it.
+     */
+    void clearFilters();
+
+    /**
+     * Return the list of Filters associated with this appender.
+     *
+     * @return
+     */
+    List<Filter> getFilters();
+
+    /**
+     * Release any resources allocated within the appender such as file
+     * handles, network connections, etc.
+     * <p/>
+     * <p>It is a programming error to append to a closed appender.
+     */
+    void close();
+
+    /**
+     * Log in <code>Appender</code> specific way. When appropriate,
+     * Loggers will call the <code>doAppend</code> method of appender
+     * implementations in order to log.
+     *
+     * @param event The LogEvent.
+     */
+    void append(LogEvent event);
+
+
+    /**
+     * Get the name of this appender.
+     *
+     * @return name, may be null.
+     */
+    String getName();
+
+    /**
+     * Returns this appenders layout.
+     *
+     * @return the Layout for the Appender or null if none is configured.
+     */
+    Layout getLayout();
+
+    /**
+     * Configurators call this method to determine if the appender
+     * requires a layout. If this method returns <code>true</code>,
+     * meaning that layout is required, then the configurator will
+     * configure an layout using the configuration information at its
+     * disposal.  If this method returns <code>false</code>, meaning that
+     * a layout is not required, then layout configuration will be
+     * skipped even if there is available layout configuration
+     * information at the disposal of the configurator..
+     * <p/>
+     * <p>In the rather exceptional case, where the appender
+     * implementation admits a layout but can also work without it, then
+     * the appender should return <code>true</code>.
+     *
+     * @return True if a Layout is required, false otherwise.
+     */
+    boolean requiresLayout();
+
+    /**
+     * If set to true any exceptions thrown by the Appender will be logged but not thrown.
+     * @return true if Exceptions should be suppressed, false otherwise.
+     */
+    boolean suppressException();
+
+    /**
+     * Called when the Appender is initialized.
+     */
+    void start();
+
+    /**
+     * Called when the Appender is being shut down.
+     */
+    void stop();
+
+    /**
+     * Returns true if the appender is ready to process requests.
+     * @return true if the appender is ready to process requests, false otherwise.
+     */
+    boolean isStarted();
+
+    ErrorHandler getHandler();
+
+    void setHandler(ErrorHandler handler);
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/ErrorHandler.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/ErrorHandler.java
new file mode 100644
index 0000000..c9b2864
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/ErrorHandler.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.core.LogEvent;
+
+/**
+ * Appenders may delegate their error handling to <code>ErrorHandlers</code>.
+ */
+public interface ErrorHandler {
+
+    /**
+     * Handle an error with a message.
+     * @param msg The message.
+     */
+    void error(String msg);
+
+    /**
+     * Handle an error with a message and an exception.
+     * @param msg The message.
+     * @param t The Throwable.
+     */
+    void error(String msg, Throwable t);
+
+    /**
+     * Handle an error with a message, and exception and a logging event.
+     * @param msg The message.
+     * @param event The LogEvent.
+     * @param t The Throwable.
+     */
+    public void error(String msg, LogEvent event, Throwable t);
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/Filter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/Filter.java
new file mode 100644
index 0000000..c2ddf16
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/Filter.java
@@ -0,0 +1,34 @@
+package org.apache.logging.log4j.core;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.message.Message;
+
+/**
+ *
+ */
+public interface Filter {
+
+    public enum Result {
+        ACCEPT, NEUTRAL, DENY
+    }
+
+    void start();
+
+    void stop();
+
+    boolean isStarted();
+
+    Result getOnMismatch();
+
+    Result getOnMatch();
+
+    Result filter(Logger logger, Level level, Marker marker, String msg, Object... params);
+
+    Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t);
+
+    Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t);
+
+    Result filter(LogEvent event);
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/Layout.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/Layout.java
new file mode 100644
index 0000000..cd4fa7f
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/Layout.java
@@ -0,0 +1,32 @@
+package org.apache.logging.log4j.core;
+
+/**
+ *
+ */
+public interface Layout {
+    // Note that the line.separator property can be looked up even by
+    // applets.
+    public static final String LINE_SEP = System.getProperty("line.separator");
+    public static final int LINE_SEP_LEN = LINE_SEP.length();
+
+    /**
+     * Formats the event suitable for display.
+     * @param event The Logging Event.
+     * @return The formatted event String.
+     */
+    byte[] format(LogEvent event);
+
+    /**
+     * Returns the header for the layout format.
+     * @return The header.
+     */
+    byte[] getHeader();
+
+    /**
+     * Returns the format for the layout format.
+     * @return The footer.
+     */
+    byte[] getFooter();
+
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/Log4jLogEvent.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/Log4jLogEvent.java
new file mode 100644
index 0000000..46e0111
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/Log4jLogEvent.java
@@ -0,0 +1,177 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.MDC;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.NDC;
+import org.apache.logging.log4j.message.Message;
+
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ *
+ */
+public class Log4jLogEvent implements LogEvent, Serializable {
+
+    private static final String NOT_AVAIL = "?";
+    private final String fqcnOfLogger;
+    private final Marker marker;
+    private final Level level;
+    private final String name;
+    private final Message message;
+    private final long timestamp;
+    private final Throwable throwable;
+    private final Map<String, Object> mdc;
+    private final Stack<Object> ndc;
+    private String threadName = null;
+    private StackTraceElement location;
+
+    public Log4jLogEvent(String loggerName, Marker marker, String fqcn, Level level, Message message, Throwable t) {
+        this(loggerName, marker, fqcn, level, message, t, MDC.getContext(), NDC.cloneStack(), null, null,
+             System.currentTimeMillis());
+    }
+
+
+    public Log4jLogEvent(String loggerName, Marker marker, String fqcn, Level level, Message message, Throwable t,
+                         Map<String, Object> mdc, Stack<Object>ndc, String threadName, StackTraceElement location,
+                         long timestamp) {
+        name = loggerName;
+        this.marker = marker;
+        this.fqcnOfLogger = fqcn;
+        this.level = level;
+        this.message = message;
+        this.throwable = t;
+        this.mdc = mdc;
+        this.ndc = ndc;
+        this.timestamp = timestamp;
+        this.threadName = threadName;
+        this.location = location;
+
+    }
+
+    public Level getLevel() {
+        return level;
+    }
+
+    public String getLoggerName() {
+        return name;
+    }
+
+    public Message getMessage() {
+        return message;
+    }
+
+    public String getThreadName() {
+        if (threadName == null) {
+            threadName = Thread.currentThread().getName();
+        }
+        return threadName;
+    }
+
+    public long getMillis() {
+        return timestamp;
+    }
+
+    public Throwable getThrown() {
+        return throwable;
+    }
+
+    public Map<String, Object> getContextMap() {
+        return mdc;
+    }
+
+    public Stack<Object> getContextStack() {
+        return ndc;
+    }
+
+    public StackTraceElement getSource() {
+        if (fqcnOfLogger == null) {
+            return null;
+        }
+        if (location == null) {
+            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+            boolean next = false;
+            for (StackTraceElement element : stackTrace) {
+                if (next) {
+                    location = element;
+                    break;
+                }
+                String className = element.getClassName();
+                if (fqcnOfLogger.equals(className)) {
+                    next = true;
+                } else if (NOT_AVAIL.equals(className)) {
+                    break;
+                }
+            }
+        }
+
+        return location;
+    }
+
+    protected Object writeReplace() {
+        return new LogEventProxy(this);
+    }
+
+    private void readObject(ObjectInputStream stream)
+        throws InvalidObjectException {
+        throw new InvalidObjectException("Proxy required");
+    }
+
+    private static class LogEventProxy implements Serializable {
+
+
+        private final String fqcnOfLogger;
+        private final Marker marker;
+        private final Level level;
+        private final String name;
+        private final Message message;
+        private final long timestamp;
+        private final Throwable throwable;
+        private final HashMap<String, Object> mdc;
+        private final Stack<Object> ndc;
+        private String threadName;
+        private StackTraceElement location;
+
+        public LogEventProxy(Log4jLogEvent event) {
+            this.fqcnOfLogger = event.fqcnOfLogger;
+            this.marker = event.marker;
+            this.level = event.level;
+            this.name = event.name;
+            this.message = event.message;
+            this.timestamp = event.timestamp;
+            this.throwable = event.throwable;
+            this.mdc = new HashMap<String, Object>(event.mdc);
+            this.ndc = event.ndc;
+            this.location = event.getSource();
+            this.threadName = event.getThreadName();
+        }
+
+        protected Object readResolve() {
+            return new Log4jLogEvent(name, marker, fqcnOfLogger, level, message, throwable, mdc, ndc, threadName,
+                                     location, timestamp);
+        }
+
+    }
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
new file mode 100644
index 0000000..58bd655
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
@@ -0,0 +1,74 @@
+package org.apache.logging.log4j.core;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.message.Message;
+
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ *
+ */
+public interface LogEvent {
+
+     /**
+     * Get level.
+     * @return level.
+     */
+    Level getLevel();
+
+    /**
+     * Get logger name.
+     * @return logger name, may be null.
+     */
+    String getLoggerName();
+
+    /**
+     * Get source of logging request.
+     * @return source of logging request, may be null.
+     */
+    StackTraceElement getSource();
+
+    /**
+     * Get the message associated with the event.
+     *
+     * @return message.
+     */
+    Message getMessage();
+
+    /**
+     * Get thread name.
+     * @return thread name, may be null.
+     */
+    String getThreadName();
+
+
+    /**
+     * Get event time in milliseconds since 1970.
+     * @return milliseconds since 1970.
+     */
+    long getMillis();
+
+
+    /**
+     * Get throwable associated with logging request.
+     * @return throwable, may be null.
+     */
+    Throwable getThrown();
+
+
+    /**
+     * Get the MDC data;
+     *
+     * @return A copy of the Mapped Diagnostic Context or null.
+     */
+    Map<String, Object> getContextMap();
+
+    /**
+     * Get the NDC data;
+     *
+     * @return A copy of the Nested Diagnostic Context of null;
+     */
+    Stack<Object> getContextStack();
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/LogEventFactory.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/LogEventFactory.java
new file mode 100644
index 0000000..fee82b9
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/LogEventFactory.java
@@ -0,0 +1,13 @@
+package org.apache.logging.log4j.core;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.message.Message;
+
+/**
+ *
+ */
+public interface LogEventFactory {
+
+    LogEvent createEvent(String loggerName, Marker marker, String fqcn, Level level, Message data, Throwable t);
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/Logger.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/Logger.java
new file mode 100644
index 0000000..0b94ab5
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/Logger.java
@@ -0,0 +1,289 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.spi.AbstractLogger;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class Logger extends AbstractLogger {
+    private static String FQCN = Logger.class.getName();
+    private final String name;
+
+    private final LoggerContext context;
+
+    /**
+     * config should be consistent across threads.
+     */
+    private volatile PrivateConfig config;
+
+    protected Logger(LoggerContext context, String name) {
+        this.context = context;
+        this.name = name;
+        config = new PrivateConfig(context.getConfiguration(), this);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    /* @Override
+    protected String getFQCN() {
+        return FQCN;
+    } */
+
+    public LoggerContext getContext() {
+        return context;
+    }
+
+    public synchronized void setLevel(Level level) {
+        config.level = level;
+        config.intLevel = level.intLevel();
+    }
+
+    public Level getLevel() {
+        return config.level;
+    }
+
+    @Override
+    protected void log(Marker marker, String fqcn, Level level, Message data, Throwable t) {
+        config.loggerConfig.log(name, marker, fqcn, level, data, t);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg) {
+        return config.filter(level, marker, msg);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Throwable t) {
+        return config.filter(level, marker, msg, t);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Object p1) {
+        return config.filter(level, marker, msg, p1);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Object p1, Object p2) {
+        return config.filter(level, marker, msg, p1, p2);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Object p1, Object p2, Object p3) {
+        return config.filter(level, marker, msg, p1, p2, p3);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Object p1, Object p2, Object p3,
+                                Object... params) {
+        return config.filter(level, marker, msg, p1, p2, p3, params);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, Object msg, Throwable t) {
+        return config.filter(level, marker, msg, t);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, Message msg, Throwable t) {
+        return config.filter(level, marker, msg, t);
+    }
+
+    public void addAppender(Appender appender) {
+        config.config.addLoggerAppender(name, appender);
+    }
+
+    public void removeAppender(Appender appender) {
+        config.loggerConfig.removeAppender(appender.getName());
+    }
+
+    public Map<String, Appender> getAppenders() {
+         return config.loggerConfig.getAppenders();
+    }
+
+    public List<Filter> getFilters() {
+        return config.loggerConfig.getFilters();
+    }
+
+    /**
+     * This method isn't synchronized to serialized updates to config. Rather, by doing this
+     * it is guaranteed that all threads will see the update without having to declare the variable
+     * volatile.
+     *
+     * @param config The new Configuration.
+     */
+    void updateConfiguration(Configuration config) {
+        this.config = new PrivateConfig(config, this);
+    }
+
+    private class PrivateConfig {
+        private final LoggerConfig loggerConfig;
+        private final Configuration config;
+        private Level level;
+        private int intLevel;
+        private final Logger logger;
+
+        public PrivateConfig(Configuration config, Logger logger) {
+            this.config = config;
+            this.loggerConfig = config.getLoggerConfig(name);
+            this.level = this.loggerConfig.getLevel();
+            this.intLevel = this.level.intLevel();
+            this.logger = logger;
+        }
+
+        public PrivateConfig(PrivateConfig pc, LoggerConfig lc) {
+            this.config = pc.config;
+            this.loggerConfig = lc;
+            this.level = lc.getLevel();
+            this.intLevel = this.level.intLevel();
+            this.logger = pc.logger;
+        }
+
+        boolean filter(Level level, Marker marker, String msg) {
+            if (config.hasFilters()) {
+                Iterator<Filter> iter = config.getFilters();
+                while (iter.hasNext()) {
+                    Filter filter = iter.next();
+                    Filter.Result r = filter.filter(logger, level, marker, msg);
+                    if (r != Filter.Result.NEUTRAL) {
+                        return r == Filter.Result.ACCEPT;
+                    }
+                }
+            }
+
+            return level.lessOrEqual(intLevel);
+        }
+
+        boolean filter(Level level, Marker marker, String msg, Throwable t) {
+            if (config.hasFilters()) {
+                Iterator<Filter> iter = config.getFilters();
+                while (iter.hasNext()) {
+                    Filter filter = iter.next();
+                    Filter.Result r = filter.filter(logger, level, marker, msg, t);
+                    if (r != Filter.Result.NEUTRAL) {
+                        return r == Filter.Result.ACCEPT;
+                    }
+                }
+            }
+
+            return level.lessOrEqual(intLevel);
+        }
+
+        boolean filter(Level level, Marker marker, String msg, Object p1) {
+            if (config.hasFilters()) {
+                Iterator<Filter> iter = config.getFilters();
+                while (iter.hasNext()) {
+                    Filter filter = iter.next();
+                    Filter.Result r = filter.filter(logger, level, marker, msg, p1);
+                    if (r != Filter.Result.NEUTRAL) {
+                        return r == Filter.Result.ACCEPT;
+                    }
+                }
+            }
+
+            return level.lessOrEqual(intLevel);
+        }
+
+        boolean filter(Level level, Marker marker, String msg, Object p1, Object p2) {
+            if (config.hasFilters()) {
+                Iterator<Filter> iter = config.getFilters();
+                while (iter.hasNext()) {
+                    Filter filter = iter.next();
+                    Filter.Result r = filter.filter(logger, level, marker, msg, p1, p2);
+                    if (r != Filter.Result.NEUTRAL) {
+                        return r == Filter.Result.ACCEPT;
+                    }
+                }
+            }
+
+            return level.lessOrEqual(intLevel);
+        }
+
+        boolean filter(Level level, Marker marker, String msg, Object p1, Object p2, Object p3) {
+            if (config.hasFilters()) {
+                Iterator<Filter> iter = config.getFilters();
+                while (iter.hasNext()) {
+                    Filter filter = iter.next();
+                    Filter.Result r = filter.filter(logger, level, marker, msg, p1, p2, p3);
+                    if (r != Filter.Result.NEUTRAL) {
+                        return r == Filter.Result.ACCEPT;
+                    }
+                }
+            }
+
+            return level.lessOrEqual(intLevel);
+        }
+
+        boolean filter(Level level, Marker marker, String msg, Object p1, Object p2, Object p3,
+                       Object... params) {
+            if (config.hasFilters()) {
+                Iterator<Filter> iter = config.getFilters();
+                while (iter.hasNext()) {
+                    Filter filter = iter.next();
+                    Filter.Result r = filter.filter(logger, level, marker, msg, p1, p2, p3, params);
+                    if (r != Filter.Result.NEUTRAL) {
+                        return r == Filter.Result.ACCEPT;
+                    }
+                }
+            }
+
+            return level.lessOrEqual(intLevel);
+        }
+
+        boolean filter(Level level, Marker marker, Object msg, Throwable t) {
+            if (config.hasFilters()) {
+                Iterator<Filter> iter = config.getFilters();
+                while (iter.hasNext()) {
+                    Filter filter = iter.next();
+                    Filter.Result r = filter.filter(logger, level, marker, msg, t);
+                    if (r != Filter.Result.NEUTRAL) {
+                        return r == Filter.Result.ACCEPT;
+                    }
+                }
+            }
+
+            return level.lessOrEqual(intLevel);
+        }
+
+        boolean filter(Level level, Marker marker, Message msg, Throwable t) {
+            if (config.hasFilters()) {
+                Iterator<Filter> iter = config.getFilters();
+                while (iter.hasNext()) {
+                    Filter filter = iter.next();
+                    Filter.Result r = filter.filter(logger, level, marker, msg, t);
+                    if (r != Filter.Result.NEUTRAL) {
+                        return r == Filter.Result.ACCEPT;
+                    }
+                }
+            }
+
+            return level.lessOrEqual(intLevel);
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
new file mode 100644
index 0000000..f7af54c
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
+import org.apache.logging.log4j.core.config.XMLConfiguration;
+import org.apache.logging.log4j.internal.StatusLogger;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ *
+ */
+public class LoggerContext implements org.apache.logging.log4j.spi.LoggerContext {
+
+    private ConcurrentMap<String, Logger> loggers = new ConcurrentHashMap<String, Logger>();
+
+    private volatile Configuration config;
+
+    private static StatusLogger logger = StatusLogger.getLogger();
+
+    public LoggerContext() {
+        reconfigure();
+    }
+
+    public Logger getLogger(String name) {
+        Logger logger = loggers.get(name);
+        if (logger != null) {
+            return logger;
+        }
+
+        logger = new Logger(this, name);
+        Logger prev = loggers.putIfAbsent(name, logger);
+        return prev == null ? logger : prev;
+    }
+
+    public Configuration getConfiguration() {
+        return config;
+    }
+
+    public void addFilter(Filter filter) {
+        config.addFilter(filter);
+    }
+
+    public void removeFiler(Filter filter) {
+        config.removeFilter(filter);
+    }
+
+    public synchronized Configuration setConfiguration(Configuration config) {
+        Configuration prev = this.config;
+        this.config = config;
+        return prev;
+    }
+
+    public synchronized void reconfigure() {
+        logger.debug("Reconfiguration started");
+        Configuration config = ConfigurationFactory.getInstance().getConfiguration();
+        config.start();
+        Configuration old = setConfiguration(config);
+        for (Logger logger : loggers.values()) {
+            logger.updateConfiguration(config);
+        }
+        if (old != null) {
+            old.stop();
+        }
+        logger.debug("Reconfiguration completed");
+    }
+
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/LoggingException.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/LoggingException.java
new file mode 100644
index 0000000..945fa19
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/LoggingException.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ *
+ *
+ *
+ *
+ */
+public class LoggingException extends RuntimeException {
+
+    public LoggingException(String msg) {
+        super(msg);
+    }
+
+    public LoggingException(String msg, Exception ex) {
+        super(msg, ex);
+    }
+
+    public LoggingException(Exception ex) {
+        super(ex);
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/AppenderBase.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/AppenderBase.java
new file mode 100644
index 0000000..2bb3744
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/AppenderBase.java
@@ -0,0 +1,129 @@
+/*
+ * 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.core.Appender;
+import org.apache.logging.log4j.core.ErrorHandler;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.internal.StatusLogger;
+import org.apache.logging.log4j.Logger;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ *
+ */
+public abstract class AppenderBase implements Appender {
+
+    protected boolean started = false;
+
+    protected Layout layout = null;
+
+    protected List<Filter> filters = new CopyOnWriteArrayList<Filter>();
+
+    private final String name;
+
+    protected static final Logger logger = StatusLogger.getLogger();
+
+    protected ErrorHandler handler;
+
+    public AppenderBase(String name) {
+        this.name = name;
+    }
+
+    public ErrorHandler getHandler() {
+        return handler;
+    }
+
+    public void setHandler(ErrorHandler handler) {
+        this.handler = handler;
+    }
+
+    public void addFilter(Filter filter) {
+        filters.add(filter);
+    }
+
+    public Filter getFilter() {
+        return filters.size() > 0 ? filters.get(0) : null;
+    }
+
+    public void clearFilters() {
+        filters.clear();
+    }
+
+    public List<Filter> getFilters() {
+        return filters;
+    }
+
+    public void close() {
+
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setLayout(Layout layout) {
+        this.layout = layout;
+    }
+
+    public Layout getLayout() {
+        return layout;
+    }
+
+    public boolean requiresLayout() {
+        return false;
+    }
+
+    public boolean suppressException() {
+        return true;
+    }
+
+    public void start() {
+        for (Filter filter : filters) {
+            filter.start();
+        }
+        this.started = true;
+    }
+
+    public void stop() {
+        this.started = false;
+        for (Filter filter : filters) {
+            filter.stop();
+        }
+    }
+
+    public boolean isStarted() {
+        return started;
+    }
+
+    public static Layout createLayout(Node node) {
+        Layout layout = null;
+        for (Node child : node.getChildren()) {
+            Object obj = child.getObject();
+            if (obj != null && obj instanceof Layout) {
+                layout = (Layout) obj;
+            }
+        }
+        return layout;
+    }
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/AppenderRuntimeException.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/AppenderRuntimeException.java
new file mode 100644
index 0000000..c72808e
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/AppenderRuntimeException.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+/**
+ *
+ */
+public class AppenderRuntimeException extends RuntimeException {
+
+    public AppenderRuntimeException(String msg) {
+        super(msg);
+    }
+
+    public AppenderRuntimeException(String msg, Throwable ex) {
+        super(msg, ex);
+    }
+
+    public AppenderRuntimeException(Throwable ex) {
+        super(ex);
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
new file mode 100644
index 0000000..dca9029
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
@@ -0,0 +1,71 @@
+/*
+ * 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.core.Layout;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+
+import java.util.Map;
+
+/**
+ * ConsoleAppender appends log events to <code>System.out</code> or
+ * <code>System.err</code> using a layout specified by the user. The
+ * default target is <code>System.out</code>.
+ */
+@Plugin(name="Console",type="Core")
+public class ConsoleAppender extends OutputStreamAppender {
+
+    public static final String LAYOUT = "layout";
+    public static final String TARGET = "target";
+    public static final String NAME = "name";
+
+    public enum Target {
+        SYSTEM_OUT, SYSTEM_ERR
+    }
+
+    public ConsoleAppender(String name, Layout layout) {
+        this(name, layout, Target.SYSTEM_OUT);
+
+    }
+
+    public ConsoleAppender(String name, Layout layout, Target target) {
+        super(name, layout, target == Target.SYSTEM_OUT ? System.out : System.err);
+    }
+
+    @PluginFactory
+    public static ConsoleAppender createAppender(Node node) {
+        Layout layout = createLayout(node);
+        String t = null;
+        String name = null;
+        for (Map.Entry<String, String> attr : node.getAttributes().entrySet()) {
+            if (attr.getKey().equalsIgnoreCase(TARGET)) {
+                t = attr.getValue().toUpperCase();
+            } else if (attr.getKey().equalsIgnoreCase(NAME)) {
+                name = attr.getValue();
+            }
+        }
+        if (name == null) {
+            logger.error("No name provided for Appender of type " + node.getName());
+            return null;
+        }
+        Target target = t == null ? Target.SYSTEM_OUT : Target.valueOf(t);
+        return new ConsoleAppender(name, layout, target);
+    }
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/DefaultErrorHandler.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/DefaultErrorHandler.java
new file mode 100644
index 0000000..66a810b
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/DefaultErrorHandler.java
@@ -0,0 +1,92 @@
+/*
+ * 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.Logger;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.ErrorHandler;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AppenderRuntimeException;
+import org.apache.logging.log4j.internal.StatusLogger;
+
+/**
+ *
+ */
+public class DefaultErrorHandler implements ErrorHandler {
+
+    private int exceptionCount = 0;
+
+    private long lastException;
+
+    private static Logger logger = StatusLogger.getLogger();
+
+    private static final int MAX_EXCEPTIONS = 3;
+
+    private static final int EXCEPTION_INTERVAL = 300000;
+
+    private Appender appender;
+
+    public DefaultErrorHandler(Appender appender) {
+        this.appender = appender;
+    }
+
+
+    /**
+     * Handle an error with a message.
+     * @param msg The message.
+     */
+    public void error(String msg) {
+        long current = System.currentTimeMillis();
+        if (lastException + EXCEPTION_INTERVAL < current || exceptionCount++ < MAX_EXCEPTIONS) {
+            logger.error(msg);
+        }
+        lastException = current;
+    }
+
+    /**
+     * Handle an error with a message and an exception.
+     * @param msg The message.
+     * @param t The Throwable.
+     */
+    public void error(String msg, Throwable t) {
+        long current = System.currentTimeMillis();
+        if (lastException + EXCEPTION_INTERVAL < current || exceptionCount++ < MAX_EXCEPTIONS) {
+            logger.error(msg, t);
+        }
+        lastException = current;
+        if (!appender.suppressException() && t != null) {
+            throw new AppenderRuntimeException(msg, t);
+        }
+    }
+
+    /**
+     * Handle an error with a message, and exception and a logging event.
+     * @param msg The message.
+     * @param event The LogEvent.
+     * @param t The Throwable.
+     */
+    public void error(String msg, LogEvent event, Throwable t) {
+        long current = System.currentTimeMillis();
+        if (lastException + EXCEPTION_INTERVAL < current || exceptionCount++ < MAX_EXCEPTIONS) {
+            logger.error(msg, t);
+        }
+        lastException = current;
+        if (!appender.suppressException() && t != null) {
+            throw new AppenderRuntimeException(msg, t);
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java
new file mode 100644
index 0000000..92771fc
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java
@@ -0,0 +1,80 @@
+/*
+ * 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.core.Layout;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.util.Map;
+
+/**
+ *
+ */
+@Plugin(name="File",type="Core")
+public class FileAppender extends OutputStreamAppender {
+
+    public static final String FILE_NAME = "fileName";
+    public static final String APPEND = "append";
+    public static final String NAME = "name";
+    public final String fileName;
+
+    public FileAppender(String name, Layout layout, OutputStream os, String filename) {
+        super(name, layout, os);
+        this.fileName = filename;
+    }
+
+    @PluginFactory
+    public static FileAppender createAppender(Node node) {
+        Layout layout = createLayout(node);
+        String fileName = null;
+        String name = null;
+        boolean isAppend = true;
+        for (Map.Entry<String, String> attr : node.getAttributes().entrySet()) {
+            if (attr.getKey().equalsIgnoreCase(FILE_NAME)) {
+                fileName = attr.getValue();
+            } else if (attr.getKey().equalsIgnoreCase(APPEND)) {
+                isAppend = Boolean.parseBoolean(attr.getValue());
+            } else if (attr.getKey().equalsIgnoreCase(NAME)) {
+                name = attr.getValue();
+            }
+        }
+
+        if (name == null) {
+            logger.error("No name provided for Appender of type " + node.getName());
+            return null;
+        }
+
+        if (fileName == null) {
+            logger.error("No filename provided for Appender of type " + node.getName() +
+                " with name " + name);
+            return null;
+        }
+
+        try {
+            OutputStream os = new FileOutputStream(fileName, isAppend);
+            return new FileAppender(name, layout, os, fileName);
+        } catch (FileNotFoundException ex) {
+            logger.error("Unable to open file " + fileName, ex);
+            return null;
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
new file mode 100644
index 0000000..e5eb17e
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
@@ -0,0 +1,318 @@
+/*
+ * 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.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ *
+ */
+public abstract class OutputStreamAppender extends AppenderBase {
+
+    /**
+     * Immediate flush means that the underlying writer or output stream
+     * will be flushed at the end of each append operation. Immediate
+     * flush is slower but ensures that each append request is actually
+     * written. If <code>immediateFlush</code> is set to
+     * <code>false</code>, then there is a good chance that the last few
+     * logs events are not actually written to persistent media if and
+     * when the application crashes.
+     * <p/>
+     * <p>The <code>immediateFlush</code> variable is set to
+     * <code>true</code> by default.
+     */
+    protected boolean immediateFlush = true;
+
+    /**
+     * The encoding to use when writing.  <p>The
+     * <code>encoding</code> variable is set to <code>null</null> by
+     * default which results in the utilization of the system's default
+     * encoding.
+     */
+    protected String encoding;
+
+    /**
+     * This is the OutputStream where we will write to.
+     */
+    protected InternalOutputStream os;
+
+    /**
+     * Instantiate a WriterAppender and set the output destination to a
+     * new {@link java.io.OutputStreamWriter} initialized with <code>os</code>
+     * as its {@link java.io.OutputStream}.
+     * @param name The name of the Appender.
+     * @param layout The layout to format the message.
+     * @param os The OutputStream.
+     */
+    public OutputStreamAppender(String name, Layout layout, OutputStream os) {
+        super(name);
+        this.layout = layout;
+        this.setOutputStream(os);
+    }
+
+    /**
+     * If the <b>ImmediateFlush</b> option is set to
+     * <code>true</code>, the appender will flush at the end of each
+     * write. This is the default behavior. If the option is set to
+     * <code>false</code>, then the underlying stream can defer writing
+     * to physical medium to a later time.
+     * <p/>
+     * <p>Avoiding the flush operation at the end of each append results in
+     * a performance gain of 10 to 20 percent. However, there is safety
+     * tradeoff involved in skipping flushing. Indeed, when flushing is
+     * skipped, then it is likely that the last few log events will not
+     * be recorded on disk when the application exits. This is a high
+     * price to pay even for a 20% performance gain.
+     */
+    public void setImmediateFlush(boolean value) {
+        immediateFlush = value;
+    }
+
+    /**
+     * Returns value of the <b>ImmediateFlush</b> option.
+     */
+    public boolean getImmediateFlush() {
+        return immediateFlush;
+    }
+
+    @Override
+    public void setLayout(Layout layout) {
+        if (layout == null) {
+            handler.error("The layout for appender " + getName() + " cannot be set to null");
+        }
+        super.setLayout(layout);
+    }
+
+    @Override
+    public void start() {
+        if (this.layout == null) {
+            logger.error("No layout set for the appender named [" + getName() + "].");
+        }
+        if (this.os == null) {
+            logger.error("No OutputStream set for the appender named [" + getName() + "].");
+        }
+        super.start();
+    }
+
+    @Override
+    public void stop() {
+        super.stop();
+        os.close();
+    }
+
+
+    /**
+     * <p/>
+     * <p>If the output stream exists and is writable then write a log
+     * statement to the output stream. Otherwise, write a single warning
+     * message to <code>System.err</code>.
+     * <p/>
+     * <p>The format of the output will depend on this appender's
+     * layout.
+     */
+    public void append(LogEvent event) {
+
+        if (!isStarted()) {
+            return;
+        }
+        subAppend(event);
+    }
+
+
+
+    /**
+     * Close this appender instance. The underlying stream or writer is
+     * also closed.
+     * <p/>
+     * <p>Closed appenders cannot be reused.
+     *
+     * @see #setOutputStream
+     */
+    public void close() {
+        reset();
+    }
+
+    /**
+     * <p>Sets the OutputStream where the log output will go. The
+     * specified OutputStream must be opened by the user and be
+     * writable.
+     * <p/>
+     * <p>The <code>java.io.OutputStream</code> will be closed when the
+     * appender instance is closed.
+     * <p/>
+     * <p/>
+     * <p><b>WARNING:</b> Logging to an unopened Writer will fail.
+     *
+     * @param os An already opened OutputStream.
+     */
+    public synchronized void setOutputStream(OutputStream os) {
+        InternalOutputStream prev = this.os;
+        this.os = new InternalOutputStream(os);
+        if (prev != null) {
+            prev.close();
+        }
+    }
+
+
+    /**
+     * Actual writing occurs here.
+     * <p/>
+     * <p>Most subclasses of <code>OutputStreamAppender</code> will need to
+     * override this method.
+     * @param event The LogEvent.
+     */
+    protected void subAppend(LogEvent event) {
+        this.os.write(this.layout.format(event));
+
+        if (this.immediateFlush) {
+            this.os.flush();
+        }
+    }
+
+
+    /**
+     * The WriterAppender requires a layout. Hence, this method returns
+     * <code>true</code>.
+     */
+    public boolean requiresLayout() {
+        return true;
+    }
+
+    /**
+     * Clear internal references to the writer and other variables.
+     * <p/>
+     * Subclasses can override this method for an alternate closing
+     * behavior.
+     */
+    protected synchronized void reset() {
+        InternalOutputStream os = this.os;
+        if (os != null) {
+            this.os = null;
+            os.close();
+        }
+    }
+
+
+    /**
+     * Write a footer as produced by the embedded layout's {@link
+     * org.apache.logging.log4j.core.Layout#getFooter} method.
+     */
+    protected void writeFooter(OutputStream os) {
+        if (layout != null) {
+            byte[] b = layout.getFooter();
+            if (b != null && os != null) {
+                try {
+                    os.write(b);
+                    os.flush();
+                } catch (IOException ioe) {
+                    this.started = false;
+                    handler.error("Failed to write footer for appender " + getName(), ioe);
+                }
+            }
+        }
+    }
+
+    /**
+     * Write a header as produced by the embedded layout's {@link
+     * org.apache.logging.log4j.core.Layout#getHeader} method.
+     */
+    protected void writeHeader(OutputStream os) {
+        if (layout != null) {
+            byte[] b = layout.getHeader();
+            if (b != null && os != null) {
+                try {
+                    os.write(b);
+                } catch (IOException ioe) {
+                    this.started = false;
+                    handler.error("Failed to write footer for appender " + getName(), ioe);
+                }
+            }
+        }
+    }
+
+    private class InternalOutputStream extends OutputStream {
+
+        private final OutputStream os;
+
+        public InternalOutputStream(OutputStream os) {
+            writeHeader(os);
+            this.os = os;
+        }
+
+        @Override
+        public void close() {
+            writeFooter(os);
+            try {
+                if (os != System.out && os != System.err) {
+                    os.close();
+                }
+            } catch (IOException ioe) {
+                handler.error("Error closing writer for " + getName(), ioe);
+            }
+
+        }
+
+        @Override
+        public void flush() {
+            try {
+                os.flush();
+            } catch (IOException ioe) {
+                handler.error("Error flushing appender " + getName(), ioe);
+            }
+        }
+
+        public void write(String msg) {
+            try {
+                if (encoding != null) {
+                    os.write(msg.getBytes(encoding));
+                } else {
+                    os.write(msg.getBytes());
+                }
+
+            } catch (IOException ioe) {
+                handler.error("Error writing to appender " + getName(), ioe);
+            }
+        }
+
+        @Override
+        public void write(byte[] bytes, int i, int i1) {
+            try {
+                os.write(bytes, i, i1);
+            } catch (IOException ioe) {
+                handler.error("Error writing to appender " + getName(), ioe);
+            }
+        }
+
+        @Override
+        public void write(byte[] bytes) {
+            write(bytes, 0, bytes.length);
+        }
+
+        @Override
+        public void write(int i) {
+            try {
+                os.write(i);
+            }  catch (IOException ioe) {
+                handler.error("Error writing to appender " + getName(), ioe);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControl.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControl.java
new file mode 100644
index 0000000..275927e
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControl.java
@@ -0,0 +1,79 @@
+/*
+ * 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.config;
+
+import org.apache.logging.log4j.core.ErrorHandler;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AppenderRuntimeException;
+import org.apache.logging.log4j.core.appender.DefaultErrorHandler;
+
+/**
+ *
+ */
+public class AppenderControl {
+
+    private final Appender appender;
+
+    private ErrorHandler handler;
+
+    AppenderControl(Appender appender) {
+        this.appender = appender;
+        handler = appender.getHandler();
+        if (handler == null) {
+            handler = new DefaultErrorHandler(appender);
+            appender.setHandler(handler);
+        }
+    }
+
+    public Appender getAppender() {
+        return appender;
+    }
+
+    public void callAppender(LogEvent event) {
+        if (!appender.isStarted()) {
+            handler.error("Attempted to append to non-started appender " + appender.getName());
+
+            if (!appender.suppressException()) {
+                throw new AppenderRuntimeException("Attempted to append to non-started appender " + appender.getName());
+            }
+        }
+
+        Filter.Result result = Filter.Result.NEUTRAL;
+
+        for (Filter filter : appender.getFilters()) {
+            result = filter.filter(event);
+            if (result != Filter.Result.NEUTRAL) {
+                break;
+            }
+        }
+        if (result == Filter.Result.DENY) {
+            return;
+        }
+
+        try {
+            appender.append(event);
+        } catch (Exception ex) {
+            handler.error("An exception occurred processing Appender " + appender.getName(), ex);
+            if (!appender.suppressException()) {
+                throw new AppenderRuntimeException(ex);
+            }
+        }
+    }
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java
new file mode 100644
index 0000000..5791d30
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java
@@ -0,0 +1,418 @@
+/*
+ * 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.config;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.config.plugins.PluginManager;
+import org.apache.logging.log4j.core.config.plugins.PluginType;
+import org.apache.logging.log4j.internal.StatusLogger;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ *
+ */
+public class BaseConfiguration implements Configuration {
+
+    private String name;
+
+    private ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<String, Appender>();
+
+    private ConcurrentMap<String, LoggerConfig> loggers = new ConcurrentHashMap<String, LoggerConfig>();
+
+    private LoggerConfig root = new LoggerConfig();
+
+    private List<Filter> filters = new CopyOnWriteArrayList<Filter>();
+
+    private boolean hasFilters = false;
+
+    private boolean started = false;
+
+    protected Node rootNode;
+
+    protected PluginManager pluginManager;
+
+    protected final static Logger logger = StatusLogger.getLogger();
+
+    protected BaseConfiguration() {
+        pluginManager = new PluginManager("Core");
+        rootNode = new Node(this);
+    }
+
+    public void start() {
+        pluginManager.collectPlugins();
+        setup();
+        doConfigure();
+        for (Appender appender : appenders.values()) {
+            appender.start();
+        }
+
+        for (Filter filter : filters) {
+            filter.start();
+        }
+    }
+
+    public void stop() {
+        for (LoggerConfig logger : loggers.values()) {
+            logger.clearAppenders();
+        }
+        for (Appender appender : appenders.values()) {
+            appender.stop();
+        }
+        for (Filter filter : filters) {
+            filter.stop();
+        }
+    }
+
+    protected void setup() {        
+    }
+
+    protected void doConfigure() {
+        createConfiguration(rootNode);
+        for (Node child : rootNode.getChildren()) {
+            if (child.getObject() == null) {
+                continue;
+            }
+            if (child.getName().equals("appenders")) {
+                appenders = (ConcurrentMap<String, Appender>) child.getObject();
+            } else if (child.getName().equals("filters")) {
+                filters = new CopyOnWriteArrayList((Filter[]) child.getObject());
+            } else if (child.getName().equals("loggers")) {
+                Loggers l = (Loggers) child.getObject();
+                loggers = l.map;
+                root = l.root;
+            }
+        }
+
+        for (Map.Entry<String, LoggerConfig> entry : loggers.entrySet()) {
+            LoggerConfig l = entry.getValue();
+            for (String ref : l.getAppenderRefs()) {
+                Appender app = appenders.get(ref);
+                if (app != null) {
+                    l.addAppender(app);
+                } else {
+                    logger.error("Unable to locate appender " + ref + " for logger " + l.getName());
+                }
+            }
+        }
+
+        setParents();
+    }
+
+    protected PluginManager getPluginManager() {
+        return pluginManager;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Appender getAppender(String name) {
+        return appenders.get(name);
+    }
+
+    public Map<String, Appender> getAppenders() {
+        return appenders;
+    }
+
+    public void addAppender(Appender appender) {
+        appenders.put(appender.getName(), appender);
+    }
+
+    public void addLoggerAppender(String name, Appender appender) {
+        LoggerConfig lc = getLoggerConfig(name);
+        if (lc.getName().equals(name)) {
+            lc.addAppender(appender);
+        } else {
+            LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), lc.isAdditive());
+            nlc.addAppender(appender);
+            nlc.setParent(lc);
+            loggers.putIfAbsent(name, nlc);
+            setParents();
+        }
+    }
+
+    public void removeAppender(String name) {
+        for (LoggerConfig logger : loggers.values()) {
+            logger.removeAppender(name);
+        }
+        Appender app = appenders.remove(name);
+
+        if (app != null) {
+            app.stop();
+        }
+    }
+
+    public LoggerConfig getLoggerConfig(String name) {
+        if (loggers.containsKey(name)) {
+            return loggers.get(name);
+        }
+        int i = 0;
+        String substr = name;
+        while ((i = substr.lastIndexOf(".")) > 0) {
+            substr = name.substring(0, i);
+            if (loggers.containsKey(substr)) {
+                return loggers.get(substr);
+            }
+        }
+        return root;
+    }
+
+    public LoggerConfig getRootLogger() {
+        return root;
+    }
+
+    public Map<String, LoggerConfig> getLoggers() {
+        return Collections.unmodifiableMap(loggers);
+    }
+
+    public LoggerConfig getLogger(String name) {
+        return loggers.get(name);
+    }
+
+    /**
+     * Adding a logger cannot be done atomically so is not allowed in an active configuration. Adding
+     * or removing a Logger requires creating a new configuration and then switching.
+     *
+     * @param name The name of the Logger.
+     * @param loggerConfig The LoggerConfig.
+     */
+    public void addLogger(String name, LoggerConfig loggerConfig) {
+        if (started) {
+            String msg = "Cannot add logger " + name + " to an active configuration";
+            logger.warn(msg);
+            throw new IllegalStateException(msg);
+        }
+        loggers.put(name, loggerConfig);
+        setParents();
+    }
+
+    /**
+     * Removing a logger cannot be done atomically so is not allowed in an active configuration. Adding
+     * or removing a Logger requires creating a new configuration and then switching.
+     *
+     * @param name The name of the Logger.
+     */
+    public void removeLogger(String name) {
+        if (started) {
+            String msg = "Cannot remove logger " + name + " in an active configuration";
+            logger.warn(msg);
+            throw new IllegalStateException(msg);
+        }
+        loggers.remove(name);
+    }
+
+    public Iterator<Filter> getFilters() {
+        return filters.iterator();
+    }
+
+    public void addFilter(Filter filter) {
+        filters.add(filter);
+        hasFilters = filters.size() > 0;
+    }
+
+    public void removeFilter(Filter filter) {
+        filters.remove(filter);
+        hasFilters = filters.size() > 0;
+    }
+
+    public boolean hasFilters() {
+        return hasFilters;
+    }
+
+    private void createConfiguration(Node node) {
+        for (Node child : node.getChildren()) {
+            createConfiguration(child);
+        }
+        PluginType type = pluginManager.getPluginType(node.getName());
+        if (type == null) {
+            if (node.getParent() != null) {
+                logger.error("Unable to locate plugin for " + node.getName());
+            }
+        } else {
+            node.setObject(createPlugin(type, node));
+        }
+    }
+   /*
+    * Retrieve a static public 'method taking a Node parameter on a class specified by its name.
+    * @param classClass the class.
+    * @return the instantiate method or null if there is none by that
+    * description.
+    */
+    public static Object createPlugin(PluginType type, Node node)
+    {
+        Class clazz = type.getPluginClass();
+
+        if (Map.class.isAssignableFrom(clazz)) {
+            try {
+                Map map = (Map) clazz.newInstance();
+                for (Node child : node.getChildren()) {
+                    map.put(child.getName(), child.getObject());
+                }
+                return map;
+            } catch (Exception ex) {
+
+            }
+        }
+
+        if (List.class.isAssignableFrom(clazz)) {
+            try {
+                List list = (List) clazz.newInstance();
+                for (Node child : node.getChildren()) {
+                    list.add(child.getObject());
+                }
+                return list;
+            } catch (Exception ex) {
+
+            }
+        }
+
+        Method factoryMethod = null;
+
+        for (Method method : clazz.getMethods()) {
+            if (method.isAnnotationPresent(PluginFactory.class)) {
+                factoryMethod = method;
+            }
+        }
+        if (factoryMethod == null) {
+            return null;
+        }
+
+        try
+        {
+            int mod = factoryMethod.getModifiers();
+            if (!Modifier.isStatic(mod))
+            {
+                logger.error(factoryMethod.getName() + " method is not static on class " +
+                    clazz.getName() + " for element " + node.getName());
+                return null;
+            }
+            logger.debug("Calling " + factoryMethod.getName() + " on class " + clazz.getName() + " for element " +
+                node.getName());
+            return factoryMethod.invoke(null, node);
+        }
+        catch (Exception e)
+        {
+            logger.error("Unable to invoke method " + factoryMethod.getName() + " in class " +
+                clazz.getName() + " for element " + node.getName(), e);
+        }
+        return null;
+    }
+
+    private void setParents() {
+         for (Map.Entry<String, LoggerConfig> entry : loggers.entrySet()) {
+            LoggerConfig logger = entry.getValue();
+            String name = entry.getKey();
+            if (!name.equals("")) {
+                int i = name.lastIndexOf(".");
+                if (i > 0) {
+                    name = name.substring(0, i);
+                    LoggerConfig parent = getLoggerConfig(name);
+                    if (parent == null) {
+                        parent = root;
+                    }
+                    logger.setParent(parent);
+                }
+            }
+        }
+    }
+
+    @Plugin(name="appenders", type="Core")
+    public static class AppendersPlugin {
+
+        @PluginFactory
+        public static ConcurrentMap<String, Appender> createAppenders(Node node) {
+            ConcurrentMap<String, Appender> map = new ConcurrentHashMap<String, Appender>();
+
+            for (Node child : node.getChildren()) {
+                Object obj = child.getObject();
+                if (obj != null && obj instanceof Appender) {
+                    Appender appender = (Appender) obj;
+                    map.put(appender.getName(), appender);
+                }
+            }
+
+            return map;
+        }
+    }
+
+
+    @Plugin(name="filters", type="Core")
+    public static class FiltersPlugin {
+
+        @PluginFactory
+        public static Filter[] createFilters(Node node) {
+            List<Filter> filters = new ArrayList<Filter>();
+
+            for (Node child : node.getChildren()) {
+                Object obj = child.getObject();
+                if (obj != null && obj instanceof Filter) {
+                    filters.add((Filter) obj);
+                }
+            }
+
+            return filters.toArray(new Filter[filters.size()]);
+        }
+    }
+
+    @Plugin(name="loggers", type="Core")
+    public static class LoggersPlugin {
+
+        @PluginFactory
+        public static Loggers createLoggers(Node node) {
+            Loggers loggers = new Loggers();
+
+            for (Node child : node.getChildren()) {
+                Object obj = child.getObject();
+                if (obj != null && obj instanceof LoggerConfig) {
+                    LoggerConfig logger = (LoggerConfig) obj;
+                    if (logger != null) {
+                        if (child.getName().equals("root")) {
+                            loggers.root = logger;
+                        }
+                        loggers.map.put(logger.getName(), logger);
+                    }
+                }
+            }
+
+            return loggers;
+        }
+    }
+
+    private static class Loggers {
+        ConcurrentMap<String, LoggerConfig> map = new ConcurrentHashMap<String, LoggerConfig>();
+        LoggerConfig root = null;
+    }
+}
\ No newline at end of file
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
new file mode 100644
index 0000000..dbf2f68
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
@@ -0,0 +1,35 @@
+package org.apache.logging.log4j.core.config;
+
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Filter;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public interface Configuration {
+
+    LoggerConfig getLoggerConfig(String name);
+
+    Map<String, Appender> getAppenders();
+
+    Iterator<Filter> getFilters();
+
+    void addFilter(Filter filter);
+
+    void removeFilter(Filter filter);
+
+    boolean hasFilters();
+
+    Map<String, LoggerConfig> getLoggers();
+
+    void addLoggerAppender(String name, Appender appender);    
+
+    void start();
+
+    void stop();
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationException.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationException.java
new file mode 100644
index 0000000..c7cd58a
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.config;
+
+/**
+ *
+ */
+public class ConfigurationException extends RuntimeException {
+
+    public ConfigurationException(String msg) {
+        super(msg);
+    }
+
+    public ConfigurationException(String msg, Exception ex) {
+        super(msg, ex);
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
new file mode 100644
index 0000000..06c7977
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
@@ -0,0 +1,127 @@
+package org.apache.logging.log4j.core.config;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.PluginManager;
+import org.apache.logging.log4j.core.config.plugins.PluginType;
+import org.apache.logging.log4j.internal.StatusLogger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * ConfigurationFactory allows the configuration implementation to be dynamically chosen in 1
+ * of 3 ways:
+ * 1. A system property named "log4j.configurationFactory" can be set with the name of the
+ * ConfigurationFactory to be used.
+ * 2. setConfigurationFactory can be called with the instance of the ConfigurationFactory to
+ * be used. This must be called before any other calls to Log4j.
+ * 3. A ConfigurationFactory implementation can be added to the classpath and configured as a
+ * plugin. The Order annotation should be used to configure the factory to be the first one
+ * inspected. See XMLConfigurationFactory for an example.
+ *
+ * If the ConfigurationFactory that was added returns null on a call to getConfiguration the
+ * any other ConfigurationFactories found as plugins will be called in their respective order.
+ * DefaultConfiguration is always called last if no configuration has been returned.
+ */
+public abstract class ConfigurationFactory {
+
+    public static final String CONFIGURATION_FACTORY_PROPERTY = "log4j.configurationFactory";
+
+    private static List<ConfigurationFactory> factories = new ArrayList<ConfigurationFactory>();
+
+    private static Logger logger = StatusLogger.getLogger();
+
+    public static ConfigurationFactory getInstance() {
+        String factoryClass = System.getProperty(CONFIGURATION_FACTORY_PROPERTY);
+        if (factoryClass != null) {
+            addFactory(factoryClass);
+        }
+        PluginManager manager = new PluginManager("ConfigurationFactory");
+        manager.collectPlugins();
+        Map<String, PluginType> plugins = manager.getPlugins();
+        Set<WeightedFactory> ordered = new TreeSet<WeightedFactory>();
+        for (PluginType type : plugins.values()) {
+            try {
+                Class<ConfigurationFactory> clazz = type.getPluginClass();
+                Order o = clazz.getAnnotation(Order.class);
+                Integer weight = o.value();
+                if (o != null) {
+                    ordered.add(new WeightedFactory(weight, clazz));
+                }
+            } catch (Exception ex) {
+
+            }
+        }
+        for (WeightedFactory wf : ordered) {
+            addFactory(wf.factoryClass);
+        }
+        return new Factory();
+    }
+
+    private static void addFactory(String factoryClass) {
+        try {
+            Class clazz = Class.forName(factoryClass);
+            addFactory(clazz);
+        } catch (ClassNotFoundException ex) {
+            logger.error("Unable to load class " + factoryClass, ex);
+        } catch (Exception ex) {
+            logger.error("Unable to load class " + factoryClass, ex);
+        }
+    }
+
+    private static void addFactory(Class factoryClass) {
+        try {
+            factories.add((ConfigurationFactory) factoryClass.newInstance());
+        } catch (Exception ex) {
+            logger.error("Unable to create instance of " + factoryClass.getName(), ex);
+        }
+    }
+
+    public static void setConfigurationFactory(ConfigurationFactory factory) {
+        factories.add(0, factory);
+    }
+
+    public static void removeConfigurationFactory(ConfigurationFactory factory) {
+        factories.remove(factory);
+    }
+
+    public abstract Configuration getConfiguration();
+
+    private static class WeightedFactory implements Comparable<WeightedFactory> {
+        private int weight;
+        private Class<ConfigurationFactory> factoryClass;
+
+        public WeightedFactory(int weight, Class<ConfigurationFactory> clazz) {
+            this.weight = weight;
+            this.factoryClass = clazz;
+        }
+
+        public int compareTo(WeightedFactory wf) {
+            int w = wf.weight;
+            if (weight == w) {
+                return 0;
+            } else if (weight > w) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }
+    }
+
+    private static class Factory extends ConfigurationFactory {
+
+        public Configuration getConfiguration() {
+
+            for (ConfigurationFactory factory : factories) {
+                Configuration c = factory.getConfiguration();
+                if (c != null) {
+                    return c;
+                }
+            }
+            return new DefaultConfiguration();
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
new file mode 100644
index 0000000..fdfd2e4
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
@@ -0,0 +1,59 @@
+/*
+ * 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.config;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+
+/**
+ *
+ */
+public class DefaultConfiguration extends BaseConfiguration {
+
+    private static final String CONSOLE = "CONSOLE";;
+    private static final String DEFAULT_LEVEL = "org.apache.logging.log4j.level";
+    private static final String EMPTY_STRING = "";
+
+    public DefaultConfiguration() {
+
+        Appender appender = new ConsoleAppender("Console", new BasicLayout());
+        addAppender(appender);
+        LoggerConfig root = getRootLogger();
+        root.addAppender(appender);
+        String l = System.getProperty(DEFAULT_LEVEL);
+        Level level = (l != null && Level.valueOf(l) != null) ? Level.valueOf(l) : Level.ERROR;
+        root.setLevel(level);
+    }
+
+    public class BasicLayout implements Layout {
+        public byte[] format(LogEvent event) {
+            String result = event.getMessage().getFormattedMessage() + "\n";
+            return result.getBytes();
+        }
+
+        public byte[] getHeader() {
+            return EMPTY_STRING.getBytes();
+        }
+
+        public byte[] getFooter() {
+            return EMPTY_STRING.getBytes();
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
new file mode 100644
index 0000000..6164dc0
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
@@ -0,0 +1,264 @@
+/*
+ * 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.config;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Log4jLogEvent;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LogEventFactory;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.internal.StatusLogger;
+import org.apache.logging.log4j.message.Message;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ *
+ */
+@Plugin(name="logger",type="Core")
+public class LoggerConfig implements LogEventFactory {
+
+    private List<String> appenderRefs = new ArrayList<String>();
+    private Map<String, AppenderControl> appenders = new ConcurrentHashMap<String, AppenderControl>();
+
+    private List<Filter> filters = new CopyOnWriteArrayList<Filter>();
+    private boolean hasFilters = false;
+
+    private final String name;
+
+    private LogEventFactory logEventFactory;
+
+    private Level level;
+
+    private boolean additive = true;
+
+    private LoggerConfig parent;
+
+    private static Logger logger = StatusLogger.getLogger();
+
+    public LoggerConfig() {
+        this.logEventFactory = this;
+        this.level = Level.ERROR;
+        this.name = "";
+    }
+
+    public LoggerConfig(String name, Level level, boolean additive) {
+        this.logEventFactory = this;
+        this.name = name;
+        this.level = level;
+        this.additive = additive;
+    }
+
+    protected LoggerConfig(String name, List<String> appenders, Filter[] filters, Level level,
+                           boolean additive) {
+        this.logEventFactory = this;        
+        this.name = name;
+        this.appenderRefs = appenders;
+        if (filters != null && filters.length > 0) {
+            this.filters = new CopyOnWriteArrayList<Filter>(filters);
+            hasFilters = true;
+        }
+        this.level = level;
+        this.additive = additive;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setParent(LoggerConfig parent) {
+        this.parent = parent;
+    }
+
+    public void addAppender(Appender appender) {
+        appenders.put(appender.getName(), new AppenderControl(appender));
+    }
+
+    public void removeAppender(String name) {
+        appenders.remove(name);
+    }
+
+    public Map<String, Appender> getAppenders() {
+        Map<String, Appender> map = new HashMap<String, Appender>();
+        for (Map.Entry<String, AppenderControl> entry : appenders.entrySet()) {
+            map.put(entry.getKey(), entry.getValue().getAppender());
+        }
+        return map;
+    }
+
+    protected void clearAppenders() {
+        appenders.clear();
+    }
+
+    public List<String> getAppenderRefs() {
+        return appenderRefs;
+    }
+
+    public void setLevel(Level level) {
+        this.level = level;
+    }
+
+    public Level getLevel() {
+        return level;
+    }
+
+    public LogEventFactory getLogEventFactory() {
+        return logEventFactory;
+    }
+
+    public void setLogEventFactory(LogEventFactory logEventFactory) {
+        this.logEventFactory = logEventFactory;
+    }
+
+    public void addFilter(Filter filter) {
+        filters.add(filter);
+        hasFilters = filters.size() > 0;
+    }
+
+    public void removeFilter(Filter filter) {
+        filters.remove(filter);
+        hasFilters = filters.size() > 0;
+    }
+
+    public List<Filter> getFilters() {
+        return Collections.unmodifiableList(filters);
+    }
+
+    public boolean isAdditive() {
+        return additive;
+    }
+
+    public void log(String loggerName, Marker marker, String fqcn, Level level, Message data, Throwable t) {
+        LogEvent event = logEventFactory.createEvent(loggerName, marker, fqcn, level, data, t);
+        log(event);
+    }
+
+    private void log(LogEvent event) {
+        if (hasFilters) {
+            for (Filter filter : filters) {
+                if (filter.filter(event) == Filter.Result.DENY) {
+                    return;
+                }
+            }
+        }
+
+        callAppenders(event);
+
+        if (additive && parent != null) {
+            parent.log(event);
+        }
+    }
+
+    private void callAppenders(LogEvent event) {
+        for (AppenderControl control: appenders.values()) {
+            control.callAppender(event);
+        }
+    }
+
+    public LogEvent createEvent(String loggerName, Marker marker, String fqcn, Level level, Message data,
+                                Throwable t) {
+        return new Log4jLogEvent(loggerName, marker, fqcn, level, data, t);
+    }
+
+    @PluginFactory
+    public static LoggerConfig createLogger(Node node) {
+        Map<String, String> map = node.getAttributes();
+        List<String> appenderRefs = new ArrayList<String>();
+        Filter[] filters = null;
+        boolean additive = true;
+        Level level = Level.ERROR;
+        String name = null;
+
+        for (Map.Entry<String, String> entry : map.entrySet()) {
+            String key = entry.getKey();
+            if (key.equalsIgnoreCase("additivity"))  {
+                additive = Boolean.parseBoolean(entry.getValue());
+            }
+            if (key.equalsIgnoreCase("level")) {
+                Level l = Level.valueOf(entry.getValue().toUpperCase());
+                if (l != null) {
+                    level = l;
+                }
+            }
+            if (key.equalsIgnoreCase("name")) {
+                name = entry.getValue();
+            }
+        }
+
+        if (node.getName().equals("root")) {
+            name = "";
+        }
+
+        if (name == null) {
+            logger.error("Loggers cannot be configured without a name");
+            return null;
+        }
+
+        for (Node child : node.getChildren()) {
+            Object obj = child.getObject();
+            if (obj != null) {
+                if (obj instanceof String) {
+                    appenderRefs.add((String) obj);
+                } else if (obj instanceof Filter[]) {
+                    filters = (Filter[]) obj;
+                }
+            }
+        }
+
+        return new LoggerConfig(name, appenderRefs, filters, level, additive);
+    }
+    /*
+    @Plugin("appender-refs")
+    public static class AppenderRefs {
+
+        @PluginFactory
+        public static String[] createAppenderRefs(Node node) {
+            String[] refs = new String[node.getChildren().size()];
+            int i = 0;
+            for (Node child : node.getChildren()) {
+                refs[i++] = (String) child.getObject();
+            }
+            return refs;
+        }
+    } */
+
+    @Plugin(name="appender-ref",type="Core")
+    public static class AppenderRef {
+
+        @PluginFactory
+        public static String createAppenderRef(Node node) {
+            Map<String, String> attrs = node.getAttributes();
+            for (Map.Entry<String, String> attr : attrs.entrySet()) {
+                if (attr.getKey().equalsIgnoreCase("ref")) {
+                    return attr.getValue();
+                }
+            }
+            return null;
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/Node.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
new file mode 100644
index 0000000..9d4f85b
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
@@ -0,0 +1,100 @@
+/*
+ * 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.config;
+
+import org.apache.logging.log4j.core.config.plugins.PluginType;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+
+public class Node {
+
+    private Node parent;
+    private String name;
+    private String value;
+    private PluginType type;
+    private Map<String, String> attributes = new HashMap<String, String>();
+    private List<Node> children = new ArrayList<Node>();
+    private Object object;
+    private Configuration config;
+
+
+    /**
+     * Creates a new instance of <code>Node</code> and initializes it
+     * with a name and the corresponding XML element.
+     *
+     * @param parent the node's parent.
+     * @param name the node's name.
+     * @param type The Plugin Type associated with the node.
+     */
+    public Node(Node parent, String name, PluginType type) {
+        this.parent = parent;
+        this.name = name;
+        this.type = type;
+        this.config = parent.config;
+    }
+
+    public Node(Configuration config) {
+        this.config = config;
+    }
+
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
+
+    public List<Node> getChildren() {
+        return children;
+    }
+
+    public boolean hasChildren() {
+        return children.size() > 0;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public Node getParent() {
+        return parent;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public boolean isRoot() {
+        return parent == null;
+    }
+
+    public void setObject(Object obj) {
+        object = obj;
+    }
+
+    public Object getObject() {
+        return object;
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/Order.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/Order.java
new file mode 100644
index 0000000..c1b6546
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/Order.java
@@ -0,0 +1,15 @@
+package org.apache.logging.log4j.core.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Order {
+    public int value();
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java
new file mode 100644
index 0000000..367f6de
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java
@@ -0,0 +1,213 @@
+/*
+ * 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.config;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.config.plugins.PluginManager;
+import org.apache.logging.log4j.core.config.plugins.PluginType;
+import org.apache.logging.log4j.core.config.plugins.ResolverUtil;
+import org.apache.logging.log4j.internal.StatusConsoleListener;
+import org.apache.logging.log4j.internal.StatusLogger;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Creates a Node hierarchy from an XML file.
+ */
+public class XMLConfiguration extends BaseConfiguration {
+
+    private List<Status> status = new ArrayList<Status>();
+
+    private Element rootElement = null;
+
+    private static final String[] verboseClasses = new String[] { ResolverUtil.class.getName() };
+
+    public XMLConfiguration(InputSource source) {
+        try {
+            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+            Document document = builder.parse(source);
+            rootElement = document.getDocumentElement();
+            Map<String, String> attrs = processAttributes(rootNode, rootElement);
+            boolean debug = false;
+            boolean verbose = false;
+
+            for (Map.Entry<String, String> entry : attrs.entrySet()) {
+                if ("debug".equalsIgnoreCase(entry.getKey())) {
+                    debug = Boolean.parseBoolean(entry.getValue());
+                } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
+                    verbose = Boolean.parseBoolean(entry.getValue());
+                } else if ("packages".equalsIgnoreCase(entry.getKey())) {
+                    String[] packages = entry.getValue().split(",");
+                    for (String p : packages) {
+                        PluginManager.addPackage(p);
+                    }
+                } else if ("name".equalsIgnoreCase(entry.getKey())) {
+                    setName(entry.getValue());
+                }
+            }
+            if (debug) {
+                StatusConsoleListener listener = new StatusConsoleListener(Level.DEBUG);
+                if (!verbose) {
+                    listener.setFilters(verboseClasses);
+                }
+                ((StatusLogger) logger).registerListener(listener);
+            }
+
+        } catch (SAXException domEx) {
+            logger.error("Error parsing " + source.getSystemId(), domEx);
+        } catch (IOException ioe) {
+            logger.error("Error parsing " + source.getSystemId(), ioe);
+        } catch (ParserConfigurationException pex) {
+            logger.error("Error parsing " + source.getSystemId(), pex);
+        }
+    }
+
+    public void setup() {
+        constructHierarchy(rootNode, rootElement);
+        if (status.size() > 0) {
+            for (Status s : status) {
+                logger.error("Error processing element " + s.name + ": " + s.errorType);
+            }
+            return;
+        }
+        rootElement = null;
+    }
+
+    private void constructHierarchy(Node node, Element element) {
+        processAttributes(node, element);
+        StringBuffer buffer = new StringBuffer();
+        NodeList list = element.getChildNodes();
+        List<Node> children = node.getChildren();
+        for (int i = 0; i < list.getLength(); i++) {
+            org.w3c.dom.Node w3cNode = list.item(i);
+            if (w3cNode instanceof Element) {
+                Element child = (Element) w3cNode;
+                String name = child.getTagName();
+                PluginType type = getPluginManager().getPluginType(name);
+                Node childNode = new Node(node, name, type);
+                constructHierarchy(childNode, child);
+                if (type == null) {
+                    String value = childNode.getValue();
+                    if (!childNode.hasChildren() && value != null) {
+                        node.getAttributes().put(name, value);
+                    } else {
+                        status.add(new Status(name, element, ErrorType.CLASS_NOT_FOUND));
+                    }
+                } else {
+                    children.add(childNode);
+                }
+            } else if (w3cNode instanceof Text) {
+                Text data = (Text) w3cNode;
+                buffer.append(data.getData());
+            }
+        }
+
+        String text = buffer.toString().trim();
+        if (text.length() > 0 || (!node.hasChildren() && !node.isRoot())) {
+            node.setValue(text);
+        }
+    }
+
+    private Map<String, String> processAttributes(Node node, Element element) {
+        NamedNodeMap attrs = element.getAttributes();
+        Map<String, String> attributes = node.getAttributes();
+
+        for (int i = 0; i < attrs.getLength(); ++i) {
+            org.w3c.dom.Node w3cNode = attrs.item(i);
+            if (w3cNode instanceof Attr) {
+                Attr attr = (Attr) w3cNode;
+                attributes.put(attr.getName(), attr.getValue());
+            }
+        }
+        return attributes;
+    }
+
+    private enum ErrorType {
+        CLASS_NOT_FOUND
+    }
+
+    private class Status {
+        Element element;
+        String name;
+        ErrorType errorType;
+
+        public Status(String name, Element element, ErrorType errorType) {
+            this.name = name;
+            this.element = element;
+            this.errorType = errorType;
+        }
+    }
+
+    @Plugin(name = "root", type = "Core")
+    public static class RootLogger extends LoggerConfig {
+
+        @PluginFactory
+        public static LoggerConfig createLogger(Node node) {
+            Map<String, String> map = node.getAttributes();
+            List<String> appenderRefs = new ArrayList<String>();
+            Filter[] filters = null;
+            boolean additive = false;
+            Level level = Level.ERROR;
+            String name = "";
+
+            for (Map.Entry<String, String> entry : map.entrySet()) {
+                String key = entry.getKey();
+                if (key.equalsIgnoreCase("level")) {
+                    Level l = Level.valueOf(entry.getValue().toUpperCase());
+                    if (l != null) {
+                        level = l;
+                    }
+                } else {
+                    logger.warn("Unsupported key " + key + " ignored on root logger");
+                }
+
+            }
+
+            for (Node child : node.getChildren()) {
+                Object obj = child.getObject();
+                if (obj != null) {
+                    if (obj instanceof String) {
+                        appenderRefs.add((String) obj);
+                    } else if (obj instanceof Filter[]) {
+                        filters = (Filter[]) obj;
+                    }
+                }
+            }
+
+            return new LoggerConfig(name, appenderRefs, filters, level, additive);
+        }
+    }
+
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfigurationFactory.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfigurationFactory.java
new file mode 100644
index 0000000..ba2eb79
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfigurationFactory.java
@@ -0,0 +1,90 @@
+/*
+ * 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.config;
+
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.xml.sax.InputSource;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ *
+ */
+@Plugin(name="XMLConfigurationFactory", type="ConfigurationFactory")
+@Order(1)
+public class XMLConfigurationFactory extends ConfigurationFactory {
+
+    public static final String CONFIGURATION_FILE_PROPERTY = "log4j.configurationFile";
+
+    public static final String DEFAULT_CONFIG_FILE = "log4j2.xml";
+
+    public static final String TEST_CONFIG_FILE = "log4j2-test.xml";
+
+    public Configuration getConfiguration() {
+        ClassLoader loader = this.getClass().getClassLoader();
+        InputSource source = getInputFromSystemProperty(loader);
+        if (source == null) {
+            source = getInputFromResource(TEST_CONFIG_FILE, loader);
+            if (source == null) {
+                source = getInputFromResource(DEFAULT_CONFIG_FILE, loader);
+            }
+            if (source == null) {
+                return null;
+            }
+        }
+        return new XMLConfiguration(source);
+    }
+
+    private InputSource getInputFromSystemProperty(ClassLoader loader) {
+        String configFile = System.getProperty(CONFIGURATION_FILE_PROPERTY);
+        if (configFile == null) {
+            return null;
+        }
+        InputSource source;
+        try {
+            URL url = new URL(configFile);
+            source = new InputSource(url.openStream());
+            source.setSystemId(configFile);
+            return source;
+        } catch (Exception ex) {
+            source = getInputFromResource(configFile, loader);
+            if (source == null) {
+                try {
+                    InputStream is = new FileInputStream(configFile);
+                    source = new InputSource(is);
+                    source.setSystemId(configFile);
+                } catch (FileNotFoundException fnfe) {
+                    // Ignore the exception
+                }
+            }
+        }
+        return source;
+    }
+
+    private InputSource getInputFromResource(String resource, ClassLoader loader) {
+        InputStream is = loader.getResourceAsStream(resource);
+        if (is == null) {
+            return null;
+        }
+        InputSource source = new InputSource(is);
+        source.setSystemId(resource);
+        return source;
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
new file mode 100644
index 0000000..776592c
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
@@ -0,0 +1,17 @@
+package org.apache.logging.log4j.core.config.plugins;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Plugin {
+
+    public String name();
+    public String type();
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
new file mode 100644
index 0000000..a1a8f8c
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
@@ -0,0 +1,15 @@
+package org.apache.logging.log4j.core.config.plugins;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface PluginFactory {
+  
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginManager.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginManager.java
new file mode 100644
index 0000000..8f861d9
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginManager.java
@@ -0,0 +1,94 @@
+/*
+ * 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.config.plugins;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ *
+ */
+public class PluginManager {
+
+
+    private Map<String, PluginType> plugins = new HashMap<String, PluginType>();
+
+    private static CopyOnWriteArrayList<String> packages = new CopyOnWriteArrayList<String>();
+
+    private final String type;
+
+    static {
+        packages.add("org.apache.logging.log4j");
+    }
+
+    public PluginManager(String type) {
+        this.type = type;
+    }
+
+    public static void addPackage(String p) {
+        packages.addIfAbsent(p);
+    }
+
+    public PluginType getPluginType(String name) {
+        return plugins.get(name);
+    }
+
+    public Map<String, PluginType> getPlugins() {
+        return plugins;
+    }
+
+
+    public void collectPlugins() {
+        ResolverUtil<?> r = new ResolverUtil();
+        ResolverUtil.Test test = new PluginTest(type);
+        for (String pkg : packages) {
+            r.findInPackage(test, pkg);
+        }
+        for (Class<?> item : r.getClasses())
+        {
+            Plugin p = item.getAnnotation(Plugin.class);
+            plugins.put(p.name(), new PluginType(item));
+        }
+    }
+
+
+    /**
+     * A Test that checks to see if each class is annotated with a specific annotation. If it
+     * is, then the test returns true, otherwise false.
+     */
+    public static class PluginTest extends ResolverUtil.ClassTest {
+        private String type;
+
+        /** Constructs an AnnotatedWith test for the specified annotation type. */
+        public PluginTest(String type) {
+            this.type = type;
+        }
+
+        /** Returns true if the type is annotated with the class provided to the constructor. */
+        public boolean matches(Class type) {
+            return type != null && type.isAnnotationPresent(Plugin.class) &&
+                this.type.equals(((Plugin)type.getAnnotation(Plugin.class)).type());
+        }
+
+        @Override public String toString() {
+            return "annotated with @" + Plugin.class.getSimpleName();
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginType.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginType.java
new file mode 100644
index 0000000..cd6bf2f
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginType.java
@@ -0,0 +1,35 @@
+/*
+ * 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.config.plugins;
+
+
+/**
+ *
+ */
+public class PluginType {
+
+    private Class pluginClass;
+
+    public PluginType(Class clazz) {
+        this.pluginClass = clazz;
+    }
+
+    public Class getPluginClass() {
+        return this.pluginClass;
+    }
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/ResolverUtil.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/ResolverUtil.java
new file mode 100644
index 0000000..e84b689
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/plugins/ResolverUtil.java
@@ -0,0 +1,458 @@
+/* Copyright 2005-2006 Tim Fennell
+ *
+ * Licensed 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.config.plugins;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.internal.StatusLogger;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+/**
+ * <p>ResolverUtil is used to locate classes that are available in the/a class path and meet
+ * arbitrary conditions. The two most common conditions are that a class implements/extends
+ * another class, or that is it annotated with a specific annotation. However, through the use
+ * of the {@link Test} class it is possible to search using arbitrary conditions.</p>
+ *
+ * <p>A ClassLoader is used to locate all locations (directories and jar files) in the class
+ * path that contain classes within certain packages, and then to load those classes and
+ * check them. By default the ClassLoader returned by
+ *  {@code Thread.currentThread().getContextClassLoader()} is used, but this can be overridden
+ * by calling {@link #setClassLoader(ClassLoader)} prior to invoking any of the {@code find()}
+ * methods.</p>
+ *
+ * <p>General searches are initiated by calling the
+ * {@link #find(org.apache.logging.log4j.core..util.ResolverUtil.Test, String...)} ()} method and supplying
+ * a package name and a Test instance. This will cause the named package <b>and all sub-packages</b>
+ * to be scanned for classes that meet the test. There are also utility methods for the common
+ * use cases of scanning multiple packages for extensions of particular classes, or classes
+ * annotated with a specific annotation.</p>
+ *
+ * <p>The standard usage pattern for the ResolverUtil class is as follows:</p>
+ *
+ *<pre>
+ *ResolverUtil&lt;ActionBean&gt; resolver = new ResolverUtil&lt;ActionBean&gt;();
+ *resolver.findImplementation(ActionBean.class, pkg1, pkg2);
+ *resolver.find(new CustomTest(), pkg1);
+ *resolver.find(new CustomTest(), pkg2);
+ *Collection&lt;ActionBean&gt; beans = resolver.getClasses();
+ *</pre>
+ *
+ * <p>This class was copied from Stripes - http://stripes.mc4j.org/confluence/display/stripes/Home
+ * </p>
+ *
+ * @author Tim Fennell
+ */
+public class ResolverUtil<T> {
+    /** An instance of Log to use for logging in this class. */
+    private static final Logger LOG = StatusLogger.getLogger();
+
+    /**
+     * A simple interface that specifies how to test classes to determine if they
+     * are to be included in the results produced by the ResolverUtil.
+     */
+    public static interface Test {
+        /**
+         * Will be called repeatedly with candidate classes. Must return True if a class
+         * is to be included in the results, false otherwise.
+         */
+        boolean matches(Class type);
+
+        boolean matches(URL resource);
+
+        boolean doesMatchClass();
+        boolean doesMatchResource();
+    }
+
+    public static abstract class ClassTest implements Test {
+        public boolean matches(URL resource) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean doesMatchClass() {
+            return true;
+        }
+        public boolean doesMatchResource() {
+            return false;
+        }
+    }
+
+    public static abstract class ResourceTest implements Test {
+        public boolean matches(Class cls) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean doesMatchClass() {
+            return false;
+        }
+        public boolean doesMatchResource() {
+            return true;
+        }
+    }
+
+    /**
+     * A Test that checks to see if each class is assignable to the provided class. Note
+     * that this test will match the parent type itself if it is presented for matching.
+     */
+    public static class IsA extends ClassTest {
+        private Class parent;
+
+        /** Constructs an IsA test using the supplied Class as the parent class/interface. */
+        public IsA(Class parentType) { this.parent = parentType; }
+
+        /** Returns true if type is assignable to the parent type supplied in the constructor. */
+        public boolean matches(Class type) {
+            return type != null && parent.isAssignableFrom(type);
+        }
+
+        @Override public String toString() {
+            return "is assignable to " + parent.getSimpleName();
+        }
+    }
+
+    /**
+     * A Test that checks to see if each class name ends with the provided suffix.
+     */
+    public static class NameEndsWith extends ClassTest {
+        private String suffix;
+
+        /** Constructs a NameEndsWith test using the supplied suffix. */
+        public NameEndsWith(String suffix) { this.suffix = suffix; }
+
+        /** Returns true if type name ends with the suffix supplied in the constructor. */
+        public boolean matches(Class type) {
+            return type != null && type.getName().endsWith(suffix);
+        }
+
+        @Override public String toString() {
+            return "ends with the suffix " + suffix;
+        }
+    }
+
+    /**
+     * A Test that checks to see if each class is annotated with a specific annotation. If it
+     * is, then the test returns true, otherwise false.
+     */
+    public static class AnnotatedWith extends ClassTest {
+        private Class<? extends Annotation> annotation;
+
+        /** Construts an AnnotatedWith test for the specified annotation type. */
+        public AnnotatedWith(Class<? extends Annotation> annotation) { this.annotation = annotation; }
+
+        /** Returns true if the type is annotated with the class provided to the constructor. */
+        public boolean matches(Class type) {
+            return type != null && type.isAnnotationPresent(annotation);
+        }
+
+        @Override public String toString() {
+            return "annotated with @" + annotation.getSimpleName();
+        }
+    }
+
+    public static class NameIs extends ResourceTest {
+        private String name;
+
+        public NameIs(String name) { this.name = "/" + name; }
+
+        public boolean matches(URL resource) {
+            return (resource.getPath().endsWith(name));
+        }
+
+        @Override public String toString() {
+            return "named " + name;
+        }
+    }
+
+    /** The set of matches being accumulated. */
+    private Set<Class<? extends T>> classMatches = new HashSet<Class<?extends T>>();
+
+    /** The set of matches being accumulated. */
+    private Set<URL> resourceMatches = new HashSet<URL>();
+
+    /**
+     * The ClassLoader to use when looking for classes. If null then the ClassLoader returned
+     * by Thread.currentThread().getContextClassLoader() will be used.
+     */
+    private ClassLoader classloader;
+
+    /**
+     * Provides access to the classes discovered so far. If no calls have been made to
+     * any of the {@code find()} methods, this set will be empty.
+     *
+     * @return the set of classes that have been discovered.
+     */
+    public Set<Class<? extends T>> getClasses() {
+        return classMatches;
+    }
+
+    public Set<URL> getResources() {
+        return resourceMatches;
+    }
+
+
+    /**
+     * Returns the classloader that will be used for scanning for classes. If no explicit
+     * ClassLoader has been set by the calling, the context class loader will be used.
+     *
+     * @return the ClassLoader that will be used to scan for classes
+     */
+    public ClassLoader getClassLoader() {
+        return classloader == null ? Thread.currentThread().getContextClassLoader() : classloader;
+    }
+
+    /**
+     * Sets an explicit ClassLoader that should be used when scanning for classes. If none
+     * is set then the context classloader will be used.
+     *
+     * @param classloader a ClassLoader to use when scanning for classes
+     */
+    public void setClassLoader(ClassLoader classloader) { this.classloader = classloader; }
+
+    /**
+     * Attempts to discover classes that are assignable to the type provided. In the case
+     * that an interface is provided this method will collect implementations. In the case
+     * of a non-interface class, subclasses will be collected.  Accumulated classes can be
+     * accessed by calling {@link #getClasses()}.
+     *
+     * @param parent the class of interface to find subclasses or implementations of
+     * @param packageNames one or more package names to scan (including subpackages) for classes
+     */
+    public void findImplementations(Class parent, String... packageNames) {
+        if (packageNames == null) return;
+
+        Test test = new IsA(parent);
+        for (String pkg : packageNames) {
+            findInPackage(test, pkg);
+        }
+    }
+
+    /**
+     * Attempts to discover classes who's name ends with the provided suffix. Accumulated classes can be
+     * accessed by calling {@link #getClasses()}.
+     *
+     * @param suffix The class name suffix to match
+     * @param packageNames one or more package names to scan (including subpackages) for classes
+     */
+    public void findSuffix(String suffix, String... packageNames) {
+        if (packageNames == null) return;
+
+        Test test = new NameEndsWith(suffix);
+        for (String pkg : packageNames) {
+            findInPackage(test, pkg);
+        }
+    }
+
+    /**
+     * Attempts to discover classes that are annotated with to the annotation. Accumulated
+     * classes can be accessed by calling {@link #getClasses()}.
+     *
+     * @param annotation the annotation that should be present on matching classes
+     * @param packageNames one or more package names to scan (including subpackages) for classes
+     */
+    public void findAnnotated(Class<? extends Annotation> annotation, String... packageNames) {
+        if (packageNames == null) return;
+
+        Test test = new AnnotatedWith(annotation);
+        for (String pkg : packageNames) {
+            findInPackage(test, pkg);
+        }
+    }
+
+    public void findNamedResource(String name, String... pathNames) {
+        if (pathNames == null) return;
+
+        Test test = new NameIs(name);
+        for (String pkg : pathNames) {
+            findInPackage(test, pkg);
+        }
+    }
+
+    /**
+     * Attempts to discover classes that pass the test. Accumulated
+     * classes can be accessed by calling {@link #getClasses()}.
+     *
+     * @param test the test to determine matching classes
+     * @param packageNames one or more package names to scan (including subpackages) for classes
+     */
+    public void find(Test test, String... packageNames) {
+        if (packageNames == null) return;
+
+        for (String pkg : packageNames) {
+            findInPackage(test, pkg);
+        }
+    }
+
+    /**
+     * Scans for classes starting at the package provided and descending into subpackages.
+     * Each class is offered up to the Test as it is discovered, and if the Test returns
+     * true the class is retained.  Accumulated classes can be fetched by calling
+     * {@link #getClasses()}.
+     *
+     * @param test an instance of {@link Test} that will be used to filter classes
+     * @param packageName the name of the package from which to start scanning for
+     *        classes, e.g. {@code net.sourceforge.stripes}
+     */
+    public void findInPackage(Test test, String packageName) {
+        packageName = packageName.replace('.', '/');
+        ClassLoader loader = getClassLoader();
+        Enumeration<URL> urls;
+
+        try {
+            urls = loader.getResources(packageName);
+        }
+        catch (IOException ioe) {
+            LOG.warn("Could not read package: " + packageName, ioe);
+            return;
+        }
+
+        while (urls.hasMoreElements()) {
+            try {
+                String urlPath = urls.nextElement().getFile();
+                urlPath = URLDecoder.decode(urlPath, "UTF-8");
+
+                // If it's a file in a directory, trim the stupid file: spec
+                if ( urlPath.startsWith("file:") ) {
+                    urlPath = urlPath.substring(5);
+                }
+
+                // Else it's in a JAR, grab the path to the jar
+                if (urlPath.indexOf('!') > 0) {
+                    urlPath = urlPath.substring(0, urlPath.indexOf('!'));
+                }
+
+                LOG.info("Scanning for classes in [" + urlPath + "] matching criteria: " + test);
+                File file = new File(urlPath);
+                if ( file.isDirectory() ) {
+                    loadImplementationsInDirectory(test, packageName, file);
+                }
+                else {
+                    loadImplementationsInJar(test, packageName, file);
+                }
+            }
+            catch (IOException ioe) {
+                LOG.warn("could not read entries", ioe);
+            }
+        }
+    }
+
+
+    /**
+     * Finds matches in a physical directory on a filesystem.  Examines all
+     * files within a directory - if the File object is not a directory, and ends with <i>.class</i>
+     * the file is loaded and tested to see if it is acceptable according to the Test.  Operates
+     * recursively to find classes within a folder structure matching the package structure.
+     *
+     * @param test a Test used to filter the classes that are discovered
+     * @param parent the package name up to this directory in the package hierarchy.  E.g. if
+     *        /classes is in the classpath and we wish to examine files in /classes/org/apache then
+     *        the values of <i>parent</i> would be <i>org/apache</i>
+     * @param location a File object representing a directory
+     */
+    private void loadImplementationsInDirectory(Test test, String parent, File location) {
+        File[] files = location.listFiles();
+        StringBuilder builder = null;
+
+        for (File file : files) {
+            builder = new StringBuilder(100);
+            builder.append(parent).append("/").append(file.getName());
+            String packageOrClass = ( parent == null ? file.getName() : builder.toString() );
+
+            if (file.isDirectory()) {
+                loadImplementationsInDirectory(test, packageOrClass, file);
+            }
+            else if (isTestApplicable(test, file.getName())) {
+                addIfMatching(test, packageOrClass);
+            }
+        }
+    }
+
+    private boolean isTestApplicable(Test test, String path) {
+        return test.doesMatchResource() || path.endsWith(".class") && test.doesMatchClass();
+    }
+
+    /**
+     * Finds matching classes within a jar files that contains a folder structure
+     * matching the package structure.  If the File is not a JarFile or does not exist a warning
+     * will be logged, but no error will be raised.
+     *
+     * @param test a Test used to filter the classes that are discovered
+     * @param parent the parent package under which classes must be in order to be considered
+     * @param jarfile the jar file to be examined for classes
+     */
+    private void loadImplementationsInJar(Test test, String parent, File jarfile) {
+
+        try {
+            JarEntry entry;
+            JarInputStream jarStream = new JarInputStream(new FileInputStream(jarfile));
+
+            while ( (entry = jarStream.getNextJarEntry() ) != null) {
+                String name = entry.getName();
+                if (!entry.isDirectory() && name.startsWith(parent) && isTestApplicable(test, name)) {
+                    addIfMatching(test, name);
+                }
+            }
+        }
+        catch (IOException ioe) {
+            LOG.error("Could not search jar file '" + jarfile + "' for classes matching criteria: " +
+                      test + " due to an IOException", ioe);
+        }
+    }
+
+    /**
+     * Add the class designated by the fully qualified class name provided to the set of
+     * resolved classes if and only if it is approved by the Test supplied.
+     *
+     * @param test the test used to determine if the class matches
+     * @param fqn the fully qualified name of a class
+     */
+    protected void addIfMatching(Test test, String fqn) {
+        try {
+            ClassLoader loader = getClassLoader();
+            if (test.doesMatchClass()) {
+                String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Checking to see if class " + externalName + " matches criteria [" + test + "]");
+                }
+
+                Class type = loader.loadClass(externalName);
+                if (test.matches(type) ) {
+                    classMatches.add( (Class<T>) type);
+                }
+            }
+            if (test.doesMatchResource()) {
+                URL url = loader.getResource(fqn);
+                if (url == null) {
+                    url = loader.getResource(fqn.substring(1));
+                }
+                if (url != null && test.matches(url)) {
+                    resourceMatches.add(url);
+                }
+            }
+        }
+        catch (Throwable t) {
+            LOG.warn("Could not examine class '" + fqn + "' due to a " +
+                     t.getClass().getName() + " with message: " + t.getMessage());
+        }
+    }
+}
\ No newline at end of file
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/filter/FilterBase.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/filter/FilterBase.java
new file mode 100644
index 0000000..ba41b39
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/filter/FilterBase.java
@@ -0,0 +1,122 @@
+/*
+ * 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.filter;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.internal.StatusLogger;
+import org.apache.logging.log4j.message.Message;
+
+/**
+ * Users should extend this class to implement filters. Filters can be either context wide or attached to
+ * an appender. A filter may choose to support being called only from the context or only from an appender in
+ * which case it will only implement the required method(s). The rest will default to return NEUTRAL.
+ */
+public abstract class FilterBase implements Filter {
+
+    protected boolean started;
+
+    protected final Result onMatch;
+
+    protected final Result onMismatch;
+
+    protected static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
+
+    protected static final String ON_MATCH = "onmatch";
+    protected static final String ON_MISMATCH = "onmismatch";
+
+    protected FilterBase() {
+        this(null, null);
+    }
+
+    protected FilterBase(Result onMatch, Result onMismatch) {
+        this.onMatch = onMatch == null ? Result.ACCEPT : onMatch;
+        this.onMismatch = onMismatch == null ? Result.NEUTRAL : onMismatch;
+    }
+
+    public void start() {
+        started = true;
+    }
+
+    public boolean isStarted() {
+        return started;
+    }
+
+    public void stop() {
+        started = false;
+    }
+
+    public final Result getOnMismatch() {
+        return onMismatch;
+    }
+
+    public final Result getOnMatch() {
+        return onMatch;
+    }
+
+    /**
+     * Appender Filter method. The default returns NEUTRAL.
+     * @param logger the logger
+     * @param level
+     * @param marker
+     * @param msg
+     * @param params
+     * @return
+     */
+    public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
+        return Result.NEUTRAL;
+    }
+
+    /**
+     * Appender Filter method. The default returns NEUTRAL.
+     * @param logger
+     * @param level
+     * @param marker
+     * @param msg
+     * @param t
+     * @return
+     */
+    public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
+        return Result.NEUTRAL;
+    }
+
+    /**
+     * Appender Filter method. The default returns NEUTRAL.
+     * @param logger
+     * @param level
+     * @param marker
+     * @param msg
+     * @param t
+     * @return
+     */
+    public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
+        return Result.NEUTRAL;
+    }
+
+    /**
+     * Context Filter method. The default returns NEUTRAL.
+     * @param event
+     * @return
+     */
+    public Result filter(LogEvent event) {
+        return Result.NEUTRAL;
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/filter/MDCFilter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/filter/MDCFilter.java
new file mode 100644
index 0000000..1f801d3
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/filter/MDCFilter.java
@@ -0,0 +1,102 @@
+/*
+ * 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.filter;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.MDC;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.message.Message;
+
+import java.util.Map;
+
+/**
+ *
+ */
+@Plugin(name="MDC", type="Core")
+public class MDCFilter extends FilterBase {
+    private final String key;
+    private final String value;
+
+    private static final String KEY = "key";
+    private static final String VALUE = "value";
+
+    public MDCFilter(String key, String value, Result onMatch, Result onMismatch) {
+        super(onMatch, onMismatch);
+        if (key == null) {
+            throw new NullPointerException("key cannot be null");
+        }
+        if (value == null) {
+            throw new NullPointerException("value cannot be null");
+        }
+        this.key = key;
+        this.value = value;
+    }
+
+    public String getKey() {
+        return this.key;
+    }
+
+    public String getValue() {
+        return this.value;
+    }
+     public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
+        return filter(MDC.get(key));
+    }
+
+    public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
+        return filter(MDC.get(key));
+    }
+
+    public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
+        return filter(MDC.get(key));
+    }
+
+    @Override
+    public Result filter(LogEvent event) {
+        return filter(event.getContextMap().get(key));
+    }
+
+    private Result filter(Object val) {
+        return this.value.equals(val) ? onMatch : onMismatch;
+    }
+
+    @PluginFactory
+    public static MDCFilter createFilter(Node node) {
+        String key = null;
+        String value = null;
+        Result onMatch = null;
+        Result onMismatch = null;
+        for (Map.Entry<String, String> entry : node.getAttributes().entrySet()) {
+            String name = entry.getKey().toLowerCase();
+            if (name.equals(KEY)) {
+                key = entry.getValue();
+            } else if (name.equals(VALUE)) {
+                value = entry.getValue();
+            } else if (name.equals(ON_MATCH)) {
+                onMatch = Result.valueOf(entry.getValue());
+            } else if (name.equals(ON_MISMATCH)) {
+                onMismatch = Result.valueOf(entry.getValue());
+            }
+        }
+        return new MDCFilter(key, value, onMatch, onMismatch);
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/filter/ThresholdFilter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/filter/ThresholdFilter.java
new file mode 100644
index 0000000..e67747f
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/filter/ThresholdFilter.java
@@ -0,0 +1,89 @@
+/*
+ * 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.filter;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.message.Message;
+
+import java.util.Map;
+
+/**
+ * This filter returns the onMatch result if the level in the LogEvent is the same or more specific
+ * than the configured level and the onMismatch value otherwise. For example, if the ThresholdFilter
+ * is configured with Level ERROR and the LogEvent contains Level DEBUG then the onMismatch value will
+ * be returned since ERROR events are more specific than DEBUG.
+ *
+ * The default Level is ERROR.
+ */
+@Plugin(name="Threshold", type="Core")
+public class ThresholdFilter extends FilterBase {
+
+    private static final String LEVEL = "level";
+
+    private final Level level;
+
+    public ThresholdFilter(Level level, Result onMatch, Result onMismatch) {
+        super(onMatch, onMismatch);
+        this.level = level;
+    }
+
+    public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
+        return filter(level);
+    }
+
+    public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
+        return filter(level);
+    }
+
+    public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(LogEvent event) {
+        return filter(event.getLevel());
+    }
+
+    private Result filter(Level level) {
+        return this.level.greaterOrEqual(level) ? onMatch : onMismatch;
+    }
+
+    @PluginFactory
+    public static ThresholdFilter createFilter(Node node) {
+        Level level = null;
+        Result onMatch = null;
+        Result onMismatch = null;
+        for (Map.Entry<String, String> entry : node.getAttributes().entrySet()) {
+            String name = entry.getKey().toLowerCase();
+            if (name.equals(LEVEL)) {
+                level = Level.toLevel(entry.getValue().toUpperCase(), Level.ERROR);
+            } else if (name.equals(ON_MATCH)) {
+                onMatch = Result.valueOf(entry.getValue());
+            } else if (name.equals(ON_MISMATCH)) {
+                onMismatch = Result.valueOf(entry.getValue());
+            }
+        }
+        return new ThresholdFilter(level, onMatch, onMismatch);
+    }
+
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/helpers/Loader.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/helpers/Loader.java
new file mode 100644
index 0000000..4b99a41
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/helpers/Loader.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.logging.log4j.core.helpers;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.internal.StatusLogger;
+
+import java.net.URL;
+import java.lang.IllegalAccessException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.io.InterruptedIOException;
+
+
+/**
+ * Load resources (or images) from various sources.
+ */
+
+public class Loader {
+
+    static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
+
+    static private boolean ignoreTCL = false;
+
+    static Logger logger = StatusLogger.getLogger();
+
+    static {
+        String ignoreTCLProp = OptionConverter.getSystemProperty("log4j.ignoreTCL", null);
+        if (ignoreTCLProp != null) {
+            ignoreTCL = OptionConverter.toBoolean(ignoreTCLProp, true);
+        }
+    }
+
+    /**
+     * This method will search for <code>resource</code> in different
+     * places. The search order is as follows:
+     * <p/>
+     * <ol>
+     * <p/>
+     * <p><li>Search for <code>resource</code> using the thread context
+     * class loader under Java2. If that fails, search for
+     * <code>resource</code> using the class loader that loaded this
+     * class (<code>Loader</code>). Under JDK 1.1, only the the class
+     * loader that loaded this class (<code>Loader</code>) is used.
+     * <p/>
+     * <p><li>Try one last time with
+     * <code>ClassLoader.getSystemResource(resource)</code>, that is is
+     * using the system class loader in JDK 1.2 and virtual machine's
+     * built-in class loader in JDK 1.1.
+     * <p/>
+     * </ol>
+     */
+    static public URL getResource(String resource) {
+        ClassLoader classLoader = null;
+        URL url = null;
+
+        try {
+            classLoader = getTCL();
+            if (classLoader != null) {
+                logger.debug("Trying to find [" + resource + "] using context classloader "
+                        + classLoader + ".");
+                url = classLoader.getResource(resource);
+                if (url != null) {
+                    return url;
+                }
+            }
+
+            // We could not find resource. Ler us now try with the
+            // classloader that loaded this class.
+            classLoader = Loader.class.getClassLoader();
+            if (classLoader != null) {
+                logger.debug("Trying to find [" + resource + "] using " + classLoader
+                    + " class loader.");
+                url = classLoader.getResource(resource);
+                if (url != null) {
+                    return url;
+                }
+            }
+        } catch (IllegalAccessException t) {
+            logger.warn(TSTR, t);
+        } catch (InvocationTargetException t) {
+            if (t.getTargetException() instanceof InterruptedException
+                || t.getTargetException() instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            logger.warn(TSTR, t);
+        } catch (Throwable t) {
+            //
+            //  can't be InterruptedException or InterruptedIOException
+            //    since not declared, must be error or RuntimeError.
+            logger.warn(TSTR, t);
+        }
+
+        // Last ditch attempt: get the resource from the class path. It
+        // may be the case that clazz was loaded by the Extentsion class
+        // loader which the parent of the system class loader. Hence the
+        // code below.
+        logger.debug("Trying to find [" + resource + "] using ClassLoader.getSystemResource().");
+        return ClassLoader.getSystemResource(resource);
+    }
+
+    /**
+     * Get the Thread Context Loader which is a JDK 1.2 feature. If we
+     * are running under JDK 1.1 or anything else goes wrong the method
+     * returns <code>null<code>.
+     */
+    private static ClassLoader getTCL() throws IllegalAccessException, InvocationTargetException {
+        return Thread.currentThread().getContextClassLoader();
+    }
+
+    public static Class loadClass(String clazz) throws ClassNotFoundException {
+        // Just call Class.forName(clazz) if we are instructed to ignore the TCL.
+        if (ignoreTCL) {
+            return Class.forName(clazz);
+        } else {
+            try {
+                return getTCL().loadClass(clazz);
+            }
+            catch (Throwable e) {
+                return Class.forName(clazz);
+            }
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/helpers/OptionConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/helpers/OptionConverter.java
new file mode 100644
index 0000000..c3fc0d7
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/helpers/OptionConverter.java
@@ -0,0 +1,347 @@
+/*
+ * 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.helpers;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.internal.StatusLogger;
+
+import java.util.Properties;
+
+/**
+ * A convenience class to convert property values to specific types.
+ */
+public class OptionConverter {
+
+    private static Logger logger = StatusLogger.getLogger();
+
+    static String DELIM_START = "${";
+    static char DELIM_STOP = '}';
+    static int DELIM_START_LEN = 2;
+    static int DELIM_STOP_LEN = 1;
+
+    /**
+     * OptionConverter is a static class.
+     */
+    private OptionConverter() {
+    }
+
+    public static String[] concatanateArrays(String[] l, String[] r) {
+        int len = l.length + r.length;
+        String[] a = new String[len];
+
+        System.arraycopy(l, 0, a, 0, l.length);
+        System.arraycopy(r, 0, a, l.length, r.length);
+
+        return a;
+    }
+
+    public static String convertSpecialChars(String s) {
+        char c;
+        int len = s.length();
+        StringBuffer sbuf = new StringBuffer(len);
+
+        int i = 0;
+        while (i < len) {
+            c = s.charAt(i++);
+            if (c == '\\') {
+                c = s.charAt(i++);
+                if (c == 'n') {
+                    c = '\n';
+                } else if (c == 'r') {
+                    c = '\r';
+                } else if (c == 't') {
+                    c = '\t';
+                } else if (c == 'f') {
+                    c = '\f';
+                } else if (c == '\b') {
+                    c = '\b';
+                } else if (c == '\"') {
+                    c = '\"';
+                } else if (c == '\'') {
+                    c = '\'';
+                } else if (c == '\\') {
+                    c = '\\';
+                }
+            }
+            sbuf.append(c);
+        }
+        return sbuf.toString();
+    }
+
+
+    /**
+     * Very similar to <code>System.getProperty</code> except
+     * that the {@link SecurityException} is hidden.
+     *
+     * @param key The key to search for.
+     * @param def The default value to return.
+     * @return the string value of the system property, or the default
+     *         value if there is no property with that key.
+     */
+    public static String getSystemProperty(String key, String def) {
+        try {
+            return System.getProperty(key, def);
+        } catch (Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx
+            logger.debug("Was not allowed to read system property \"" + key + "\".");
+            return def;
+        }
+    }
+
+
+    public static Object instantiateByKey(Properties props, String key, Class superClass,
+                                   Object defaultValue) {
+
+        // Get the value of the property in string form
+        String className = findAndSubst(key, props);
+        if (className == null) {
+            logger.error("Could not find value for key " + key);
+            return defaultValue;
+        }
+        // Trim className to avoid trailing spaces that cause problems.
+        return OptionConverter.instantiateByClassName(className.trim(), superClass,
+            defaultValue);
+    }
+
+    /**
+     * If <code>value</code> is "true", then <code>true</code> is
+     * returned. If <code>value</code> is "false", then
+     * <code>true</code> is returned. Otherwise, <code>default</code> is
+     * returned.
+     * <p/>
+     * <p>Case of value is unimportant.
+     */
+    public static boolean toBoolean(String value, boolean dEfault) {
+        if (value == null) {
+            return dEfault;
+        }
+        String trimmedVal = value.trim();
+        if ("true".equalsIgnoreCase(trimmedVal)) {
+            return true;
+        }
+        if ("false".equalsIgnoreCase(trimmedVal)) {
+            return false;
+        }
+        return dEfault;
+    }
+
+    /**
+     * Convert the String value to an int.
+     * @param value The value as a String.
+     * @param dEfault The default value.
+     * @return The value as an int.
+     */
+    public static int toInt(String value, int dEfault) {
+        if (value != null) {
+            String s = value.trim();
+            try {
+                return Integer.valueOf(s);
+            }
+            catch (NumberFormatException e) {
+                logger.error("[" + s + "] is not in proper int form.");
+                e.printStackTrace();
+            }
+        }
+        return dEfault;
+    }
+
+    /**
+     *
+     * @param value The size of the file as a String.
+     * @param dEfault The default value.
+     * @return The size of the file as a long.
+     */
+    public static long toFileSize(String value, long dEfault) {
+        if (value == null) {
+            return dEfault;
+        }
+
+        String s = value.trim().toUpperCase();
+        long multiplier = 1;
+        int index;
+
+        if ((index = s.indexOf("KB")) != -1) {
+            multiplier = 1024;
+            s = s.substring(0, index);
+        } else if ((index = s.indexOf("MB")) != -1) {
+            multiplier = 1024 * 1024;
+            s = s.substring(0, index);
+        } else if ((index = s.indexOf("GB")) != -1) {
+            multiplier = 1024 * 1024 * 1024;
+            s = s.substring(0, index);
+        }
+        if (s != null) {
+            try {
+                return Long.valueOf(s) * multiplier;
+            }
+            catch (NumberFormatException e) {
+                logger.error("[" + s + "] is not in proper int form.");
+                logger.error("[" + value + "] not in expected format.", e);
+            }
+        }
+        return dEfault;
+    }
+
+    /**
+     * Find the value corresponding to <code>key</code> in
+     * <code>props</code>. Then perform variable substitution on the
+     * found value.
+     * @param key The key to locate.
+     * @param props The properties.
+     * @return The String after substitution.
+     */
+    public static String findAndSubst(String key, Properties props) {
+        String value = props.getProperty(key);
+        if (value == null) {
+            return null;
+        }
+
+        try {
+            return substVars(value, props);
+        } catch (IllegalArgumentException e) {
+            logger.error("Bad option value [" + value + "].", e);
+            return value;
+        }
+    }
+
+    /**
+     * Instantiate an object given a class name. Check that the
+     * <code>className</code> is a subclass of
+     * <code>superClass</code>. If that test fails or the object could
+     * not be instantiated, then <code>defaultValue</code> is returned.
+     *
+     * @param className    The fully qualified class name of the object to instantiate.
+     * @param superClass   The class to which the new object should belong.
+     * @param defaultValue The object to return in case of non-fulfillment
+     * @return The created object.
+     */
+    public static Object instantiateByClassName(String className, Class superClass,
+                                         Object defaultValue) {
+        if (className != null) {
+            try {
+                Class classObj = Loader.loadClass(className);
+                if (!superClass.isAssignableFrom(classObj)) {
+                    logger.error("A \"" + className + "\" object is not assignable to a \"" +
+                        superClass.getName() + "\" variable.");
+                    logger.error("The class \"" + superClass.getName() + "\" was loaded by ");
+                    logger.error("[" + superClass.getClassLoader() + "] whereas object of type ");
+                    logger.error("\"" + classObj.getName() + "\" was loaded by ["
+                        + classObj.getClassLoader() + "].");
+                    return defaultValue;
+                }
+                return classObj.newInstance();
+            } catch (ClassNotFoundException e) {
+                logger.error("Could not instantiate class [" + className + "].", e);
+            } catch (IllegalAccessException e) {
+                logger.error("Could not instantiate class [" + className + "].", e);
+            } catch (InstantiationException e) {
+                logger.error("Could not instantiate class [" + className + "].", e);
+            } catch (RuntimeException e) {
+                logger.error("Could not instantiate class [" + className + "].", e);
+            }
+        }
+        return defaultValue;
+    }
+
+
+    /**
+     * Perform variable substitution in string <code>val</code> from the
+     * values of keys found in the system propeties.
+     * <p/>
+     * <p>The variable substitution delimeters are <b>${</b> and <b>}</b>.
+     * <p/>
+     * <p>For example, if the System properties contains "key=value", then
+     * the call
+     * <pre>
+     * String s = OptionConverter.substituteVars("Value of key is ${key}.");
+     * </pre>
+     * <p/>
+     * will set the variable <code>s</code> to "Value of key is value.".
+     * <p/>
+     * <p>If no value could be found for the specified key, then the
+     * <code>props</code> parameter is searched, if the value could not
+     * be found there, then substitution defaults to the empty string.
+     * <p/>
+     * <p>For example, if system propeties contains no value for the key
+     * "inexistentKey", then the call
+     * <p/>
+     * <pre>
+     * String s = OptionConverter.subsVars("Value of inexistentKey is [${inexistentKey}]");
+     * </pre>
+     * will set <code>s</code> to "Value of inexistentKey is []"
+     * <p/>
+     * <p>An {@link java.lang.IllegalArgumentException} is thrown if
+     * <code>val</code> contains a start delimeter "${" which is not
+     * balanced by a stop delimeter "}". </p>
+     * <p/>
+     * <p><b>Author</b> Avy Sharell</a></p>
+     *
+     * @param val The string on which variable substitution is performed.
+     * @param props The properties to use for substitution.
+     * @return The String after substitution.
+     * @throws IllegalArgumentException if <code>val</code> is malformed.
+     */
+    public static String substVars(String val, Properties props) throws
+        IllegalArgumentException {
+
+        StringBuilder sbuf = new StringBuilder();
+
+        int i = 0;
+        int j, k;
+
+        while (true) {
+            j = val.indexOf(DELIM_START, i);
+            if (j == -1) {
+                // no more variables
+                if (i == 0) { // this is a simple string
+                    return val;
+                } else { // add the tail string which contails no variables and return the result.
+                    sbuf.append(val.substring(i, val.length()));
+                    return sbuf.toString();
+                }
+            } else {
+                sbuf.append(val.substring(i, j));
+                k = val.indexOf(DELIM_STOP, j);
+                if (k == -1) {
+                    throw new IllegalArgumentException('"' + val +
+                        "\" has no closing brace. Opening brace at position " + j
+                        + '.');
+                } else {
+                    j += DELIM_START_LEN;
+                    String key = val.substring(j, k);
+                    // first try in System properties
+                    String replacement = getSystemProperty(key, null);
+                    // then try props parameter
+                    if (replacement == null && props != null) {
+                        replacement = props.getProperty(key);
+                    }
+
+                    if (replacement != null) {
+                        // Do variable substitution on the replacement string
+                        // such that we can solve "Hello ${x2}" as "Hello p1"
+                        // the where the properties are
+                        // x1=p1
+                        // x2=${x1}
+                        String recursiveReplacement = substVars(replacement, props);
+                        sbuf.append(recursiveReplacement);
+                    }
+                    i = k + DELIM_STOP_LEN;
+                }
+            }
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/LayoutBase.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/LayoutBase.java
new file mode 100644
index 0000000..61713ec
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/LayoutBase.java
@@ -0,0 +1,48 @@
+/*
+ * 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.layout;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.internal.StatusLogger;
+
+/**
+ *
+ */
+public abstract class LayoutBase implements Layout {
+
+    protected byte[] header;
+    protected byte[] footer;
+
+    protected static Logger logger = StatusLogger.getLogger();
+
+    public byte[] getHeader() {
+        return header;
+    }
+
+    public void setHeader(byte[] header) {
+        this.header = header;
+    }
+
+    public byte[] getFooter() {
+        return footer;
+    }
+
+    public void setFooter(byte[] footer) {
+        this.footer = footer;
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java
new file mode 100644
index 0000000..696100a
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java
@@ -0,0 +1,495 @@
+/*
+ * 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.layout;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.helpers.OptionConverter;
+import org.apache.logging.log4j.core.layout.pattern.PatternConverter;
+import org.apache.logging.log4j.core.layout.pattern.PatternParser;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>A flexible layout configurable with pattern string. The goal of this class
+ * is to {@link #format format} a {@link LogEvent} and return the results.
+ * The format of the result depends on the <em>conversion pattern</em>.
+ * <p>
+ * <p/>
+ * <p>The conversion pattern is closely related to the conversion
+ * pattern of the printf function in C. A conversion pattern is
+ * composed of literal text and format control expressions called
+ * <em>conversion specifiers</em>.
+ * <p/>
+ * <p><i>Note that you are free to insert any literal text within the
+ * conversion pattern.</i>
+ * </p>
+ * <p/>
+ * <p>Each conversion specifier starts with a percent sign (%) and is
+ * followed by optional <em>format modifiers</em> and a <em>conversion
+ * character</em>. The conversion character specifies the type of
+ * data, e.g. category, priority, date, thread name. The format
+ * modifiers control such things as field width, padding, left and
+ * right justification. The following is a simple example.
+ * <p/>
+ * <p>Let the conversion pattern be <b>"%-5p [%t]: %m%n"</b> and assume
+ * that the log4j environment was set to use a PatternLayout. Then the
+ * statements
+ * <pre>
+ * Logger logger = LoggerFactory().getLogger("MyLogger");
+ * logger.debug("Message 1");
+ * logger.warn("Message 2");
+ * </pre>
+ * would yield the output
+ * <pre>
+ * DEBUG [main]: Message 1
+ * WARN  [main]: Message 2
+ * </pre>
+ * <p/>
+ * <p>Note that there is no explicit separator between text and
+ * conversion specifiers. The pattern parser knows when it has reached
+ * the end of a conversion specifier when it reads a conversion
+ * character. In the example above the conversion specifier
+ * <b>%-5p</b> means the priority of the logging event should be left
+ * justified to a width of five characters.
+ * <p/>
+ * The recognized conversion characters are
+ * <p/>
+ * <p>
+ * <table border="1" CELLPADDING="8">
+ * <th>Conversion Character</th>
+ * <th>Effect</th>
+ * <p/>
+ * <tr>
+ * <td align=center><b>c</b></td>
+ * <p/>
+ * <td>Used to output the category of the logging event. The
+ * category conversion specifier can be optionally followed by
+ * <em>precision specifier</em>, that is a decimal constant in
+ * brackets.
+ * <p/>
+ * <p>If a precision specifier is given, then only the corresponding
+ * number of right most components of the category name will be
+ * printed. By default the category name is printed in full.
+ * <p/>
+ * <p>For example, for the category name "a.b.c" the pattern
+ * <b>%c{2}</b> will output "b.c".
+ * <p/>
+ * </td>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <td align=center><b>C</b></td>
+ * <p/>
+ * <td>Used to output the fully qualified class name of the caller
+ * issuing the logging request. This conversion specifier
+ * can be optionally followed by <em>precision specifier</em>, that
+ * is a decimal constant in brackets.
+ * <p/>
+ * <p>If a precision specifier is given, then only the corresponding
+ * number of right most components of the class name will be
+ * printed. By default the class name is output in fully qualified form.
+ * <p/>
+ * <p>For example, for the class name "org.apache.xyz.SomeClass", the
+ * pattern <b>%C{1}</b> will output "SomeClass".
+ * <p/>
+ * <p><b>WARNING</b> Generating the caller class information is
+ * slow. Thus, it's use should be avoided unless execution speed is
+ * not an issue.
+ * <p/>
+ * </td>
+ * </tr>
+ * <p/>
+ * <tr> <td align=center><b>d</b></td> <td>Used to output the date of
+ * the logging event. The date conversion specifier may be
+ * followed by a set of braces containing a
+ * date and time pattern strings {@link java.text.SimpleDateFormat},
+ * <em>ABSOLUTE</em>, <em>DATE</em> or <em>ISO8601</em>
+ * and a set of braces containing a time zone id per
+ * {@link java.util.TimeZone#getTimeZone(String)}.
+ * For example, <b>%d{HH:mm:ss,SSS}</b>,
+ * <b>%d{dd&nbsp;MMM&nbsp;yyyy&nbsp;HH:mm:ss,SSS}</b>,
+ * <b>%d{DATE}</b> or <b>%d{HH:mm:ss}{GMT+0}</b>. If no date format specifier is given then
+ * ISO8601 format is assumed.
+ * </td>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <td align=center><b>F</b></td>
+ * <p/>
+ * <td>Used to output the file name where the logging request was
+ * issued.
+ * <p/>
+ * <p><b>WARNING</b> Generating caller location information is
+ * extremely slow. Its use should be avoided unless execution speed
+ * is not an issue.
+ * <p/>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <td align=center><b>l</b></td>
+ * <p/>
+ * <td>Used to output location information of the caller which generated
+ * the logging event.
+ * <p/>
+ * <p>The location information depends on the JVM implementation but
+ * usually consists of the fully qualified name of the calling
+ * method followed by the callers source the file name and line
+ * number between parentheses.
+ * <p/>
+ * </td>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <td align=center><b>L</b></td>
+ * <p/>
+ * <td>Used to output the line number from where the logging request
+ * was issued.
+ * <p/>
+ * </tr>
+ * <p/>
+ * <p/>
+ * <tr>
+ * <td align=center><b>m</b></td>
+ * <td>Used to output the application supplied message associated with
+ * the logging event.</td>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <td align=center><b>M</b></td>
+ * <p/>
+ * <td>Used to output the method name where the logging request was
+ * issued.
+ * <p/>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <td align=center><b>n</b></td>
+ * <p/>
+ * <td>Outputs the platform dependent line separator character or
+ * characters.
+ * <p/>
+ * <p>This conversion character offers practically the same
+ * performance as using non-portable line separator strings such as
+ * "\n", or "\r\n". Thus, it is the preferred way of specifying a
+ * line separator.
+ * <p/>
+ * <p/>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <td align=center><b>p</b></td>
+ * <td>Used to output the level of the logging event.</td>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <p/>
+ * <td align=center><b>r</b></td>
+ * <p/>
+ * <td>Used to output the number of milliseconds elapsed since the construction
+ * of the layout until the creation of the logging event.</td>
+ * </tr>
+ * <p/>
+ * <p/>
+ * <tr>
+ * <td align=center><b>t</b></td>
+ * <p/>
+ * <td>Used to output the name of the thread that generated the logging event.</td>
+ * <p/>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <p/>
+ * <td align=center><b>x</b></td>
+ * <p/>
+ * <td>Used to output the NDC (nested diagnostic context) associated
+ * with the thread that generated the logging event.
+ * </td>
+ * </tr>
+ * <p/>
+ * <p/>
+ * <tr>
+ * <td align=center><b>X</b></td>
+ * <p/>
+ * <td>
+ * <p/>
+ * <p>Used to output the MDC (mapped diagnostic context) associated
+ * with the thread that generated the logging event. The <b>X</b>
+ * conversion character can be followed by the key for the
+ * map placed between braces, as in <b>%X{clientNumber}</b> where
+ * <code>clientNumber</code> is the key. The value in the MDC
+ * corresponding to the key will be output. If no additional sub-option
+ * is specified, then the entire contents of the MDC key value pair set
+ * is output using a format {{key1,val1},{key2,val2}}</p>
+ * <p/>
+ * <p>See {@link MDC} class for more details.
+ * </p>
+ * <p/>
+ * </td>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <td align=center><b>properties</b></td>
+ * <p/>
+ * <td>
+ * <p>Used to output the Properties associated with the logging event. The <b>properties</b>
+ * conversion word can be followed by the key for the
+ * map placed between braces, as in <b>%properties{application}</b> where
+ * <code>application</code> is the key. The value in the Properties bundle
+ * corresponding to the key will be output. If no additional sub-option
+ * is specified, then the entire contents of the Properties key value pair set
+ * is output using a format {{key1,val1},{key2,val2}}</p>
+ * </td>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <td align=center><b>throwable</b></td>
+ * <p/>
+ * <td>
+ * <p>Used to output the Throwable trace that has been bound to the LoggingEvent, by
+ * default this will output the full trace as one would normally find by a call to Throwable.printStackTrace().
+ * The throwable conversion word can be followed by an option in the form <b>%throwable{short}</b>
+ * which will only output the first line of the Throwable.</p>
+ * </td>
+ * </tr>
+ * <p/>
+ * <tr>
+ * <p/>
+ * <td align=center><b>%</b></td>
+ * <p/>
+ * <td>The sequence %% outputs a single percent sign.
+ * </td>
+ * </tr>
+ * <p/>
+ * </table>
+ * <p/>
+ * <p>By default the relevant information is output as is. However,
+ * with the aid of format modifiers it is possible to change the
+ * minimum field width, the maximum field width and justification.
+ * <p/>
+ * <p>The optional format modifier is placed between the percent sign
+ * and the conversion character.
+ * <p/>
+ * <p>The first optional format modifier is the <em>left justification
+ * flag</em> which is just the minus (-) character. Then comes the
+ * optional <em>minimum field width</em> modifier. This is a decimal
+ * constant that represents the minimum number of characters to
+ * output. If the data item requires fewer characters, it is padded on
+ * either the left or the right until the minimum width is
+ * reached. The default is to pad on the left (right justify) but you
+ * can specify right padding with the left justification flag. The
+ * padding character is space. If the data item is larger than the
+ * minimum field width, the field is expanded to accommodate the
+ * data. The value is never truncated.
+ * <p/>
+ * <p>This behavior can be changed using the <em>maximum field
+ * width</em> modifier which is designated by a period followed by a
+ * decimal constant. If the data item is longer than the maximum
+ * field, then the extra characters are removed from the
+ * <em>beginning</em> of the data item and not from the end. For
+ * example, it the maximum field width is eight and the data item is
+ * ten characters long, then the first two characters of the data item
+ * are dropped. This behavior deviates from the printf function in C
+ * where truncation is done from the end.
+ * <p/>
+ * <p>Below are various format modifier examples for the category
+ * conversion specifier.
+ * <p/>
+ * <p/>
+ * <TABLE BORDER=1 CELLPADDING=8>
+ * <th>Format modifier
+ * <th>left justify
+ * <th>minimum width
+ * <th>maximum width
+ * <th>comment
+ * <p/>
+ * <tr>
+ * <td align=center>%20c</td>
+ * <td align=center>false</td>
+ * <td align=center>20</td>
+ * <td align=center>none</td>
+ * <p/>
+ * <td>Left pad with spaces if the category name is less than 20
+ * characters long.
+ * <p/>
+ * <tr> <td align=center>%-20c</td> <td align=center>true</td> <td
+ * align=center>20</td> <td align=center>none</td> <td>Right pad with
+ * spaces if the category name is less than 20 characters long.
+ * <p/>
+ * <tr>
+ * <td align=center>%.30c</td>
+ * <td align=center>NA</td>
+ * <td align=center>none</td>
+ * <td align=center>30</td>
+ * <p/>
+ * <td>Truncate from the beginning if the category name is longer than 30
+ * characters.
+ * <p/>
+ * <tr>
+ * <td align=center>%20.30c</td>
+ * <td align=center>false</td>
+ * <td align=center>20</td>
+ * <td align=center>30</td>
+ * <p/>
+ * <td>Left pad with spaces if the category name is shorter than 20
+ * characters. However, if category name is longer than 30 characters,
+ * then truncate from the beginning.
+ * <p/>
+ * <tr>
+ * <td align=center>%-20.30c</td>
+ * <td align=center>true</td>
+ * <td align=center>20</td>
+ * <td align=center>30</td>
+ * <p/>
+ * <td>Right pad with spaces if the category name is shorter than 20
+ * characters. However, if category name is longer than 30 characters,
+ * then truncate from the beginning.
+ * <p/>
+ * </table>
+ * <p/>
+ * <p>Below are some examples of conversion patterns.
+ * <p/>
+ * <dl>
+ * <p/>
+ * <p><dt><b>%r [%t] %-5p %c %x - %m%n</b>
+ * <p><dd>This is essentially the TTCC layout.
+ * <p/>
+ * <p><dt><b>%-6r [%15.15t] %-5p %30.30c %x - %m%n</b>
+ * <p/>
+ * <p><dd>Similar to the TTCC layout except that the relative time is
+ * right padded if less than 6 digits, thread name is right padded if
+ * less than 15 characters and truncated if longer and the category
+ * name is left padded if shorter than 30 characters and truncated if
+ * longer.
+ * <p/>
+ * </dl>
+ * <p/>
+ * <p>The above text is largely inspired from Peter A. Darnell and
+ * Philip E. Margolis' highly recommended book "C -- a Software
+ * Engineering Approach", ISBN 0-387-97389-3.
+ */
+@Plugin(name="PatternLayout",type="Core")
+public class PatternLayout extends LayoutBase {
+    /**
+     * Default pattern string for log output. Currently set to the
+     * string <b>"%m%n"</b> which just prints the application supplied
+     * message.
+     */
+    public static final String DEFAULT_CONVERSION_PATTERN = "%m%n";
+
+    /**
+     * A conversion pattern equivalent to the TTCCCLayout.
+     * Current value is <b>%r [%t] %p %c %x - %m%n</b>.
+     */
+    public static final String TTCC_CONVERSION_PATTERN =
+        "%r [%t] %p %c %x - %m%n";
+
+    /**
+     * Initial converter for pattern.
+     */
+    private List<PatternConverter> converters;
+
+    private static final String KEY = "Converter";
+
+    /**
+     * Conversion pattern.
+     */
+    private String conversionPattern;
+
+    /**
+     * True if any element in pattern formats information from exceptions.
+     */
+    private boolean handlesExceptions;
+
+    /**
+     * Constructs a EnhancedPatternLayout using the DEFAULT_LAYOUT_PATTERN.
+     * <p/>
+     * The default pattern just produces the application supplied message.
+     */
+    public PatternLayout() {
+        this(DEFAULT_CONVERSION_PATTERN);
+    }
+
+    /**
+     * Constructs a EnhancedPatternLayout using the supplied conversion pattern.
+     *
+     * @param pattern conversion pattern.
+     */
+    public PatternLayout(final String pattern) {
+
+        this.conversionPattern = pattern;
+        PatternParser parser = createPatternParser();
+        converters = parser.parse((pattern == null) ? DEFAULT_CONVERSION_PATTERN : pattern);
+        handlesExceptions = parser.handlesExceptions();
+
+    }
+
+    /**
+     * Set the <b>ConversionPattern</b> option. This is the string which
+     * controls formatting and consists of a mix of literal content and
+     * conversion specifiers.
+     *
+     * @param conversionPattern conversion pattern.
+     */
+    public void setConversionPattern(final String conversionPattern) {
+        String pattern = OptionConverter.convertSpecialChars(conversionPattern);
+        if (pattern == null) {
+            return;
+        }
+        PatternParser parser = createPatternParser();
+        converters = parser.parse(pattern);
+        handlesExceptions = parser.handlesExceptions();
+    }
+
+    /**
+     * Formats a logging event to a writer.
+     *
+     * @param event logging event to be formatted.
+     */
+    public byte[] format(final LogEvent event) {
+        StringBuilder buf = new StringBuilder();
+        for (PatternConverter c : converters) {
+            c.format(event, buf);
+        }
+        return buf.toString().getBytes();
+    }
+
+    private PatternParser createPatternParser() {
+
+        return new PatternParser(KEY);
+    }
+
+    @PluginFactory
+    public static PatternLayout createLayout(Node node) {
+        String pattern = null;
+        for (Map.Entry<String, String> entry : node.getAttributes().entrySet()) {
+            String name = entry.getKey().toLowerCase();
+            if (name.equals("pattern")) {
+                pattern = entry.getValue();
+            }
+        }
+        if (pattern != null) {
+            return new PatternLayout(pattern);
+        }
+        logger.error("No pattern specified for PatternLayout");
+        return null;
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/CachedDateFormat.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/CachedDateFormat.java
new file mode 100644
index 0000000..88a7375
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/CachedDateFormat.java
@@ -0,0 +1,371 @@
+/*
+ * 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.layout.pattern;
+
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Date;
+import java.util.TimeZone;
+
+
+/**
+ * CachedDateFormat optimizes the performance of a wrapped
+ * DateFormat.  The implementation is not thread-safe.
+ * If the millisecond pattern is not recognized,
+ * the class will only use the cache if the
+ * same value is requested.
+ */
+final class CachedDateFormat extends DateFormat {
+    /**
+     * Constant used to represent that there was no change
+     * observed when changing the millisecond count.
+     */
+    public static final int NO_MILLISECONDS = -2;
+
+    /**
+     * Supported digit set.  If the wrapped DateFormat uses
+     * a different unit set, the millisecond pattern
+     * will not be recognized and duplicate requests
+     * will use the cache.
+     */
+    private static final String DIGITS = "0123456789";
+
+    /**
+     * Constant used to represent that there was an
+     * observed change, but was an expected change.
+     */
+    public static final int UNRECOGNIZED_MILLISECONDS = -1;
+
+    /**
+     * First magic number used to detect the millisecond position.
+     */
+    private static final int MAGIC1 = 654;
+
+    /**
+     * Expected representation of first magic number.
+     */
+    private static final String MAGICSTRING1 = "654";
+
+    /**
+     * Second magic number used to detect the millisecond position.
+     */
+    private static final int MAGIC2 = 987;
+
+    /**
+     * Expected representation of second magic number.
+     */
+    private static final String MAGICSTRING2 = "987";
+
+    /**
+     * Expected representation of 0 milliseconds.
+     */
+    private static final String ZERO_STRING = "000";
+
+    /**
+     * Wrapped formatter.
+     */
+    private final DateFormat formatter;
+
+    /**
+     * Index of initial digit of millisecond pattern or
+     * UNRECOGNIZED_MILLISECONDS or NO_MILLISECONDS.
+     */
+    private int millisecondStart;
+
+    /**
+     * Integral second preceding the previous convered Date.
+     */
+    private long slotBegin;
+
+    /**
+     * Cache of previous conversion.
+     */
+    private StringBuffer cache = new StringBuffer(50);
+
+    /**
+     * Maximum validity period for the cache.
+     * Typically 1, use cache for duplicate requests only, or
+     * 1000, use cache for requests within the same integral second.
+     */
+    private final int expiration;
+
+    /**
+     * Date requested in previous conversion.
+     */
+    private long previousTime;
+
+    /**
+     * Scratch date object used to minimize date object creation.
+     */
+    private final Date tmpDate = new Date(0);
+
+    /**
+     * Creates a new CachedDateFormat object.
+     *
+     * @param dateFormat Date format, may not be null.
+     * @param expiration maximum cached range in milliseconds.
+     *                   If the dateFormat is known to be incompatible with the
+     *                   caching algorithm, use a value of 0 to totally disable
+     *                   caching or 1 to only use cache for duplicate requests.
+     */
+    public CachedDateFormat(final DateFormat dateFormat, final int expiration) {
+        if (dateFormat == null) {
+            throw new IllegalArgumentException("dateFormat cannot be null");
+        }
+
+        if (expiration < 0) {
+            throw new IllegalArgumentException("expiration must be non-negative");
+        }
+
+        formatter = dateFormat;
+        this.expiration = expiration;
+        millisecondStart = 0;
+
+        //
+        //   set the previousTime so the cache will be invalid
+        //        for the next request.
+        previousTime = Long.MIN_VALUE;
+        slotBegin = Long.MIN_VALUE;
+    }
+
+    /**
+     * Finds start of millisecond field in formatted time.
+     *
+     * @param time      long time, must be integral number of seconds
+     * @param formatted String corresponding formatted string
+     * @param formatter DateFormat date format
+     * @return int position in string of first digit of milliseconds,
+     *         -1 indicates no millisecond field, -2 indicates unrecognized
+     *         field (likely RelativeTimeDateFormat)
+     */
+    public static int findMillisecondStart(final long time, final String formatted, final DateFormat formatter) {
+        long slotBegin = (time / 1000) * 1000;
+
+        if (slotBegin > time) {
+            slotBegin -= 1000;
+        }
+
+        int millis = (int) (time - slotBegin);
+
+        int magic = MAGIC1;
+        String magicString = MAGICSTRING1;
+
+        if (millis == MAGIC1) {
+            magic = MAGIC2;
+            magicString = MAGICSTRING2;
+        }
+
+        String plusMagic = formatter.format(new Date(slotBegin + magic));
+
+        /**
+         *   If the string lengths differ then
+         *      we can't use the cache except for duplicate requests.
+         */
+        if (plusMagic.length() != formatted.length()) {
+            return UNRECOGNIZED_MILLISECONDS;
+        } else {
+            // find first difference between values
+            for (int i = 0; i < formatted.length(); i++) {
+                if (formatted.charAt(i) != plusMagic.charAt(i)) {
+                    //
+                    //   determine the expected digits for the base time
+                    StringBuffer formattedMillis = new StringBuffer("ABC");
+                    millisecondFormat(millis, formattedMillis, 0);
+
+                    String plusZero = formatter.format(new Date(slotBegin));
+
+                    //   If the next 3 characters match the magic
+                    //      string and the expected string
+                    if (
+                        (plusZero.length() == formatted.length())
+                            && magicString.regionMatches(
+                            0, plusMagic, i, magicString.length())
+                            && formattedMillis.toString().regionMatches(
+                            0, formatted, i, magicString.length())
+                            && ZERO_STRING.regionMatches(
+                            0, plusZero, i, ZERO_STRING.length())) {
+                        return i;
+                    } else {
+                        return UNRECOGNIZED_MILLISECONDS;
+                    }
+                }
+            }
+        }
+
+        return NO_MILLISECONDS;
+    }
+
+    /**
+     * Formats a Date into a date/time string.
+     *
+     * @param date          the date to format.
+     * @param sbuf          the string buffer to write to.
+     * @param fieldPosition remains untouched.
+     * @return the formatted time string.
+     */
+    public StringBuffer format(Date date, StringBuffer sbuf, FieldPosition fieldPosition) {
+        format(date.getTime(), sbuf);
+
+        return sbuf;
+    }
+
+    /**
+     * Formats a millisecond count into a date/time string.
+     *
+     * @param now Number of milliseconds after midnight 1 Jan 1970 GMT.
+     * @param buf the string buffer to write to.
+     * @return the formatted time string.
+     */
+    public StringBuffer format(long now, StringBuffer buf) {
+        //
+        // If the current requested time is identical to the previously
+        //     requested time, then append the cache contents.
+        //
+        if (now == previousTime) {
+            buf.append(cache);
+
+            return buf;
+        }
+
+        //
+        //   If millisecond pattern was not unrecognized
+        //     (that is if it was found or milliseconds did not appear)
+        //
+        if (millisecondStart != UNRECOGNIZED_MILLISECONDS &&
+            //    Check if the cache is still valid.
+            //    If the requested time is within the same integral second
+            //       as the last request and a shorter expiration was not requested.
+            (now < (slotBegin + expiration)) && (now >= slotBegin)
+            && (now < (slotBegin + 1000L))) {
+            //
+            //    if there was a millisecond field then update it
+            //
+            if (millisecondStart >= 0) {
+                millisecondFormat((int) (now - slotBegin), cache, millisecondStart);
+            }
+
+            //
+            //   update the previously requested time
+            //      (the slot begin should be unchanged)
+            previousTime = now;
+            buf.append(cache);
+
+            return buf;
+        }
+
+        //
+        //  could not use previous value.
+        //    Call underlying formatter to format date.
+        cache.setLength(0);
+        tmpDate.setTime(now);
+        cache.append(formatter.format(tmpDate));
+        buf.append(cache);
+        previousTime = now;
+        slotBegin = (previousTime / 1000) * 1000;
+
+        if (slotBegin > previousTime) {
+            slotBegin -= 1000;
+        }
+
+        //
+        //    if the milliseconds field was previous found
+        //       then reevaluate in case it moved.
+        //
+        if (millisecondStart >= 0) {
+            millisecondStart =
+                findMillisecondStart(now, cache.toString(), formatter);
+        }
+
+        return buf;
+    }
+
+    /**
+     * Formats a count of milliseconds (0-999) into a numeric representation.
+     *
+     * @param millis Millisecond coun between 0 and 999.
+     * @param buf    String buffer, may not be null.
+     * @param offset Starting position in buffer, the length of the
+     *               buffer must be at least offset + 3.
+     */
+    private static void millisecondFormat(
+        final int millis, final StringBuffer buf, final int offset) {
+        buf.setCharAt(offset, DIGITS.charAt(millis / 100));
+        buf.setCharAt(offset + 1, DIGITS.charAt((millis / 10) % 10));
+        buf.setCharAt(offset + 2, DIGITS.charAt(millis % 10));
+    }
+
+    /**
+     * Set timezone.
+     * <p/>
+     * Setting the timezone using getCalendar().setTimeZone()
+     * will likely cause caching to misbehave.
+     *
+     * @param timeZone TimeZone new timezone
+     */
+    public void setTimeZone(final TimeZone timeZone) {
+        formatter.setTimeZone(timeZone);
+        previousTime = Long.MIN_VALUE;
+        slotBegin = Long.MIN_VALUE;
+    }
+
+    /**
+     * This method is delegated to the formatter which most
+     * likely returns null.
+     *
+     * @param s   string representation of date.
+     * @param pos field position, unused.
+     * @return parsed date, likely null.
+     */
+    public Date parse(String s, ParsePosition pos) {
+        return formatter.parse(s, pos);
+    }
+
+    /**
+     * Gets number formatter.
+     *
+     * @return NumberFormat number formatter
+     */
+    public NumberFormat getNumberFormat() {
+        return formatter.getNumberFormat();
+    }
+
+    /**
+     * Gets maximum cache validity for the specified SimpleDateTime
+     * conversion pattern.
+     *
+     * @param pattern conversion pattern, may not be null.
+     * @return Duration in milliseconds from an integral second
+     *         that the cache will return consistent results.
+     */
+    public static int getMaximumCacheValidity(final String pattern) {
+        //
+        //   If there are more "S" in the pattern than just one "SSS" then
+        //      (for example, "HH:mm:ss,SSS SSS"), then set the expiration to
+        //      one millisecond which should only perform duplicate request caching.
+        //
+        int firstS = pattern.indexOf('S');
+
+        if ((firstS >= 0) && (firstS != pattern.lastIndexOf("SSS"))) {
+            return 1;
+        }
+
+        return 1000;
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ClassNamePatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ClassNamePatternConverter.java
new file mode 100644
index 0000000..ca46684
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ClassNamePatternConverter.java
@@ -0,0 +1,72 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Formats the class name of the site of the logging request.
+ */
+@Plugin(name="ClassNamePatternConverter", type="Converter")
+@ConverterKeys({"C", "class"})
+public final class ClassNamePatternConverter extends NamePatternConverter {
+
+    private static final String NA = "?";
+    /**
+     * Private constructor.
+     *
+     * @param options options, may be null.
+     */
+    private ClassNamePatternConverter(
+        final String[] options) {
+        super("Class Name", "class name", options);
+    }
+
+    /**
+     * Gets an instance of ClassNamePatternConverter.
+     *
+     * @param options options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static ClassNamePatternConverter newInstance(
+        final String[] options) {
+        return new ClassNamePatternConverter(options);
+    }
+
+    /**
+     * Format a logging event.
+     *
+     * @param event      event to format.
+     * @param toAppendTo string buffer to which class name will be appended.
+     */
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        final int initialLength = toAppendTo.length();
+
+        StackTraceElement element = event.getSource();
+
+        if (element == null) {
+            toAppendTo.append(NA);
+        } else {
+            toAppendTo.append(element.getClassName());
+        }
+
+        abbreviate(initialLength, toAppendTo);
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ConverterKeys.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ConverterKeys.java
new file mode 100644
index 0000000..7a157bf
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ConverterKeys.java
@@ -0,0 +1,15 @@
+package org.apache.logging.log4j.core.layout.pattern;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ConverterKeys {
+    public String[] value();
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/DatePatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/DatePatternConverter.java
new file mode 100644
index 0000000..1bc7500
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/DatePatternConverter.java
@@ -0,0 +1,163 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+
+/**
+ * Convert and format the event's date in a StringBuffer.
+ */
+@Plugin(name="DatePatternConverter", type="Converter")
+@ConverterKeys({"d", "date"})
+public final class DatePatternConverter extends LogEventPatternConverter {
+    /**
+     * ABSOLUTE string literal.
+     */
+    private static final String ABSOLUTE_FORMAT = "ABSOLUTE";
+    /**
+     * SimpleTimePattern for ABSOLUTE.
+     */
+    private static final String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS";
+
+
+    /**
+     * DATE string literal.
+     */
+    private static final String DATE_AND_TIME_FORMAT = "DATE";
+    /**
+     * SimpleTimePattern for DATE.
+     */
+    private static final String DATE_AND_TIME_PATTERN = "dd MMM yyyy HH:mm:ss,SSS";
+
+    /**
+     * ISO8601 string literal.
+     */
+    private static final String ISO8601_FORMAT = "ISO8601";
+    /**
+     * SimpleTimePattern for ISO8601.
+     */
+    private static final String ISO8601_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS";
+    /**
+     * Date format.
+     */
+    private String cachedDate;
+
+    private long lastTimestamp;
+
+    private SimpleDateFormat simpleFormat;
+
+    /**
+     * Private constructor.
+     *
+     * @param options options, may be null.
+     */
+    private DatePatternConverter(final String[] options) {
+        super("Date", "date");
+
+        String patternOption;
+
+        if ((options == null) || (options.length == 0)) {
+            // the branch could be optimized, but here we are making explicit
+            // that null values for patternOption are allowed.
+            patternOption = null;
+        } else {
+            patternOption = options[0];
+        }
+
+        String pattern;
+
+        if (patternOption == null || patternOption.equalsIgnoreCase(ISO8601_FORMAT)) {
+            pattern = ISO8601_PATTERN;
+        } else if (patternOption.equalsIgnoreCase(ABSOLUTE_FORMAT)) {
+            pattern = ABSOLUTE_TIME_PATTERN;
+        } else if (patternOption.equalsIgnoreCase(DATE_AND_TIME_FORMAT)) {
+            pattern = DATE_AND_TIME_PATTERN;
+        } else {
+            pattern = patternOption;
+        }
+
+        try {
+            simpleFormat = new SimpleDateFormat(pattern);
+        } catch (IllegalArgumentException e) {
+            logger.warn("Could not instantiate SimpleDateFormat with pattern " + patternOption, e);
+
+            // default to the ISO8601 format
+            simpleFormat = new SimpleDateFormat(ISO8601_PATTERN);
+        }
+
+        // if the option list contains a TZ option, then set it.
+        if ((options != null) && (options.length > 1)) {
+            TimeZone tz = TimeZone.getTimeZone(options[1]);
+            simpleFormat.setTimeZone(tz);
+        }
+    }
+
+    /**
+     * Obtains an instance of pattern converter.
+     *
+     * @param options options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static DatePatternConverter newInstance(final String[] options) {
+        return new DatePatternConverter(options);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder output) {
+        long timestamp = event.getMillis();
+
+        synchronized (this) {
+            if (timestamp != lastTimestamp) {
+                lastTimestamp = timestamp;
+                cachedDate = simpleFormat.format(timestamp);
+            }
+        }
+        output.append(cachedDate);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final Object obj, final StringBuilder output) {
+        if (obj instanceof Date) {
+            format((Date) obj, output);
+        }
+
+        super.format(obj, output);
+    }
+
+    /**
+     * Append formatted date to string buffer.
+     *
+     * @param date       date
+     * @param toAppendTo buffer to which formatted date is appended.
+     */
+    public void format(final Date date, final StringBuilder toAppendTo) {
+        synchronized (this) {
+            toAppendTo.append(simpleFormat.format(date.getTime()));
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FileDatePatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FileDatePatternConverter.java
new file mode 100644
index 0000000..ff06408
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FileDatePatternConverter.java
@@ -0,0 +1,53 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+/**
+ * Formats an date by delegating to DatePatternConverter.  The default
+ * date pattern for a %d specifier in a file name is different than
+ * the %d pattern in pattern layout.
+ */
+@Plugin(name="FileDatePatternConverter", type="FileConverter")
+@ConverterKeys({"d", "date"})
+public final class FileDatePatternConverter {
+    /**
+     * Private constructor.
+     */
+    private FileDatePatternConverter() {
+    }
+
+    /**
+     * Obtains an instance of pattern converter.
+     *
+     * @param options options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static PatternConverter newInstance(
+        final String[] options) {
+        if ((options == null) || (options.length == 0)) {
+            return DatePatternConverter.newInstance(
+                new String[]{
+                    "yyyy-MM-dd"
+                });
+        }
+
+        return DatePatternConverter.newInstance(options);
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FileLocationPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FileLocationPatternConverter.java
new file mode 100644
index 0000000..b1b84b6
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FileLocationPatternConverter.java
@@ -0,0 +1,64 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Return the event's line location information in a StringBuffer.
+ */
+@Plugin(name="FileLocationPatternConverter", type="Converter")
+@ConverterKeys({"F", "file"})
+public final class FileLocationPatternConverter extends LogEventPatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final FileLocationPatternConverter INSTANCE =
+        new FileLocationPatternConverter();
+
+    /**
+     * Private constructor.
+     */
+    private FileLocationPatternConverter() {
+        super("File Location", "file");
+    }
+
+    /**
+     * Obtains an instance of pattern converter.
+     *
+     * @param options options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static FileLocationPatternConverter newInstance(
+        final String[] options) {
+        return INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder output) {
+        StackTraceElement element = event.getSource();
+
+        if (element != null) {
+            output.append(element.getFileName());
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FormattingInfo.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FormattingInfo.java
new file mode 100644
index 0000000..49f64c0
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FormattingInfo.java
@@ -0,0 +1,132 @@
+/*
+ * 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.layout.pattern;
+
+
+/**
+ * Modifies the output of a pattern converter for a specified minimum
+ * and maximum width and alignment.
+ */
+public final class FormattingInfo {
+    /**
+     * Array of spaces.
+     */
+    private static final char[] SPACES =
+        new char[]{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
+
+    /**
+     * Default instance.
+     */
+    private static final FormattingInfo DEFAULT =
+        new FormattingInfo(false, 0, Integer.MAX_VALUE);
+
+    /**
+     * Minimum length.
+     */
+    private final int minLength;
+
+    /**
+     * Maximum length.
+     */
+    private final int maxLength;
+
+    /**
+     * Alignment.
+     */
+    private final boolean leftAlign;
+
+    /**
+     * Creates new instance.
+     *
+     * @param leftAlign left align if true.
+     * @param minLength minimum length.
+     * @param maxLength maximum length.
+     */
+    public FormattingInfo(final boolean leftAlign, final int minLength, final int maxLength) {
+        this.leftAlign = leftAlign;
+        this.minLength = minLength;
+        this.maxLength = maxLength;
+    }
+
+    /**
+     * Gets default instance.
+     *
+     * @return default instance.
+     */
+    public static FormattingInfo getDefault() {
+        return DEFAULT;
+    }
+
+    /**
+     * Determine if left aligned.
+     *
+     * @return true if left aligned.
+     */
+    public boolean isLeftAligned() {
+        return leftAlign;
+    }
+
+    /**
+     * Get minimum length.
+     *
+     * @return minimum length.
+     */
+    public int getMinLength() {
+        return minLength;
+    }
+
+    /**
+     * Get maximum length.
+     *
+     * @return maximum length.
+     */
+    public int getMaxLength() {
+        return maxLength;
+    }
+
+    /**
+     * Adjust the content of the buffer based on the specified lengths and alignment.
+     *
+     * @param fieldStart start of field in buffer.
+     * @param buffer     buffer to be modified.
+     */
+    public void format(final int fieldStart, final StringBuilder buffer) {
+        final int rawLength = buffer.length() - fieldStart;
+
+        if (rawLength > maxLength) {
+            buffer.delete(fieldStart, buffer.length() - maxLength);
+        } else if (rawLength < minLength) {
+            if (leftAlign) {
+                final int fieldEnd = buffer.length();
+                buffer.setLength(fieldStart + minLength);
+
+                for (int i = fieldEnd; i < buffer.length(); i++) {
+                    buffer.setCharAt(i, ' ');
+                }
+            } else {
+                int padLength = minLength - rawLength;
+
+                for (; padLength > 8; padLength -= 8) {
+                    buffer.insert(fieldStart, SPACES);
+                }
+
+                buffer.insert(fieldStart, SPACES, 0, padLength);
+            }
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FullLocationPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FullLocationPatternConverter.java
new file mode 100644
index 0000000..09caedc
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/FullLocationPatternConverter.java
@@ -0,0 +1,64 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Format the event's line location information.
+ */
+@Plugin(name="FullLocationPatternConverter", type="Converter")
+@ConverterKeys({"l", "location"})
+public final class FullLocationPatternConverter extends LogEventPatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final FullLocationPatternConverter INSTANCE =
+        new FullLocationPatternConverter();
+
+    /**
+     * Private constructor.
+     */
+    private FullLocationPatternConverter() {
+        super("Full Location", "fullLocation");
+    }
+
+    /**
+     * Obtains an instance of pattern converter.
+     *
+     * @param options options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static FullLocationPatternConverter newInstance(
+        final String[] options) {
+        return INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder output) {
+        StackTraceElement element = event.getSource();
+
+        if (element != null) {
+            output.append(element.toString());
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/IntegerPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/IntegerPatternConverter.java
new file mode 100644
index 0000000..50e3fc8
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/IntegerPatternConverter.java
@@ -0,0 +1,67 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+import java.util.Date;
+
+
+/**
+ * Formats an integer.
+ */
+@Plugin(name="IntegerPatternConverter", type="FileConverter")
+@ConverterKeys({"i", "index"})
+public final class IntegerPatternConverter extends PatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final IntegerPatternConverter INSTANCE =
+        new IntegerPatternConverter();
+
+    /**
+     * Private constructor.
+     */
+    private IntegerPatternConverter() {
+        super("Integer", "integer");
+    }
+
+    /**
+     * Obtains an instance of pattern converter.
+     *
+     * @param options options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static IntegerPatternConverter newInstance(
+        final String[] options) {
+        return INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(Object obj, final StringBuilder toAppendTo) {
+        if (obj instanceof Integer) {
+            toAppendTo.append(obj.toString());
+        }
+
+        if (obj instanceof Date) {
+            toAppendTo.append(Long.toString(((Date) obj).getTime()));
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LevelPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LevelPatternConverter.java
new file mode 100644
index 0000000..3137532
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LevelPatternConverter.java
@@ -0,0 +1,95 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Return the event's level in a StringBuffer.
+ */
+@Plugin(name = "LevelPatternConverter", type = "Converter")
+@ConverterKeys({"p", "level"})
+public final class LevelPatternConverter extends LogEventPatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final LevelPatternConverter INSTANCE =
+        new LevelPatternConverter();
+
+    /**
+     * Private constructor.
+     */
+    private LevelPatternConverter() {
+        super("Level", "level");
+    }
+
+    /**
+     * Obtains an instance of pattern converter.
+     *
+     * @param options options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static LevelPatternConverter newInstance(
+        final String[] options) {
+        return INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder output) {
+        output.append(event.getLevel().toString());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getStyleClass(Object e) {
+        if (e instanceof LogEvent) {
+            Level level = ((LogEvent) e).getLevel();
+
+            switch (level) {
+                case TRACE:
+                    return "level trace";
+
+                case DEBUG:
+                    return "level debug";
+
+                case INFO:
+                    return "level info";
+
+                case WARN:
+                    return "level warn";
+
+                case ERROR:
+                    return "level error";
+
+                case FATAL:
+                    return "level fatal";
+
+                default:
+                    return "level " + ((LogEvent) e).getLevel().toString();
+            }
+        }
+
+        return "level";
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LineLocationPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LineLocationPatternConverter.java
new file mode 100644
index 0000000..37c1326
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LineLocationPatternConverter.java
@@ -0,0 +1,64 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Return the event's line location information in a StringBuffer.
+ */
+@Plugin(name="LineLocationPatternConverter", type="Converter")
+@ConverterKeys({"L", "line"})
+public final class LineLocationPatternConverter extends LogEventPatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final LineLocationPatternConverter INSTANCE =
+        new LineLocationPatternConverter();
+
+    /**
+     * Private constructor.
+     */
+    private LineLocationPatternConverter() {
+        super("Line", "line");
+    }
+
+    /**
+     * Obtains an instance of pattern converter.
+     *
+     * @param options options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static LineLocationPatternConverter newInstance(
+        final String[] options) {
+        return INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder output) {
+        StackTraceElement element = event.getSource();
+
+        if (element != null) {
+            output.append(element.getLineNumber());
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LineSeparatorPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LineSeparatorPatternConverter.java
new file mode 100644
index 0000000..27108d0
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LineSeparatorPatternConverter.java
@@ -0,0 +1,66 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Formats a line separator.
+ */
+@Plugin(name="LineSeparatorPatternConverter", type="Converter")
+@ConverterKeys({"n"})
+public final class LineSeparatorPatternConverter extends LogEventPatternConverter {
+  /**
+   * Singleton.
+   */
+  private static final LineSeparatorPatternConverter INSTANCE =
+    new LineSeparatorPatternConverter();
+
+  /**
+   * Line separator.
+   */
+  private final String lineSep;
+
+  /**
+   * Private constructor.
+   */
+  private LineSeparatorPatternConverter() {
+    super("Line Sep", "lineSep");
+    lineSep = Layout.LINE_SEP;
+  }
+
+  /**
+   * Obtains an instance of pattern converter.
+   * @param options options, may be null.
+   * @return instance of pattern converter.
+   */
+  public static LineSeparatorPatternConverter newInstance(
+    final String[] options) {
+    return INSTANCE;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void format(LogEvent event, final StringBuilder toAppendTo) {
+    toAppendTo.append(lineSep);
+  }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LiteralPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LiteralPatternConverter.java
new file mode 100644
index 0000000..6b3b18c
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LiteralPatternConverter.java
@@ -0,0 +1,47 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+
+
+/**
+ * Formats a string literal.
+ */
+public final class LiteralPatternConverter extends LogEventPatternConverter {
+  /**
+   * String literal.
+   */
+  private final String literal;
+
+  /**
+   * Create a new instance.
+   * @param literal string literal.
+   */
+  public LiteralPatternConverter(final String literal) {
+    super("Literal", "literal");
+    this.literal = literal;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void format(final LogEvent event, final StringBuilder toAppendTo) {
+    toAppendTo.append(literal);
+  }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LogEventPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LogEventPatternConverter.java
new file mode 100644
index 0000000..442892f
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LogEventPatternConverter.java
@@ -0,0 +1,71 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.internal.StatusLogger;
+
+/**
+ * LoggingEventPatternConverter is a base class for pattern converters
+ * that can format information from instances of LoggingEvent.
+ */
+public abstract class LogEventPatternConverter extends PatternConverter {
+
+    protected static final Logger logger = StatusLogger.getLogger();
+    /**
+     * Constructs an instance of LoggingEventPatternConverter.
+     *
+     * @param name  name of converter.
+     * @param style CSS style for output.
+     */
+    protected LogEventPatternConverter(
+        final String name, final String style) {
+        super(name, style);
+    }
+
+    /**
+     * Formats an event into a string buffer.
+     *
+     * @param event      event to format, may not be null.
+     * @param toAppendTo string buffer to which the formatted event will be appended.  May not be null.
+     */
+    public abstract void format(final LogEvent event, final StringBuilder toAppendTo);
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final Object obj, final StringBuilder output) {
+        if (obj instanceof LogEvent) {
+            format((LogEvent) obj, output);
+        }
+    }
+
+    /**
+     * Normally pattern converters are not meant to handle Exceptions although
+     * few pattern converters might.
+     * <p/>
+     * By examining the return values for this method, the containing layout will
+     * determine whether it handles throwables or not.
+     *
+     * @return true if this PatternConverter handles throwables
+     */
+    public boolean handlesThrowable() {
+        return false;
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LoggerPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LoggerPatternConverter.java
new file mode 100644
index 0000000..4bd7553
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/LoggerPatternConverter.java
@@ -0,0 +1,68 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Formats a logger name.
+ */
+@Plugin(name="LoggerPatternConverter", type="Converter")
+@ConverterKeys({"c", "logger"})
+public final class LoggerPatternConverter extends NamePatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final LoggerPatternConverter INSTANCE =
+        new LoggerPatternConverter(null);
+
+    /**
+     * Private constructor.
+     *
+     * @param options options, may be null.
+     */
+    private LoggerPatternConverter(final String[] options) {
+        super("Logger", "logger", options);
+    }
+
+    /**
+     * Obtains an instance of pattern converter.
+     *
+     * @param options options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static LoggerPatternConverter newInstance(
+        final String[] options) {
+        if ((options == null) || (options.length == 0)) {
+            return INSTANCE;
+        }
+
+        return new LoggerPatternConverter(options);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        final int initialLength = toAppendTo.length();
+        toAppendTo.append(event.getLoggerName());
+        abbreviate(initialLength, toAppendTo);
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/MDCPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/MDCPatternConverter.java
new file mode 100644
index 0000000..b31e999
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/MDCPatternConverter.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.logging.log4j.core.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * Able to handle the contents of the LogEvent's MDC and either
+ * output the entire contents of the properties in a similar format to the
+ * java.util.Hashtable.toString(), or to output the value of a specific key
+ * within the property bundle
+ * when this pattern converter has the option set.
+ */
+ @Plugin(name="MDCPatternConverter", type="Converter")
+@ConverterKeys({"X", "mdc", "MDC"})
+public final class MDCPatternConverter extends LogEventPatternConverter {
+    /**
+     * Name of property to output.
+     */
+    private final String key;
+
+    /**
+     * Private constructor.
+     *
+     * @param options options, may be null.
+     */
+    private MDCPatternConverter(final String[] options) {
+        super(((options != null) && (options.length > 0)) ? ("MDC{" + options[0] + "}") : "MDC", "mdc");
+        key = (options != null && options.length > 0) ? options[0] : null;
+    }
+
+    /**
+     * Obtains an instance of PropertiesPatternConverter.
+     *
+     * @param options options, may be null or first element contains name of property to format.
+     * @return instance of PropertiesPatternConverter.
+     */
+    public static MDCPatternConverter newInstance(
+        final String[] options) {
+        return new MDCPatternConverter(options);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        Map<String, Object> contextMap = event.getContextMap();
+        // if there is no additional options, we output every single
+        // Key/Value pair for the MDC in a similar format to Hashtable.toString()
+        if (key == null) {
+
+
+            if (contextMap == null || contextMap.size() == 0) {
+                toAppendTo.append("{}");
+                return;
+            }
+            StringBuilder sb = new StringBuilder("{");
+            Set<String> keys = new TreeSet<String>(contextMap.keySet());
+            for (String key : keys) {
+                if (sb.length() > 1) {
+                    sb.append(", ");
+                }
+                sb.append(key).append("=").append(contextMap.get(key));
+
+            }
+            sb.append("}");
+            toAppendTo.append(sb);
+        } else if (contextMap != null) {
+            // otherwise they just want a single key output
+            Object val = contextMap.get(key);
+
+            if (val != null) {
+                toAppendTo.append(val);
+            }
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/MessagePatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/MessagePatternConverter.java
new file mode 100644
index 0000000..bae943c
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/MessagePatternConverter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Return the event's rendered message in a StringBuffer.
+ */
+@Plugin(name="MessagePatternConverter", type="Converter")
+@ConverterKeys({"m", "message"})
+public final class MessagePatternConverter extends LogEventPatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final MessagePatternConverter INSTANCE =
+        new MessagePatternConverter();
+
+    /**
+     * Private constructor.
+     */
+    private MessagePatternConverter() {
+        super("Message", "message");
+    }
+
+    /**
+     * Obtains an instance of pattern converter.
+     *
+     * @param options options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static MessagePatternConverter newInstance(
+        final String[] options) {
+        return INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        toAppendTo.append(event.getMessage().getFormattedMessage());
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/MethodLocationPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/MethodLocationPatternConverter.java
new file mode 100644
index 0000000..aa3bd28
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/MethodLocationPatternConverter.java
@@ -0,0 +1,64 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Return the event's line location information in a StringBuffer.
+ */
+@Plugin(name = "MethodLocationPatternConverter", type = "Converter")
+@ConverterKeys({"M", "method"})
+public final class MethodLocationPatternConverter extends LogEventPatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final MethodLocationPatternConverter INSTANCE =
+        new MethodLocationPatternConverter();
+
+    /**
+     * Private constructor.
+     */
+    private MethodLocationPatternConverter() {
+        super("Method", "method");
+    }
+
+    /**
+     * Obtains an instance of MethodLocationPatternConverter.
+     *
+     * @param options options, may be null.
+     * @return instance of MethodLocationPatternConverter.
+     */
+    public static MethodLocationPatternConverter newInstance(
+        final String[] options) {
+        return INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        StackTraceElement element = event.getSource();
+
+        if (element != null) {
+            toAppendTo.append(element.getMethodName());
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/NDCPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/NDCPatternConverter.java
new file mode 100644
index 0000000..6552481
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/NDCPatternConverter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Return the event's NDC in a StringBuffer.
+ */
+@Plugin(name="NDCPatternConverter", type="Converter")
+@ConverterKeys({"C", "class"})
+public final class NDCPatternConverter extends LogEventPatternConverter {
+  /**
+   *   Singleton.
+   */
+  private static final NDCPatternConverter INSTANCE =
+    new NDCPatternConverter();
+
+  /**
+   * Private constructor.
+   */
+  private NDCPatternConverter() {
+    super("NDC", "ndc");
+  }
+
+  /**
+   * Obtains an instance of NDCPatternConverter.
+   * @param options options, may be null.
+   * @return instance of NDCPatternConverter.
+   */
+  public static NDCPatternConverter newInstance(
+    final String[] options) {
+    return INSTANCE;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void format(final LogEvent event, final StringBuilder toAppendTo) {
+    toAppendTo.append(event.getContextStack());
+  }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/NameAbbreviator.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/NameAbbreviator.java
new file mode 100644
index 0000000..d5cec0f
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/NameAbbreviator.java
@@ -0,0 +1,303 @@
+/*
+ * 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.layout.pattern;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * NameAbbreviator generates abbreviated logger and class names.
+ */
+public abstract class NameAbbreviator {
+    /**
+     * Default (no abbreviation) abbreviator.
+     */
+    private static final NameAbbreviator DEFAULT = new NOPAbbreviator();
+
+    /**
+     * Gets an abbreviator.
+     * <p/>
+     * For example, "%logger{2}" will output only 2 elements of the logger name,
+     * "%logger{1.}" will output only the first character of the non-final elements in the name,
+     * "%logger(1~.2~} will output the first character of the first element, two characters of
+     * the second and subsequent elements and will use a tilde to indicate abbreviated characters.
+     *
+     * @param pattern abbreviation pattern.
+     * @return abbreviator, will not be null.
+     */
+    public static NameAbbreviator getAbbreviator(final String pattern) {
+        if (pattern.length() > 0) {
+            //  if pattern is just spaces and numbers then
+            //     use MaxElementAbbreviator
+            String trimmed = pattern.trim();
+
+            if (trimmed.length() == 0) {
+                return DEFAULT;
+            }
+
+            int i = 0;
+
+            while ((i < trimmed.length()) && (trimmed.charAt(i) >= '0')
+                    && (trimmed.charAt(i) <= '9')) {
+                i++;
+            }
+
+            //
+            //  if all blanks and digits
+            //
+            if (i == trimmed.length()) {
+                return new MaxElementAbbreviator(Integer.parseInt(trimmed));
+            }
+
+            ArrayList<PatternAbbreviatorFragment> fragments = new ArrayList<PatternAbbreviatorFragment>(5);
+            char ellipsis;
+            int charCount;
+            int pos = 0;
+
+            while ((pos < trimmed.length()) && (pos >= 0)) {
+                int ellipsisPos = pos;
+
+                if (trimmed.charAt(pos) == '*') {
+                    charCount = Integer.MAX_VALUE;
+                    ellipsisPos++;
+                } else {
+                    if ((trimmed.charAt(pos) >= '0') && (trimmed.charAt(pos) <= '9')) {
+                        charCount = trimmed.charAt(pos) - '0';
+                        ellipsisPos++;
+                    } else {
+                        charCount = 0;
+                    }
+                }
+
+                ellipsis = '\0';
+
+                if (ellipsisPos < trimmed.length()) {
+                    ellipsis = trimmed.charAt(ellipsisPos);
+
+                    if (ellipsis == '.') {
+                        ellipsis = '\0';
+                    }
+                }
+
+                fragments.add(new PatternAbbreviatorFragment(charCount, ellipsis));
+                pos = trimmed.indexOf(".", pos);
+
+                if (pos == -1) {
+                    break;
+                }
+
+                pos++;
+            }
+
+            return new PatternAbbreviator(fragments);
+        }
+
+        //
+        //  no matching abbreviation, return defaultAbbreviator
+        //
+        return DEFAULT;
+    }
+
+    /**
+     * Gets default abbreviator.
+     *
+     * @return default abbreviator.
+     */
+    public static NameAbbreviator getDefaultAbbreviator() {
+        return DEFAULT;
+    }
+
+    /**
+     * Abbreviates a name in a StringBuffer.
+     *
+     * @param nameStart starting position of name in buf.
+     * @param buf       buffer, may not be null.
+     */
+    public abstract void abbreviate(final int nameStart, final StringBuilder buf);
+
+    /**
+     * Abbreviator that simply appends full name to buffer.
+     */
+    private static class NOPAbbreviator extends NameAbbreviator {
+        /**
+         * Constructor.
+         */
+        public NOPAbbreviator() {
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void abbreviate(final int nameStart, final StringBuilder buf) {
+        }
+    }
+
+    /**
+     * Abbreviator that drops starting path elements.
+     */
+    private static class MaxElementAbbreviator extends NameAbbreviator {
+        /**
+         * Maximum number of path elements to output.
+         */
+        private final int count;
+
+        /**
+         * Create new instance.
+         *
+         * @param count maximum number of path elements to output.
+         */
+        public MaxElementAbbreviator(final int count) {
+            this.count = count;
+        }
+
+        /**
+         * Abbreviate name.
+         *
+         * @param buf       buffer to append abbreviation.
+         * @param nameStart start of name to abbreviate.
+         */
+        public void abbreviate(final int nameStart, final StringBuilder buf) {
+            int len = buf.length() - nameStart;
+
+            // We substract 1 from 'len' when assigning to 'end' to avoid out of
+            // bounds exception in return r.substring(end+1, len). This can happen if
+            // precision is 1 and the category name ends with a dot.
+            int end = buf.length() - 1;
+
+            String bufString = buf.toString();
+            for (int i = count; i > 0; i--) {
+                end = bufString.lastIndexOf(".", end - 1);
+
+                if ((end == -1) || (end < nameStart)) {
+                    return;
+                }
+            }
+
+            buf.delete(nameStart, end + 1);
+        }
+    }
+
+    /**
+     * Fragment of an pattern abbreviator.
+     */
+    private static class PatternAbbreviatorFragment {
+        /**
+         * Count of initial characters of element to output.
+         */
+        private final int charCount;
+
+        /**
+         * Character used to represent dropped characters.
+         * '\0' indicates no representation of dropped characters.
+         */
+        private final char ellipsis;
+
+        /**
+         * Creates a PatternAbbreviatorFragment.
+         *
+         * @param charCount number of initial characters to preserve.
+         * @param ellipsis  character to represent elimination of characters,
+         *                  '\0' if no ellipsis is desired.
+         */
+        public PatternAbbreviatorFragment(
+            final int charCount, final char ellipsis) {
+            this.charCount = charCount;
+            this.ellipsis = ellipsis;
+        }
+
+        /**
+         * Abbreviate element of name.
+         *
+         * @param buf      buffer to receive element.
+         * @param startPos starting index of name element.
+         * @return starting index of next element.
+         */
+        public int abbreviate(final StringBuilder buf, final int startPos) {
+            int nextDot = buf.toString().indexOf(".", startPos);
+
+            if (nextDot != -1) {
+                if ((nextDot - startPos) > charCount) {
+                    buf.delete(startPos + charCount, nextDot);
+                    nextDot = startPos + charCount;
+
+                    if (ellipsis != '\0') {
+                        buf.insert(nextDot, ellipsis);
+                        nextDot++;
+                    }
+                }
+
+                nextDot++;
+            }
+
+            return nextDot;
+        }
+    }
+
+    /**
+     * Pattern abbreviator.
+     */
+    private static class PatternAbbreviator extends NameAbbreviator {
+        /**
+         * Element abbreviation patterns.
+         */
+        private final PatternAbbreviatorFragment[] fragments;
+
+        /**
+         * Create PatternAbbreviator.
+         *
+         * @param fragments element abbreviation patterns.
+         */
+        public PatternAbbreviator(List fragments) {
+            if (fragments.size() == 0) {
+                throw new IllegalArgumentException(
+                    "fragments must have at least one element");
+            }
+
+            this.fragments = new PatternAbbreviatorFragment[fragments.size()];
+            fragments.toArray(this.fragments);
+        }
+
+        /**
+         * Abbreviate name.
+         *
+         * @param buf       buffer that abbreviated name is appended.
+         * @param nameStart start of name.
+         */
+        public void abbreviate(final int nameStart, final StringBuilder buf) {
+            //
+            //  all non-terminal patterns are executed once
+            //
+            int pos = nameStart;
+
+            for (int i = 0; (i < (fragments.length - 1)) && (pos < buf.length());
+                 i++) {
+                pos = fragments[i].abbreviate(buf, pos);
+            }
+
+            //
+            //   last pattern in executed repeatedly
+            //
+            PatternAbbreviatorFragment terminalFragment = fragments[fragments.length - 1];
+
+            while ((pos < buf.length()) && (pos >= 0)) {
+                pos = terminalFragment.abbreviate(buf, pos);
+            }
+        }
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/NamePatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/NamePatternConverter.java
new file mode 100644
index 0000000..6e8e398
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/NamePatternConverter.java
@@ -0,0 +1,56 @@
+/*
+ * 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.layout.pattern;
+
+
+/**
+ * Base class for other pattern converters which can return only parts of their name.
+ */
+public abstract class NamePatternConverter extends LogEventPatternConverter {
+    /**
+     * Abbreviator.
+     */
+    private final NameAbbreviator abbreviator;
+
+    /**
+     * Constructor.
+     *
+     * @param name    name of converter.
+     * @param style   style name for associated output.
+     * @param options options, may be null, first element will be interpreted as an abbreviation pattern.
+     */
+    protected NamePatternConverter(final String name, final String style, final String[] options) {
+        super(name, style);
+
+        if ((options != null) && (options.length > 0)) {
+            abbreviator = NameAbbreviator.getAbbreviator(options[0]);
+        } else {
+            abbreviator = NameAbbreviator.getDefaultAbbreviator();
+        }
+    }
+
+    /**
+     * Abbreviate name in string buffer.
+     *
+     * @param nameStart starting position of name to abbreviate.
+     * @param buf       string buffer containing name.
+     */
+    protected final void abbreviate(final int nameStart, final StringBuilder buf) {
+        abbreviator.abbreviate(nameStart, buf);
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/PatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/PatternConverter.java
new file mode 100644
index 0000000..ed16089
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/PatternConverter.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.layout.pattern;
+
+
+/**
+ * <p>PatternConverter is an abstract class that provides the
+ * formatting functionality that derived classes need.
+ * <p/>
+ * <p>Conversion specifiers in a conversion patterns are parsed to
+ * individual PatternConverters. Each of which is responsible for
+ * converting an object in a converter specific manner.
+ */
+public abstract class PatternConverter {
+    /**
+     * Converter name.
+     */
+    private final String name;
+
+    /**
+     * Converter style name.
+     */
+    private final String style;
+
+    /**
+     * Create a new pattern converter.
+     *
+     * @param name  name for pattern converter.
+     * @param style CSS style for formatted output.
+     */
+    protected PatternConverter(final String name, final String style) {
+        this.name = name;
+        this.style = style;
+    }
+
+    /**
+     * Formats an object into a string buffer.
+     *
+     * @param obj        event to format, may not be null.
+     * @param toAppendTo string buffer to which the formatted event will be appended.  May not be null.
+     */
+    public abstract void format(final Object obj, final StringBuilder toAppendTo);
+
+    /**
+     * This method returns the name of the conversion pattern.
+     * <p/>
+     * The name can be useful to certain Layouts such as HTMLLayout.
+     *
+     * @return the name of the conversion pattern
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /**
+     * This method returns the CSS style class that should be applied to
+     * the LoggingEvent passed as parameter, which can be null.
+     * <p/>
+     * This information is currently used only by HTMLLayout.
+     *
+     * @param e null values are accepted
+     * @return the name of the conversion pattern
+     */
+    public String getStyleClass(Object e) {
+        return style;
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/PatternParser.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/PatternParser.java
new file mode 100644
index 0000000..28f3abd
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/PatternParser.java
@@ -0,0 +1,493 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.PluginManager;
+import org.apache.logging.log4j.core.config.plugins.PluginType;
+import org.apache.logging.log4j.internal.StatusLogger;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Most of the work of the {@link org.apache.logging.log4j.core.layout.PatternLayout} class
+ * is delegated to the PatternParser class.
+ * <p>It is this class that parses conversion patterns and creates
+ * a chained list of {@link PatternConverter PatternConverters}.
+ */
+public final class PatternParser {
+    /**
+     * Escape character for format specifier.
+     */
+    private static final char ESCAPE_CHAR = '%';
+
+    /**
+     * Literal state.
+     */
+    private static final int LITERAL_STATE = 0;
+
+    /**
+     * In converter name state.
+     */
+    private static final int CONVERTER_STATE = 1;
+
+    /**
+     * Dot state.
+     */
+    private static final int DOT_STATE = 3;
+
+    /**
+     * Min state.
+     */
+    private static final int MIN_STATE = 4;
+
+    /**
+     * Max state.
+     */
+    private static final int MAX_STATE = 5;
+
+    /**
+     * Does pattern process exceptions.
+     */
+    private boolean handlesExceptions;
+
+    private final Map<String, Class<PatternConverter>> converterRules;
+
+    protected final static Logger logger = StatusLogger.getLogger();
+
+
+    /**
+     * Constructor
+     * @param converterKey The key to lookup the converters.
+     */
+    public PatternParser(String converterKey) {
+        PluginManager manager = new PluginManager(converterKey);
+        manager.collectPlugins();
+        Map<String, PluginType> plugins = manager.getPlugins();
+        Map<String, Class<PatternConverter>> converters = new HashMap<String, Class<PatternConverter>>();
+
+        for (PluginType type : plugins.values()) {
+            try {
+                Class<PatternConverter> clazz = type.getPluginClass();
+                ConverterKeys keys = clazz.getAnnotation(ConverterKeys.class);
+                if (keys != null) {
+                    for (String key : keys.value()) {
+                        converters.put(key, clazz);
+                    }
+                }
+            } catch (Exception ex) {
+
+            }
+        }
+        converterRules = converters;
+    }
+
+
+    public List<PatternConverter> parse(String pattern) {
+        List<PatternConverter> converters = new ArrayList<PatternConverter>();
+        List<FormattingInfo> fields = new ArrayList<FormattingInfo>();
+
+        parse(pattern, converters, fields, converterRules);
+
+        LogEventPatternConverter[] patternConverters = new LogEventPatternConverter[converters.size()];
+        FormattingInfo[] patternFields = new FormattingInfo[converters.size()];
+
+        int i = 0;
+        Iterator fieldIter = fields.iterator();
+
+        for (PatternConverter converter : converters) {
+            if (converter instanceof LogEventPatternConverter) {
+                patternConverters[i] = (LogEventPatternConverter) converter;
+                handlesExceptions |= patternConverters[i].handlesThrowable();
+            } else {
+                patternConverters[i] = new LiteralPatternConverter("");
+            }
+
+            if (fieldIter.hasNext()) {
+                patternFields[i] = (FormattingInfo) fieldIter.next();
+            } else {
+                patternFields[i] = FormattingInfo.getDefault();
+            }
+
+            i++;
+        }
+        return converters;
+    }
+
+    public boolean handlesExceptions() {
+        return handlesExceptions;
+    }
+
+    /**
+     * Extract the converter identifier found at position i.
+     * <p/>
+     * After this function returns, the variable i will point to the
+     * first char after the end of the converter identifier.
+     * <p/>
+     * If i points to a char which is not a character acceptable at the
+     * start of a unicode identifier, the value null is returned.
+     *
+     * @param lastChar       last processed character.
+     * @param pattern        format string.
+     * @param i              current index into pattern format.
+     * @param convBuf        buffer to receive conversion specifier.
+     * @param currentLiteral literal to be output in case format specifier in unrecognized.
+     * @return position in pattern after converter.
+     */
+    private static int extractConverter(
+        char lastChar, final String pattern, int i, final StringBuilder convBuf,
+        final StringBuilder currentLiteral) {
+        convBuf.setLength(0);
+
+        // When this method is called, lastChar points to the first character of the
+        // conversion word. For example:
+        // For "%hello"     lastChar = 'h'
+        // For "%-5hello"   lastChar = 'h'
+        //System.out.println("lastchar is "+lastChar);
+        if (!Character.isUnicodeIdentifierStart(lastChar)) {
+            return i;
+        }
+
+        convBuf.append(lastChar);
+
+        while ((i < pattern.length()) && Character.isUnicodeIdentifierPart(pattern.charAt(i))) {
+            convBuf.append(pattern.charAt(i));
+            currentLiteral.append(pattern.charAt(i));
+            i++;
+        }
+
+        return i;
+    }
+
+    /**
+     * Extract options.
+     *
+     * @param pattern conversion pattern.
+     * @param i       start of options.
+     * @param options array to receive extracted options
+     * @return position in pattern after options.
+     */
+    private static int extractOptions(String pattern, int i, List<String> options) {
+        while ((i < pattern.length()) && (pattern.charAt(i) == '{')) {
+            int end = pattern.indexOf('}', i);
+
+            if (end == -1) {
+                break;
+            }
+
+            String r = pattern.substring(i + 1, end);
+            options.add(r);
+            i = end + 1;
+        }
+
+        return i;
+    }
+
+    /**
+     * Parse a format specifier.
+     *
+     * @param pattern           pattern to parse.
+     * @param patternConverters list to receive pattern converters.
+     * @param formattingInfos   list to receive field specifiers corresponding to pattern converters.
+     * @param rules             map of stock pattern converters keyed by format specifier.
+     */
+    public void parse(final String pattern, final List<PatternConverter> patternConverters,
+            final List<FormattingInfo> formattingInfos,
+            final Map<String, Class<PatternConverter>> rules) {
+        if (pattern == null) {
+            throw new NullPointerException("pattern");
+        }
+
+        StringBuilder currentLiteral = new StringBuilder(32);
+
+        int patternLength = pattern.length();
+        int state = LITERAL_STATE;
+        char c;
+        int i = 0;
+        FormattingInfo formattingInfo = FormattingInfo.getDefault();
+
+        while (i < patternLength) {
+            c = pattern.charAt(i++);
+
+            switch (state) {
+                case LITERAL_STATE:
+
+                    // In literal state, the last char is always a literal.
+                    if (i == patternLength) {
+                        currentLiteral.append(c);
+
+                        continue;
+                    }
+
+                    if (c == ESCAPE_CHAR) {
+                        // peek at the next char.
+                        switch (pattern.charAt(i)) {
+                            case ESCAPE_CHAR:
+                                currentLiteral.append(c);
+                                i++; // move pointer
+
+                                break;
+
+                            default:
+
+                                if (currentLiteral.length() != 0) {
+                                    patternConverters.add(new LiteralPatternConverter(currentLiteral.toString()));
+                                    formattingInfos.add(FormattingInfo.getDefault());
+                                }
+
+                                currentLiteral.setLength(0);
+                                currentLiteral.append(c); // append %
+                                state = CONVERTER_STATE;
+                                formattingInfo = FormattingInfo.getDefault();
+                        }
+                    } else {
+                        currentLiteral.append(c);
+                    }
+
+                    break;
+
+                case CONVERTER_STATE:
+                    currentLiteral.append(c);
+
+                    switch (c) {
+                        case '-':
+                            formattingInfo =
+                                new FormattingInfo(true, formattingInfo.getMinLength(),
+                                    formattingInfo.getMaxLength());
+
+                            break;
+
+                        case '.':
+                            state = DOT_STATE;
+
+                            break;
+
+                        default:
+
+                            if ((c >= '0') && (c <= '9')) {
+                                formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), c - '0',
+                                        formattingInfo.getMaxLength());
+                                state = MIN_STATE;
+                            } else {
+                                i = finalizeConverter(c, pattern, i, currentLiteral, formattingInfo,
+                                        rules, patternConverters, formattingInfos);
+
+                                // Next pattern is assumed to be a literal.
+                                state = LITERAL_STATE;
+                                formattingInfo = FormattingInfo.getDefault();
+                                currentLiteral.setLength(0);
+                            }
+                    } // switch
+
+                    break;
+
+                case MIN_STATE:
+                    currentLiteral.append(c);
+
+                    if ((c >= '0') && (c <= '9')) {
+                        formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(),
+                                (formattingInfo.getMinLength() * 10) + (c - '0'),
+                                formattingInfo.getMaxLength());
+                    } else if (c == '.') {
+                        state = DOT_STATE;
+                    } else {
+                        i = finalizeConverter(c, pattern, i, currentLiteral, formattingInfo,
+                                rules, patternConverters, formattingInfos);
+                        state = LITERAL_STATE;
+                        formattingInfo = FormattingInfo.getDefault();
+                        currentLiteral.setLength(0);
+                    }
+
+                    break;
+
+                case DOT_STATE:
+                    currentLiteral.append(c);
+
+                    if ((c >= '0') && (c <= '9')) {
+                        formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(),
+                            formattingInfo.getMinLength(), c - '0');
+                        state = MAX_STATE;
+                    } else {
+                        logger.error("Error occurred in position " + i
+                                + ".\n Was expecting digit, instead got char \"" + c + "\".");
+
+                        state = LITERAL_STATE;
+                    }
+
+                    break;
+
+                case MAX_STATE:
+                    currentLiteral.append(c);
+
+                    if ((c >= '0') && (c <= '9')) {
+                        formattingInfo = new FormattingInfo(
+                                formattingInfo.isLeftAligned(), formattingInfo.getMinLength(),
+                                (formattingInfo.getMaxLength() * 10) + (c - '0'));
+                    } else {
+                        i = finalizeConverter(c, pattern, i, currentLiteral, formattingInfo,
+                                rules, patternConverters, formattingInfos);
+                        state = LITERAL_STATE;
+                        formattingInfo = FormattingInfo.getDefault();
+                        currentLiteral.setLength(0);
+                    }
+
+                    break;
+            } // switch
+        }
+
+        // while
+        if (currentLiteral.length() != 0) {
+            patternConverters.add(new LiteralPatternConverter(currentLiteral.toString()));
+            formattingInfos.add(FormattingInfo.getDefault());
+        }
+    }
+
+    /**
+     * Creates a new PatternConverter.
+     *
+     * @param converterId       converterId.
+     * @param currentLiteral    literal to be used if converter is unrecognized or following converter
+     *                          if converterId contains extra characters.
+     * @param rules             map of stock pattern converters keyed by format specifier.
+     * @param options           converter options.
+     * @return converter or null.
+     */
+    private PatternConverter createConverter(final String converterId, final StringBuilder currentLiteral,
+            final Map<String, Class<PatternConverter>> rules,
+            final List<String> options) {
+        String converterName = converterId;
+        Class<PatternConverter> converterClass = null;
+
+        for (int i = converterId.length(); (i > 0) && (converterClass == null); i--) {
+            converterName = converterName.substring(0, i);
+
+            if ((converterClass == null) && (rules != null)) {
+                converterClass = rules.get(converterName);
+            }
+        }
+
+        if (converterClass == null) {
+            logger.error("Unrecognized format specifier [" + converterId + "]");
+
+            return null;
+        }
+
+        try {
+            Method factory = converterClass.getMethod(
+                    "newInstance",
+                    new Class[]{
+                        Class.forName("[Ljava.lang.String;")
+                    });
+            String[] optionsArray = new String[options.size()];
+            optionsArray = options.toArray(optionsArray);
+
+            Object newObj = factory.invoke(null, new Object[]{optionsArray});
+
+            if (newObj instanceof PatternConverter) {
+                currentLiteral.delete(0, currentLiteral.length()
+                        - (converterId.length() - converterName.length()));
+
+                return (PatternConverter) newObj;
+            } else {
+                logger.warn("Class " + converterClass.getName() + " does not extend PatternConverter.");
+            }
+        } catch (Exception ex) {
+            logger.error("Error creating converter for " + converterId, ex);
+
+            try {
+                //
+                //  try default constructor
+                PatternConverter pc = converterClass.newInstance();
+                currentLiteral.delete(0, currentLiteral.length()
+                        - (converterId.length() - converterName.length()));
+
+                return pc;
+            } catch (Exception ex2) {
+                logger.error("Error creating converter for " + converterId, ex2);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Processes a format specifier sequence.
+     *
+     * @param c                 initial character of format specifier.
+     * @param pattern           conversion pattern
+     * @param i                 current position in conversion pattern.
+     * @param currentLiteral    current literal.
+     * @param formattingInfo    current field specifier.
+     * @param rules             map of stock pattern converters keyed by format specifier.
+     * @param patternConverters list to receive parsed pattern converter.
+     * @param formattingInfos   list to receive corresponding field specifier.
+     * @return position after format specifier sequence.
+     */
+    private int finalizeConverter(char c, String pattern, int i,
+            final StringBuilder currentLiteral, final FormattingInfo formattingInfo,
+            final Map<String, Class<PatternConverter>> rules,
+            final List<PatternConverter> patternConverters, final List<FormattingInfo> formattingInfos) {
+        StringBuilder convBuf = new StringBuilder();
+        i = extractConverter(c, pattern, i, convBuf, currentLiteral);
+
+        String converterId = convBuf.toString();
+
+        List<String> options = new ArrayList<String>();
+        i = extractOptions(pattern, i, options);
+
+        PatternConverter pc = createConverter(converterId, currentLiteral, rules, options);
+
+        if (pc == null) {
+            StringBuilder msg;
+
+            if ((converterId == null) || (converterId.length() == 0)) {
+                msg =
+                    new StringBuilder("Empty conversion specifier starting at position ");
+            } else {
+                msg = new StringBuilder("Unrecognized conversion specifier [");
+                msg.append(converterId);
+                msg.append("] starting at position ");
+            }
+
+            msg.append(Integer.toString(i));
+            msg.append(" in conversion pattern.");
+
+            logger.error(msg.toString());
+
+            patternConverters.add(new LiteralPatternConverter(currentLiteral.toString()));
+            formattingInfos.add(FormattingInfo.getDefault());
+        } else {
+            patternConverters.add(pc);
+            formattingInfos.add(formattingInfo);
+
+            if (currentLiteral.length() > 0) {
+                patternConverters.add(new LiteralPatternConverter(currentLiteral.toString()));
+                formattingInfos.add(FormattingInfo.getDefault());
+            }
+        }
+
+        currentLiteral.setLength(0);
+
+        return i;
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/RelativeTimePatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/RelativeTimePatternConverter.java
new file mode 100644
index 0000000..8fc4ee2
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/RelativeTimePatternConverter.java
@@ -0,0 +1,70 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Return the relative time in milliseconds since loading of the LoggingEvent
+ * class.
+ */
+@Plugin(name="RelativeTimePatternConverter", type="Converter")
+@ConverterKeys({"r", "relative"})
+public class RelativeTimePatternConverter extends LogEventPatternConverter {
+    /**
+     * Cached formatted timestamp.
+     */
+    private long lastTimestamp = Long.MIN_VALUE;
+    private long startTime = System.currentTimeMillis();
+    private String relative;
+
+    /**
+     * Private constructor.
+     */
+    public RelativeTimePatternConverter() {
+        super("Time", "time");
+    }
+
+    /**
+     * Obtains an instance of RelativeTimePatternConverter.
+     *
+     * @param options options, currently ignored, may be null.
+     * @return instance of RelativeTimePatternConverter.
+     */
+    public static RelativeTimePatternConverter newInstance(
+        final String[] options) {
+        return new RelativeTimePatternConverter();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        long timestamp = event.getMillis();
+
+        synchronized (this) {
+            if (timestamp != lastTimestamp) {
+                lastTimestamp = timestamp;
+                relative = Long.toString(timestamp - startTime);
+            }
+        }
+        toAppendTo.append(relative);
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/SequenceNumberPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/SequenceNumberPatternConverter.java
new file mode 100644
index 0000000..678b2ea
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/SequenceNumberPatternConverter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+
+/**
+ * Formats the event sequence number.
+ */
+@Plugin(name="SequenceNumberPatternConverter", type="Converter")
+@ConverterKeys({"sn", "sequenceNumber"})
+public class SequenceNumberPatternConverter extends LogEventPatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final SequenceNumberPatternConverter INSTANCE =
+        new SequenceNumberPatternConverter();
+
+    /**
+     * Private constructor.
+     */
+    private SequenceNumberPatternConverter() {
+        super("Sequence Number", "sn");
+    }
+
+    /**
+     * Obtains an instance of SequencePatternConverter.
+     *
+     * @param options options, currently ignored, may be null.
+     * @return instance of SequencePatternConverter.
+     */
+    public static SequenceNumberPatternConverter newInstance(
+        final String[] options) {
+        return INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        toAppendTo.append("0");
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ThreadPatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ThreadPatternConverter.java
new file mode 100644
index 0000000..69698b7
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ThreadPatternConverter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+/**
+ * Formats the event thread name.
+ */
+@Plugin(name="ThreadPatternConverter", type="Converter")
+@ConverterKeys({"t", "thread"})
+public class ThreadPatternConverter extends LogEventPatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final ThreadPatternConverter INSTANCE =
+        new ThreadPatternConverter();
+
+    /**
+     * Private constructor.
+     */
+    private ThreadPatternConverter() {
+        super("Thread", "thread");
+    }
+
+    /**
+     * Obtains an instance of ThreadPatternConverter.
+     *
+     * @param options options, currently ignored, may be null.
+     * @return instance of ThreadPatternConverter.
+     */
+    public static ThreadPatternConverter newInstance(
+        final String[] options) {
+        return INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        toAppendTo.append(event.getThreadName());
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ThrowablePatternConverter.java b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ThrowablePatternConverter.java
new file mode 100644
index 0000000..e2435f9
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/ThrowablePatternConverter.java
@@ -0,0 +1,92 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+
+/**
+ * Outputs the ThrowableInformation portion of the LoggingiEvent as a full stacktrace
+ * unless this converter's option is 'short', where it just outputs the first line of the trace.
+ */
+@Plugin(name = "ThrowablePatternConverter", type = "Converter")
+@ConverterKeys({"ex", "throwable"})
+public class ThrowablePatternConverter extends LogEventPatternConverter {
+    /**
+     * If "short", only first line of throwable report will be formatted.
+     */
+    private final String option;
+
+    /**
+     * Private constructor.
+     *
+     * @param options options, may be null.
+     */
+    private ThrowablePatternConverter(final String[] options) {
+        super("Throwable", "throwable");
+
+        if ((options != null) && (options.length > 0)) {
+            option = options[0];
+        } else {
+            option = null;
+        }
+    }
+
+    /**
+     * Gets an instance of the class.
+     *
+     * @param options pattern options, may be null.  If first element is "short",
+     *                only the first line of the throwable will be formatted.
+     * @return instance of class.
+     */
+    public static ThrowablePatternConverter newInstance(
+        final String[] options) {
+        return new ThrowablePatternConverter(options);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        Throwable t = event.getThrown();
+
+        if (t != null) {
+            if (option == null || option.equals("full")) {
+                StringWriter w = new StringWriter();
+                t.printStackTrace(new PrintWriter(w));
+                toAppendTo.append(w.toString());
+            } else {
+                StackTraceElement[] e = t.getStackTrace();
+                toAppendTo.append(t.toString()).append(" at ").append(e[0].toString());
+            }
+        }
+    }
+
+    /**
+     * This converter obviously handles throwables.
+     *
+     * @return true.
+     */
+    public boolean handlesThrowable() {
+        return true;
+    }
+}
diff --git a/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/package.html b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/package.html
new file mode 100644
index 0000000..a61bfdd
--- /dev/null
+++ b/log4j2-core/src/main/java/org/apache/logging/log4j/core/layout/pattern/package.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html> <head>
+<title></title>
+</head>
+
+<body>
+
+<p>Provides classes implementing format specifiers in conversion patterns.</p>
+
+<hr>
+</body> </html>
diff --git a/log4j2-core/src/main/resources/META-INF/LICENSE b/log4j2-core/src/main/resources/META-INF/LICENSE
new file mode 100644
index 0000000..6279e52
--- /dev/null
+++ b/log4j2-core/src/main/resources/META-INF/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 1999-2005 The Apache Software Foundation
+
+   Licensed 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.
diff --git a/log4j2-core/src/main/resources/META-INF/NOTICE b/log4j2-core/src/main/resources/META-INF/NOTICE
new file mode 100644
index 0000000..6233b56
--- /dev/null
+++ b/log4j2-core/src/main/resources/META-INF/NOTICE
@@ -0,0 +1,5 @@
+Apache log4j Enhanced PatternLayout for log4j 1.2.x
+Copyright 2007 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
diff --git a/log4j2-core/src/main/resources/META-INF/log4j-provider.xml b/log4j2-core/src/main/resources/META-INF/log4j-provider.xml
new file mode 100644
index 0000000..bac73a7
--- /dev/null
+++ b/log4j2-core/src/main/resources/META-INF/log4j-provider.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+    <entry key="LoggerContextClass">org.apache.logging.log4j.core.LoggerContext</entry>
+    <entry key="Log4jAPIVersion">1.99.0</entry>
+</properties>
\ No newline at end of file
diff --git a/log4j2-core/src/site/resources/css/site.css b/log4j2-core/src/site/resources/css/site.css
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/log4j2-core/src/site/resources/css/site.css
@@ -0,0 +1 @@
+
diff --git a/log4j2-core/src/site/resources/images/logo.jpg b/log4j2-core/src/site/resources/images/logo.jpg
new file mode 100644
index 0000000..5b6ede8
--- /dev/null
+++ b/log4j2-core/src/site/resources/images/logo.jpg
Binary files differ
diff --git a/log4j2-core/src/site/resources/images/ls-logo.jpg b/log4j2-core/src/site/resources/images/ls-logo.jpg
new file mode 100755
index 0000000..611c5c3
--- /dev/null
+++ b/log4j2-core/src/site/resources/images/ls-logo.jpg
Binary files differ
diff --git a/log4j2-core/src/site/site.xml b/log4j2-core/src/site/site.xml
new file mode 100644
index 0000000..8bef54f
--- /dev/null
+++ b/log4j2-core/src/site/site.xml
@@ -0,0 +1,36 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project name="Component">
+  <bannerLeft>
+    <name>Logging Services</name>
+    <src>images/ls-logo.jpg</src>
+    <href>http://logging.apache.org/</href>
+  </bannerLeft>
+  <bannerRight>
+    <src>images/logo.jpg</src>
+  </bannerRight>
+  <body>
+    <links>
+      <item name="Apache" href="http://www.apache.org/" />
+      <item name="Logging Services" href="http://logging.apache.org/"/>
+      <item name="Log4j" href="http://logging.apache.org/log4j/"/>
+      <item name="Log4j Companions" href="http://logging.apache.org/log4j/companions"/>
+    </links>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/BasicConfigurationFactory.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/BasicConfigurationFactory.java
new file mode 100644
index 0000000..5a87dd3
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/BasicConfigurationFactory.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.config.BaseConfiguration;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+
+/**
+ *
+ */
+public class BasicConfigurationFactory extends ConfigurationFactory {
+
+    public Configuration getConfiguration() {
+        return new BasicConfiguration();
+    }
+
+    public class BasicConfiguration extends BaseConfiguration {
+
+    private static final String DEFAULT_LEVEL = "org.apache.logging.log4j.level";
+
+     public BasicConfiguration() {
+
+        LoggerConfig root = getRootLogger();
+        String l = System.getProperty(DEFAULT_LEVEL);
+        Level level = (l != null && Level.valueOf(l) != null) ? Level.valueOf(l) : Level.ERROR;
+        root.setLevel(level);
+    }
+}
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/SimplePerfTest.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/SimplePerfTest.java
new file mode 100644
index 0000000..0d90d49
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/SimplePerfTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.internal.StatusLogger;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class SimplePerfTest {
+
+    private static org.apache.logging.log4j.Logger logger = LogManager.getLogger(SimplePerfTest.class.getName());
+    private volatile Level lvl = Level.DEBUG;
+    private static final int LOOP_CNT = 100000000;
+
+    @Test
+    public void debugDisabled() {
+        Timer timer = new Timer("DebugDisabled", LOOP_CNT);
+        timer.start();
+        for (int i=0; i < LOOP_CNT; ++i) {
+            logger.isDebugEnabled();
+        }
+        timer.stop();
+        System.out.println(timer.toString());
+    }
+
+    @Test
+    public void debugLogger() {
+        Timer timer = new Timer("DebugLogger", LOOP_CNT);
+        timer.start();
+        for (int i=0; i < LOOP_CNT; ++i) {
+            logger.debug("This is a test");
+        }
+        timer.stop();
+        System.out.println(timer.toString());
+    }
+    /*
+    @Test
+    public void errorLogger() {
+        Timer timer = new Timer("ErrorLogger", 10);
+        timer.start();
+        for (int i=0; i < 10; ++i) {
+            logger.error("This is a test");
+        }
+        timer.stop();
+        System.out.println(timer.toString());
+    }  */
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/ThreadedPerfTest.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/ThreadedPerfTest.java
new file mode 100644
index 0000000..e6e3f76
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/ThreadedPerfTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.junit.Test;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ *
+ */
+public class ThreadedPerfTest {
+
+    private static org.apache.logging.log4j.Logger logger = LogManager.getLogger(ThreadedPerfTest.class.getName());
+    private volatile Level lvl = Level.DEBUG;
+    private static final int LOOP_CNT = 10000000;
+    private static final int THREADS = 10;     
+
+    @Test
+    public void debugDisabled() {
+        Timer timer = new Timer("DebugDisabled", LOOP_CNT * THREADS);
+        Runnable runnable = new DebugDisabledRunnable();
+        ExecutorService pool = Executors.newFixedThreadPool(THREADS);
+        timer.start();
+        for (int i=0; i < THREADS; ++i) {
+            pool.execute(runnable);
+        }
+        pool.shutdown();
+        timer.stop();
+        System.out.println(timer.toString());
+    }
+
+    @Test
+    public void debugLogger() {
+        Timer timer = new Timer("DebugLogger", LOOP_CNT * THREADS);
+        Runnable runnable = new DebugLoggerRunnable();
+        ExecutorService pool = Executors.newFixedThreadPool(THREADS);
+        timer.start();
+        for (int i=0; i < THREADS; ++i) {
+            pool.execute(runnable);
+        }
+        pool.shutdown();
+        timer.stop();
+        System.out.println(timer.toString());
+    }
+
+    public class DebugDisabledRunnable implements Runnable {
+        public void run() {
+            for (int i=0; i < LOOP_CNT; ++i) {
+                logger.isDebugEnabled();
+            }
+        }
+    }
+
+     public class DebugLoggerRunnable implements Runnable {
+        public void run() {
+            for (int i=0; i < LOOP_CNT; ++i) {
+                logger.debug("This is a test");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/Timer.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/Timer.java
new file mode 100644
index 0000000..508dc16
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/Timer.java
@@ -0,0 +1,252 @@
+/*
+ * 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;
+
+import java.io.Serializable;
+import java.text.DecimalFormat;
+
+/**
+ *
+ */
+public class Timer implements Serializable
+{
+    private String m_name;              // The timer's name
+    private String m_status;            // The timer's status
+    private long m_startTime;           // The start time
+    private long m_elapsedTime;         // The elapsed time
+    private int m_iterations;
+    private static long NANO_PER_SECOND = 1000000000L;
+    private static long NANO_PER_MINUTE = NANO_PER_SECOND * 60;
+    private static long NANO_PER_HOUR = NANO_PER_MINUTE * 60;
+
+
+    /**
+     * Constructor.
+     * @param name the timer name.
+     */
+    public Timer(String name)
+    {
+        this(name, 0);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param name the timer name.
+     */
+    public Timer(String name, int iterations)
+    {
+        m_name = name;
+        m_startTime = 0;
+        m_status = "Stopped";
+        m_iterations = (iterations > 0) ? iterations : 0;
+    }
+
+    /**
+     * Start the timer.
+     */
+    public void start()
+    {
+        m_startTime = System.nanoTime();
+        m_elapsedTime = 0;
+        m_status = "Start";
+    }
+
+    /**
+     * Stop the timer.
+     */
+    public void stop()
+    {
+        m_elapsedTime += System.nanoTime() - m_startTime;
+        m_startTime = 0;
+        m_status = "Stop";
+    }
+
+    /**
+     * Pause the timer.
+     */
+    public void pause()
+    {
+        m_elapsedTime += System.nanoTime() - m_startTime;
+        m_startTime = 0;
+        m_status = "Pause";
+    }
+
+    /**
+     * Resume the timer.
+     */
+    public void resume()
+    {
+        m_startTime = System.nanoTime();
+        m_status = "Resume";
+    }
+
+    /**
+     * Accessor for the name.
+     * @return the timer's name.
+     */
+    public String getName()
+    {
+        return m_name;
+    }
+
+    /**
+     * Access the elapsed time.
+     *
+     * @return the elapsed time.
+     */
+    public long getElapsedTime()
+    {
+        return m_elapsedTime / 1000000;
+    }
+
+    /**
+     * Access the elapsed time.
+     *
+     * @return the elapsed time.
+     */
+    public long getElapsedNanoTime()
+    {
+        return m_elapsedTime;
+    }
+
+    /**
+     * Return the name of the last operation performed on this timer (Start, Stop, Pause or
+     * Resume).
+     * @return the string representing the last operation performed.
+     */
+    public String getStatus()
+    {
+        return m_status;
+    }
+
+    /**
+     * Return the String representation of the timer based upon its current state
+     */
+    public String toString()
+    {
+        StringBuilder result = new StringBuilder("Timer ").append(m_name);
+        if (m_status.equals("Start"))
+        {
+            result.append(" started");
+        }
+        else if (m_status.equals("Pause"))
+        {
+            result.append(" paused");
+        }
+        else if (m_status.equals("Resume"))
+        {
+            result.append(" resumed");
+        }
+        else if (m_status.equals("Stop"))
+        {
+            long nanoseconds = m_elapsedTime;
+            // Get elapsed hours
+            long hours = nanoseconds / NANO_PER_HOUR;
+            // Get remaining nanoseconds
+            nanoseconds = nanoseconds % NANO_PER_HOUR;
+            // Get minutes
+            long minutes = nanoseconds / NANO_PER_MINUTE;
+            // Get remaining nanoseconds
+            nanoseconds = nanoseconds % NANO_PER_MINUTE;
+            // Get seconds
+            long seconds = nanoseconds / NANO_PER_SECOND;
+            // Get remaining nanoseconds
+            nanoseconds = nanoseconds % NANO_PER_SECOND;
+
+            String elapsed = "";
+
+            if (hours > 0)
+            {
+                elapsed += hours + " hours ";
+            }
+            if (minutes > 0 || hours > 0)
+            {
+                elapsed += minutes + " minutes ";
+            }
+
+            DecimalFormat numFormat = null;
+            numFormat = new DecimalFormat("#0");
+            elapsed += numFormat.format(seconds) + ".";
+            numFormat = new DecimalFormat("000000000");
+            elapsed += numFormat.format(nanoseconds) + " seconds";
+            result.append(" stopped. Elapsed time: ").append(elapsed);
+            if (m_iterations > 0)
+            {
+                nanoseconds = m_elapsedTime / m_iterations;
+                // Get elapsed hours
+                hours = nanoseconds / NANO_PER_HOUR;
+                // Get remaining nanoseconds
+                nanoseconds = nanoseconds % NANO_PER_HOUR;
+                // Get minutes
+                minutes = nanoseconds / NANO_PER_MINUTE;
+                // Get remaining nanoseconds
+                nanoseconds = nanoseconds % NANO_PER_MINUTE;
+                // Get seconds
+                seconds = nanoseconds / NANO_PER_SECOND;
+                // Get remaining nanoseconds
+                nanoseconds = nanoseconds % NANO_PER_SECOND;
+
+                elapsed = "";
+
+                if (hours > 0)
+                {
+                    elapsed += hours + " hours ";
+                }
+                if (minutes > 0 || hours > 0)
+                {
+                    elapsed += minutes + " minutes ";
+                }
+
+                numFormat = new DecimalFormat("#0");
+                elapsed += numFormat.format(seconds) + ".";
+                numFormat = new DecimalFormat("000000000");
+                elapsed += numFormat.format(nanoseconds) + " seconds";
+                result.append(" Average per iteration: ").append(elapsed);
+            }
+        }
+        else
+        {
+            result.append(" ").append(m_status);
+        }
+        return result.toString();
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof Timer)) return false;
+
+        final Timer timer = (Timer) o;
+
+        if (m_elapsedTime != timer.m_elapsedTime) return false;
+        if (m_startTime != timer.m_startTime) return false;
+        if (m_name != null ? !m_name.equals(timer.m_name) : timer.m_name != null) return false;
+        if (m_status != null ? !m_status.equals(timer.m_status) : timer.m_status != null) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = (m_name != null ? m_name.hashCode() : 0);
+        result = 29 * result + (m_status != null ? m_status.hashCode() : 0);
+        result = 29 * result + (int) (m_startTime ^ (m_startTime >>> 32));
+        result = 29 * result + (int) (m_elapsedTime ^ (m_elapsedTime >>> 32));
+        return result;
+    }
+
+}
\ No newline at end of file
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/config/XMLConfigurationTest.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/config/XMLConfigurationTest.java
new file mode 100644
index 0000000..e4f714d
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/config/XMLConfigurationTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.config;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.filter.MDCFilter;
+import org.apache.logging.log4j.internal.StatusData;
+import org.apache.logging.log4j.internal.StatusLogger;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+
+/**
+ *
+ */
+public class XMLConfigurationTest {
+
+    private static final String CONFIG = "log4j-test1.xml";
+
+    @BeforeClass
+    public static void setupClass() {
+        System.setProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
+        LoggerContext ctx = (LoggerContext) LogManager.getContext();
+        Configuration config = ctx.getConfiguration();
+        if (config instanceof XMLConfiguration) {
+            String name = ((XMLConfiguration) config).getName();
+            if (name == null || !name.equals("XMLConfigTest")) {
+                ctx.reconfigure();
+            }
+        } else {
+            ctx.reconfigure();
+        }
+    }
+
+    @AfterClass
+    public static void cleanupClass() {
+        System.clearProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
+        LoggerContext ctx = (LoggerContext) LogManager.getContext();
+        ctx.reconfigure();
+        StatusLogger.getLogger().reset();
+    }
+
+    @Test
+    public void testLogger() {
+        Logger logger = LogManager.getLogger("org.apache.logging.log4j.test1.Test");
+        assertTrue(logger instanceof org.apache.logging.log4j.core.Logger);
+        org.apache.logging.log4j.core.Logger l = (org.apache.logging.log4j.core.Logger) logger;
+        assertTrue(l.getLevel().equals(Level.DEBUG));
+        List<Filter> filters = l.getFilters();
+        assertTrue("number of filters - " + filters.size(), filters.size() == 1);
+        Filter filter = filters.get(0);
+        assertTrue(filter instanceof MDCFilter);
+        Map<String, Appender> appenders = l.getAppenders();
+        assertNotNull(appenders);
+        assertTrue("number of appenders = " + appenders.size(), appenders.size() == 1);
+        Appender a = appenders.get("STDOUT");
+        assertNotNull(a);
+        assertEquals(a.getName(), "STDOUT");
+    }
+
+    @Test
+    public void logToFile() {
+        Logger logger = LogManager.getLogger("org.apache.logging.log4j.test2.Test");
+        logger.debug("This is a test");
+    }
+
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
new file mode 100644
index 0000000..e98e3db
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.layout;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.MDC;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.BasicConfigurationFactory;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.util.Compare;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.FileOutputStream;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ *
+ */
+public class PatternLayoutTest {
+    static String OUTPUT_FILE   = "output/PatternParser";
+    static String WITNESS_FILE  = "witness/PatternParser";
+    LoggerContext ctx = (LoggerContext) LogManager.getContext();
+    Logger root = ctx.getLogger("");
+
+    static String msgPattern = "%m%n";
+    static ConfigurationFactory cf = new BasicConfigurationFactory();
+
+    @BeforeClass
+    public static void setupClass() {
+        ConfigurationFactory.setConfigurationFactory(cf);
+        LoggerContext ctx = (LoggerContext) LogManager.getContext();
+        ctx.reconfigure();
+    }
+
+    @AfterClass
+    public static void cleanupClass() {
+        ConfigurationFactory.removeConfigurationFactory(cf);
+    }
+
+
+    /**
+     * Test case for MDC conversion pattern.
+     */
+    @Test
+    public void mdcPattern() throws Exception {
+
+        String mdcMsgPattern1 = "%m : %X%n";
+        String mdcMsgPattern2 = "%m : %X{key1}%n";
+        String mdcMsgPattern3 = "%m : %X{key2}%n";
+        String mdcMsgPattern4 = "%m : %X{key3}%n";
+        String mdcMsgPattern5 = "%m : %X{key1},%X{key2},%X{key3}%n";
+
+        // set up appender
+        PatternLayout layout = new PatternLayout(msgPattern);
+        FileOutputStream fos = new FileOutputStream(OUTPUT_FILE + "_mdc");
+        Appender appender = new FileAppender("File", layout, fos, OUTPUT_FILE + "_mdc");
+        appender.start();
+
+        // set appender on root and set level to debug
+        root.addAppender(appender);
+        root.setLevel(Level.DEBUG);
+
+        // output starting message
+        root.debug("starting mdc pattern test");
+
+        layout.setConversionPattern(mdcMsgPattern1);
+        root.debug("empty mdc, no key specified in pattern");
+
+        layout.setConversionPattern(mdcMsgPattern2);
+        root.debug("empty mdc, key1 in pattern");
+
+        layout.setConversionPattern(mdcMsgPattern3);
+        root.debug("empty mdc, key2 in pattern");
+
+        layout.setConversionPattern(mdcMsgPattern4);
+        root.debug("empty mdc, key3 in pattern");
+
+        layout.setConversionPattern(mdcMsgPattern5);
+        root.debug("empty mdc, key1, key2, and key3 in pattern");
+
+        MDC.put("key1", "value1");
+        MDC.put("key2", "value2");
+
+        layout.setConversionPattern(mdcMsgPattern1);
+        root.debug("filled mdc, no key specified in pattern");
+
+        layout.setConversionPattern(mdcMsgPattern2);
+        root.debug("filled mdc, key1 in pattern");
+
+        layout.setConversionPattern(mdcMsgPattern3);
+        root.debug("filled mdc, key2 in pattern");
+
+        layout.setConversionPattern(mdcMsgPattern4);
+        root.debug("filled mdc, key3 in pattern");
+
+        layout.setConversionPattern(mdcMsgPattern5);
+        root.debug("filled mdc, key1, key2, and key3 in pattern");
+
+        MDC.remove("key1");
+        MDC.remove("key2");
+
+        layout.setConversionPattern(msgPattern);
+        root.debug("finished mdc pattern test");
+
+        assertTrue(Compare.compare(this.getClass(), OUTPUT_FILE + "_mdc", WITNESS_FILE + "_mdc"));
+    }
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/layout/pattern/PatternParserTest.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/layout/pattern/PatternParserTest.java
new file mode 100644
index 0000000..7cc961a
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/layout/pattern/PatternParserTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.layout.pattern;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.MDC;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.util.Compare;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.Assert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileOutputStream;
+import java.util.List;
+
+/**
+ *
+ */
+public class PatternParserTest {
+
+    static String OUTPUT_FILE   = "output/PatternParser";
+    static String WITNESS_FILE  = "witness/PatternParser";
+    LoggerContext ctx = (LoggerContext) LogManager.getContext();
+    Logger root = ctx.getLogger("");
+
+    private static String msgPattern = "%m%n";
+    private String mdcMsgPattern1 = "%m : %X%n";
+    private String mdcMsgPattern2 = "%m : %X{key1}%n";
+    private String mdcMsgPattern3 = "%m : %X{key2}%n";
+    private String mdcMsgPattern4 = "%m : %X{key3}%n";
+    private String mdcMsgPattern5 = "%m : %X{key1},%X{key2},%X{key3}%n";
+
+
+    private static final String KEY = "Converter";
+    private PatternParser parser;
+
+    @Before
+    public void setup() {
+        parser = new PatternParser(KEY);
+    }
+
+    private void validateConverter(List<PatternConverter> converters, int index, String name) {
+        PatternConverter pc = converters.get(index);
+        assertEquals("Incorrect converter " + pc.getName() + " at index " + index + " expected " + name,
+            pc.getName(), name);
+    }
+
+    /**
+     * Test the default pattern
+     */
+    @Test
+    public void defaultPattern() {
+        List<PatternConverter> converters = parser.parse(msgPattern);
+        assertNotNull(converters);
+        assertTrue(converters.size() == 2);
+        validateConverter(converters, 0, "Message");
+        validateConverter(converters, 1, "Line Sep");
+    }
+
+
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/AbsoluteDateAndTimeFilter.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/AbsoluteDateAndTimeFilter.java
new file mode 100644
index 0000000..b27bf42
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/AbsoluteDateAndTimeFilter.java
@@ -0,0 +1,36 @@
+/*
+ * 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.util;
+
+import org.apache.oro.text.perl.Perl5Util;
+
+
+public class AbsoluteDateAndTimeFilter implements Filter {
+  Perl5Util util = new Perl5Util();
+
+  public String filter(String in) {
+    String pat = "/" + Filter.ABSOLUTE_DATE_AND_TIME_PAT + "/";
+
+    if (util.match(pat, in)) {
+      return util.substitute(
+        "s/" + Filter.ABSOLUTE_DATE_AND_TIME_PAT + "//", in);
+    } else {
+      return in;
+    }
+  } 
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/AbsoluteTimeFilter.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/AbsoluteTimeFilter.java
new file mode 100644
index 0000000..03e446e
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/AbsoluteTimeFilter.java
@@ -0,0 +1,34 @@
+/*
+ * 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.util;
+
+import org.apache.oro.text.perl.Perl5Util;
+
+public class AbsoluteTimeFilter implements Filter {
+  Perl5Util util = new Perl5Util();
+
+  public String filter(String in) {
+    String pat = "/" + Filter.ABSOLUTE_TIME_PAT + "/";
+
+    if (util.match(pat, in)) {
+      return util.substitute("s/" + Filter.ABSOLUTE_TIME_PAT + "//", in);
+    } else {
+      return in;
+    }
+  }
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/Compare.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/Compare.java
new file mode 100644
index 0000000..b6423cb
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/Compare.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.util;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.*;
+import java.net.URL;
+
+
+public class Compare {
+    static final int B1_NULL = -1;
+    static final int B2_NULL = -2;
+
+    private static final InputStream open(
+        final Class testClass,
+        final String fileName) throws IOException {
+        String resourceName = fileName;
+        /* if (fileName.startsWith("witness/")) {
+           resourceName = fileName.substring(fileName.lastIndexOf('/') + 1);
+       } */
+        InputStream is = testClass.getResourceAsStream(resourceName);
+        if (is == null) {
+            is = testClass.getClassLoader().getResourceAsStream(resourceName);
+        }
+        if (is == null) {
+            File file = new File(fileName);
+            if (file.exists()) {
+                is = new FileInputStream(file);
+            } else {
+                throw new FileNotFoundException("Resource "
+                    + resourceName + " not found");
+            }
+        }
+        return is;
+    }
+
+    public static boolean compare(Class testClass,
+                                  final String file1,
+                                  final String file2)
+        throws IOException {
+        BufferedReader in1 = new BufferedReader(new FileReader(file1));
+        BufferedReader in2 = new BufferedReader(new InputStreamReader(
+            open(testClass, file2)));
+        try {
+            return compare(testClass, file1, file2, in1, in2);
+        } finally {
+            in1.close();
+            in2.close();
+        }
+    }
+
+    public static boolean compare(
+        Class testClass, String file1, String file2, BufferedReader in1, BufferedReader in2) throws IOException {
+
+        String s1;
+        int lineCounter = 0;
+
+        while ((s1 = in1.readLine()) != null) {
+            lineCounter++;
+
+            String s2 = in2.readLine();
+
+            if (!s1.equals(s2)) {
+                System.out.println(
+                    "Files [" + file1 + "] and [" + file2 + "] differ on line "
+                        + lineCounter);
+                System.out.println("One reads:  [" + s1 + "].");
+                System.out.println("Other reads:[" + s2 + "].");
+                outputFile(testClass, file1);
+                outputFile(testClass, file2);
+
+                return false;
+            }
+        }
+
+        // the second file is longer
+        if (in2.read() != -1) {
+            System.out.println(
+                "File [" + file2 + "] longer than file [" + file1 + "].");
+            outputFile(testClass, file1);
+            outputFile(testClass, file2);
+
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Prints file on the console.
+     */
+    private static void outputFile(Class testClass, String file)
+        throws IOException {
+        InputStream is = open(testClass, file);
+        BufferedReader in1 = new BufferedReader(new InputStreamReader(is));
+
+        String s1;
+        int lineCounter = 0;
+        System.out.println("--------------------------------");
+        System.out.println("Contents of " + file + ":");
+
+        while ((s1 = in1.readLine()) != null) {
+            lineCounter++;
+            System.out.print(lineCounter);
+
+            if (lineCounter < 10) {
+                System.out.print("   : ");
+            } else if (lineCounter < 100) {
+                System.out.print("  : ");
+            } else if (lineCounter < 1000) {
+                System.out.print(" : ");
+            } else {
+                System.out.print(": ");
+            }
+
+            System.out.println(s1);
+        }
+        in1.close();
+    }
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/ControlFilter.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/ControlFilter.java
new file mode 100644
index 0000000..9a09fc3
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/ControlFilter.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util;
+
+import org.apache.oro.text.perl.Perl5Util;
+
+
+public class ControlFilter implements Filter {
+  Perl5Util util = new Perl5Util();
+  String[] allowedPatterns;
+
+  public ControlFilter(String[] allowedPatterns) {
+    this.allowedPatterns = allowedPatterns;
+  }
+
+  public String filter(String in) throws UnexpectedFormatException {
+    int len = allowedPatterns.length;
+
+    for (int i = 0; i < len; i++) {
+      //System.out.println("["+allowedPatterns[i]+"]");
+      if (util.match("/" + allowedPatterns[i] + "/", in)) {
+        //System.out.println("["+in+"] matched ["+allowedPatterns[i]);
+        return in;
+      }
+    }
+
+    throw new UnexpectedFormatException("[" + in + "]");
+  }
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/Filter.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/Filter.java
new file mode 100644
index 0000000..91d8cc1
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/Filter.java
@@ -0,0 +1,40 @@
+/*
+ * 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.util;
+
+public interface Filter {
+  // 06 avr. 2002 18:36:32,036
+  // 18 fevr. 2002 20:05:36,222
+  public static final String ABSOLUTE_DATE_AND_TIME_PAT =
+    "^\\d{1,2} .{2,6}\\.? 200\\d \\d{2}:\\d{2}:\\d{2},\\d{3}";
+
+  // 18:54:19,201
+  public static final String ABSOLUTE_TIME_PAT =
+    "^\\d{2}:\\d{2}:\\d{2},\\d{3}";
+  public static final String RELATIVE_TIME_PAT = "^\\d{1,10}";
+  final String BASIC_PAT = "\\[main\\] (FATAL|ERROR|WARN|INFO|DEBUG)";
+  final String ISO8601_PAT =
+    "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2},\\d{3}";
+
+  /**
+   * This filter transforms the input string and returns the results as
+   * output. If the input should be ignored, this method returns null.
+   *
+   */
+  String filter(String in) throws UnexpectedFormatException;
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/ISO8601Filter.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/ISO8601Filter.java
new file mode 100644
index 0000000..3896f13
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/ISO8601Filter.java
@@ -0,0 +1,35 @@
+/*
+ * 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.util;
+
+import org.apache.oro.text.perl.Perl5Util;
+
+
+public class ISO8601Filter implements Filter {
+  Perl5Util util = new Perl5Util();
+
+  public String filter(String in) {
+    String pat = "/" + ISO8601_PAT + "/";
+
+    if (util.match(pat, in)) {
+      return util.substitute("s/" + ISO8601_PAT + "//", in);
+    } else {
+      return in;
+    }
+  }
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/JunitTestRunnerFilter.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/JunitTestRunnerFilter.java
new file mode 100644
index 0000000..47f653d
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/JunitTestRunnerFilter.java
@@ -0,0 +1,57 @@
+/*
+ * 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.util;
+
+import org.apache.oro.text.perl.Perl5Util;
+
+
+public class JunitTestRunnerFilter implements Filter {
+  Perl5Util util = new Perl5Util();
+
+  private static final String[] patterns = {
+          "/at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner/",
+          "/at org.apache.tools.ant/",
+          "/at junit.textui.TestRunner/",
+          "/at com.intellij.rt.execution.junit/",
+          "/at java.lang.reflect.Method.invoke/",
+          "/at org.apache.maven.surefire./"
+  };
+
+  /**
+   * Filter out stack trace lines coming from the various JUnit TestRunners.
+   */
+  public String filter(String in) {
+    if (in == null) {
+      return null;
+    }
+
+      //
+      //  restore the one instance of Method.invoke that we actually want
+      //
+    if (util.match("/at junit.framework.TestCase.runTest/", in)) {
+        return "\tat java.lang.reflect.Method.invoke(X)\n" + in;
+    }
+
+    for (int i = 0; i < patterns.length; i++) {
+        if(util.match(patterns[i], in)) {
+            return null;
+        }
+    }
+    return in;
+  }
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/LineNumberFilter.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/LineNumberFilter.java
new file mode 100644
index 0000000..3632265
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/LineNumberFilter.java
@@ -0,0 +1,35 @@
+/*
+ * 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.util;
+
+import org.apache.oro.text.perl.Perl5Util;
+
+
+public class LineNumberFilter implements Filter {
+  Perl5Util util = new Perl5Util();
+
+  public String filter(String in) {
+    if (util.match("/\\(.*:\\d{1,4}\\)/", in)) {
+      return util.substitute("s/\\(.*:\\d{1,4}\\)/\\(X\\)/", in);
+    } else if (util.match("/\\(Native Method\\)/", in)) {
+      return util.substitute("s/\\(Native Method\\)/\\(X\\)/", in);
+    } else {
+      return in;
+    }
+  }
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/MDCOrderFilter.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/MDCOrderFilter.java
new file mode 100644
index 0000000..87339a5
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/MDCOrderFilter.java
@@ -0,0 +1,63 @@
+/*
+ * 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.util;
+
+/**
+ * This class switches MDC values into the order
+ * (unreasonably) expected by the witness files.
+ */
+public class MDCOrderFilter implements Filter {
+
+    /**
+     * Unexpected orders of keys.
+     * Note expected values are "va-one-one" and "va-one-two".
+     */
+  private static final String[] patterns =
+          new String[] {
+                  "{key2,va12}{key1,va11}",
+                  "{key2,value2}{key1,value1}"
+          };
+
+    /**
+     * Replacement values.
+     */
+  private static final String[] replacements =
+            new String[] {
+                    "{key1,va11}{key2,va12}",
+                    "{key1,value1}{key2,value2}"
+            };
+
+  /**
+   *  Switch order of MDC keys when not in expected order.
+   */
+  public String filter(final String in) {
+    if (in == null) {
+      return null;
+    }
+
+    for(int i = 0; i < patterns.length; i++) {
+        int ipos = in.indexOf(patterns[i]);
+        if (ipos >= 1) {
+            return in.substring(0, ipos)
+                    + replacements[i]
+                    + in.substring(ipos + patterns[i].length());
+        }
+    }
+    return in;
+  }
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/RelativeTimeFilter.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/RelativeTimeFilter.java
new file mode 100644
index 0000000..4fb235c
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/RelativeTimeFilter.java
@@ -0,0 +1,36 @@
+/*
+ * 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.util;
+
+import org.apache.oro.text.perl.Perl5Util;
+
+
+public class RelativeTimeFilter implements Filter {
+  Perl5Util util = new Perl5Util();
+
+  public String filter(String in) {
+    String pat = "/" + Filter.RELATIVE_TIME_PAT + "/";
+
+    if (util.match(pat, in)) {
+      //System.out.println("Removing relative time from line ["+in+"]");
+      return util.substitute("s/" + Filter.RELATIVE_TIME_PAT + "//", in);
+    } else {
+      return in;
+    }
+  }
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/SunReflectFilter.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/SunReflectFilter.java
new file mode 100644
index 0000000..a32fb60
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/SunReflectFilter.java
@@ -0,0 +1,40 @@
+/*
+ * 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.util;
+
+import org.apache.oro.text.perl.Perl5Util;
+
+/**
+ * The sun.reflect.* lines are not present in all JDKs.
+ *
+ * @author Ceki Gulcu
+ */
+public class SunReflectFilter implements Filter {
+  Perl5Util util = new Perl5Util();
+
+  public String filter(String in) {
+    if(in == null) {
+      return null;
+    }
+    if (util.match("/at sun.reflect/", in)) {
+      return null;
+    } else {
+      return in;
+    }
+  }
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/Transformer.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/Transformer.java
new file mode 100644
index 0000000..380bf9a
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/Transformer.java
@@ -0,0 +1,80 @@
+/*
+ * 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.util;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintStream;
+
+public class Transformer {
+
+  public
+  static
+  void transform(String in, String out, Filter[] filters) throws FileNotFoundException,
+                                                                 IOException,
+                                                                 UnexpectedFormatException {
+
+    String line;
+    BufferedReader input = new BufferedReader(new FileReader(in));
+    PrintStream output = new PrintStream(new FileOutputStream(out, false));
+
+    try {
+      // Initialization of input and output omitted
+      while ((line = input.readLine()) != null) {
+        // apply all filters
+        for (int i = 0; i < filters.length; i++) {
+          line = filters[i].filter(line);
+        }
+        if (line != null) {
+          output.println(line);
+        }
+      }
+    } finally {
+      input.close();
+      output.close();
+    }
+  }
+
+
+
+  public
+  static
+  void transform(String in, String out, Filter filter) throws FileNotFoundException,
+                                                              IOException,
+                                                              UnexpectedFormatException {
+
+    String line;
+    BufferedReader input = new BufferedReader(new FileReader(in));
+    PrintStream output = new PrintStream(new FileOutputStream(out));
+
+    try {
+      // Initialization of input and output omitted
+      while((line = input.readLine()) != null) {
+        line = filter.filter(line);
+        output.println(line);
+      }
+    } finally {
+      input.close();
+      output.close();
+    }
+  }
+
+}
diff --git a/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/UnexpectedFormatException.java b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/UnexpectedFormatException.java
new file mode 100644
index 0000000..b65cef4
--- /dev/null
+++ b/log4j2-core/src/test/java/org/apache/logging/log4j/core/util/UnexpectedFormatException.java
@@ -0,0 +1,25 @@
+/*
+ * 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.util;
+
+public class UnexpectedFormatException extends Exception {
+
+  public UnexpectedFormatException(String msg) {
+    super(msg);
+  }
+}
diff --git a/log4j2-core/src/test/resources/log4j-test1.xml b/log4j2-core/src/test/resources/log4j-test1.xml
new file mode 100644
index 0000000..eaf5d25
--- /dev/null
+++ b/log4j2-core/src/test/resources/log4j-test1.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration packages="" debug="true" name="XMLConfigTest">
+  <filters>
+    <Threshold level="debug"/>
+  </filters>
+
+  <appenders>
+    <Console name="STDOUT">
+      <PatternLayout>
+        <pattern>%m%n</pattern>
+      </PatternLayout>
+    </Console>
+    <File name="File" fileName="target/test.log">
+      <PatternLayout>
+        <pattern>%d %p %C{1.} [%t] %m%n</pattern>
+      </PatternLayout>
+    </File>
+  </appenders>
+
+  <loggers>
+    <logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
+      <filters>
+        <MDC key="test" value="123"/>
+      </filters>
+      <appender-ref ref="STDOUT"/>
+    </logger>>
+
+    <logger name="org.apache.logging.log4j.test2" level="debug" additivity="false">
+      <appender-ref ref="File"/>
+    </logger>>
+
+    <root level="error">
+      <appender-ref ref="STDOUT"/>
+    </root>
+  </loggers>
+
+</configuration>
\ No newline at end of file
diff --git a/log4j2-core/src/test/resources/witness/PatternParser_mdc b/log4j2-core/src/test/resources/witness/PatternParser_mdc
new file mode 100644
index 0000000..5c64114
--- /dev/null
+++ b/log4j2-core/src/test/resources/witness/PatternParser_mdc
@@ -0,0 +1,12 @@
+starting mdc pattern test
+empty mdc, no key specified in pattern : {}
+empty mdc, key1 in pattern : 
+empty mdc, key2 in pattern : 
+empty mdc, key3 in pattern : 
+empty mdc, key1, key2, and key3 in pattern : ,,
+filled mdc, no key specified in pattern : {key1=value1, key2=value2}
+filled mdc, key1 in pattern : value1
+filled mdc, key2 in pattern : value2
+filled mdc, key3 in pattern : 
+filled mdc, key1, key2, and key3 in pattern : value1,value2,
+finished mdc pattern test
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..9a3e4f1
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,164 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.logging</groupId>
+  <artifactId>log4j2</artifactId>
+  <packaging>pom</packaging>
+  <name>Apache Log4j 2</name>
+  <version>1.99.0-SNAPSHOT</version>
+  <description>Apache Log4j 2</description>
+  <url>http://logging.apache.org/log4j/2.0/</url>
+  <issueManagement>
+    <system>Jira</system>
+    <url>http://issues.apache.org/jira/browse/LOG4J2</url>
+  </issueManagement>
+  <ciManagement>
+    <system>Gump</system>
+    <url>http://vmgump.apache.org/gump/public/logging-log4j-20/logging-log4j-20/index.html</url>
+  </ciManagement>
+  <inceptionYear>1999</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>log4j-user</name>
+      <subscribe>log4j-user-subscribe@logging.apache.org</subscribe>
+      <unsubscribe>log4j-user-unsubscribe@logging.apache.org</unsubscribe>
+      <post>log4j-user@logging.apache.org</post>
+      <archive>http://mail-archives.apache.org/mod_mbox/logging-log4j-dev/</archive>
+      <otherArchives>
+        <otherArchive>http://marc.info/?l=log4j-user</otherArchive>
+        <otherArchive>http://dir.gmane.org/gmane.comp.jakarta.log4j.user</otherArchive>
+      </otherArchives>
+    </mailingList>
+    <mailingList>
+      <name>log4j-dev</name>
+      <subscribe>log4j-dev-subscribe@logging.apache.org</subscribe>
+      <unsubscribe>log4j-dev-unsubscribe@logging.apache.org</unsubscribe>
+      <post>log4j-dev@logging.apache.org</post>
+      <archive>http://mail-archives.apache.org/mod_mbox/logging-log4j-dev/</archive>
+      <otherArchives>
+        <otherArchive>http://marc.info/?l=log4j-dev</otherArchive>
+        <otherArchive>http://dir.gmane.org/gmane.comp.jakarta.log4j.devel</otherArchive>
+      </otherArchives>
+    </mailingList>
+  </mailingLists>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL
+    </developerConnection>
+    <url>http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL</url>
+  </scm>
+  <organization>
+    <name>Apache Software Foundation</name>
+    <url>http://www.apache.org</url>
+  </organization>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <dependencies>
+          <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.14</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.5</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>cobertura-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>clean</id>
+            <goals>
+              <goal>clean</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <reporting>
+    <plugins>
+      <plugin>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-project-info-reports-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>jxr-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>cobertura-maven-plugin</artifactId>
+        <!-- version 2.1 was flawed and reports 100% coverage  -->
+        <version>2.0</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-changes-plugin</artifactId>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>changes-report</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+        <configuration>
+          <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+  <distributionManagement>
+    <site>
+      <id>apache.website</id>
+      <url>scp://people.apache.org/home/carnold/public_html/log4j/companions/pattern-layout</url>
+    </site>
+  </distributionManagement>
+  <modules>
+    <module>log4j2-api</module>
+    <module>log4j12-api</module>
+    <module>log4j2-core</module>
+    <module>log4j2-doc</module>
+  </modules>
+</project>