You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2022/04/11 22:00:50 UTC

[logging-log4j2] branch slf4j-2.0 created (now 8dcdb7c7d9)

This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a change to branch slf4j-2.0
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


      at 8dcdb7c7d9 [LOG4J2-3370] Initial SLF4J 2.0.x support

This branch includes the following new commits:

     new 8dcdb7c7d9 [LOG4J2-3370] Initial SLF4J 2.0.x support

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[logging-log4j2] 01/01: [LOG4J2-3370] Initial SLF4J 2.0.x support

Posted by pk...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch slf4j-2.0
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 8dcdb7c7d9c38ab80c2d6957cf52ab2cefc48e2a
Author: Piotr P. Karwasz <pi...@karwasz.org>
AuthorDate: Mon Apr 11 23:59:26 2022 +0200

    [LOG4J2-3370] Initial SLF4J 2.0.x support
---
 log4j-slf4j20-impl/pom.xml                         | 255 +++++++++++++
 .../java/org/apache/logging/slf4j/Log4jLogger.java | 420 +++++++++++++++++++++
 .../apache/logging/slf4j/Log4jLoggerFactory.java   |  75 ++++
 .../org/apache/logging/slf4j/Log4jMDCAdapter.java  |  60 +++
 .../java/org/apache/logging/slf4j/Log4jMarker.java | 126 +++++++
 .../apache/logging/slf4j/Log4jMarkerFactory.java   | 138 +++++++
 .../logging/slf4j/SLF4JLoggingException.java       |  41 ++
 .../apache/logging/slf4j/SLF4JServiceProvider.java |  59 +++
 .../org/apache/logging/slf4j/package-info.java     |  22 ++
 .../services/org.slf4j.spi.SLF4JServiceProvider    |   1 +
 log4j-slf4j20-impl/src/site/markdown/index.md      |  40 ++
 log4j-slf4j20-impl/src/site/site.xml               |  52 +++
 .../logging/other/pkg/LoggerContextAnchorTest.java |  91 +++++
 .../logging/slf4j/CallerInformationTest.java       |  67 ++++
 .../org/apache/logging/slf4j/CustomFlatMarker.java |  76 ++++
 .../org/apache/logging/slf4j/Log4j1222Test.java    |  57 +++
 .../logging/slf4j/Log4j2_1482_Slf4jTest.java       |  41 ++
 .../org/apache/logging/slf4j/Log4jMarkerTest.java  |  47 +++
 .../apache/logging/slf4j/LoggerContextTest.java    |  44 +++
 .../java/org/apache/logging/slf4j/LoggerTest.java  | 161 ++++++++
 .../java/org/apache/logging/slf4j/MarkerTest.java  | 186 +++++++++
 .../org/apache/logging/slf4j/OverflowTest.java     |  43 +++
 .../org/apache/logging/slf4j/SerializeTest.java    |  46 +++
 .../src/test/resources/log4j-test1.xml             |  33 ++
 .../src/test/resources/log4j2-1482.xml             |  27 ++
 pom.xml                                            |   1 +
 26 files changed, 2209 insertions(+)

diff --git a/log4j-slf4j20-impl/pom.xml b/log4j-slf4j20-impl/pom.xml
new file mode 100644
index 0000000000..8d516fdc1b
--- /dev/null
+++ b/log4j-slf4j20-impl/pom.xml
@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.logging.log4j</groupId>
+    <artifactId>log4j</artifactId>
+    <version>2.17.3-SNAPSHOT</version>
+  </parent>
+  <artifactId>log4j-slf4j20-impl</artifactId>
+  <packaging>jar</packaging>
+  <name>Apache Log4j SLF4J 2.0+ Binding</name>
+  <description>The Apache Log4j SLF4J 2.0 API binding to Log4j 2 Core</description>
+  <properties>
+    <log4jParentDir>${basedir}/..</log4jParentDir>
+    <docLabel>SLF4J Documentation</docLabel>
+    <projectDir>/slf4j18</projectDir>
+    <slf4j.version>2.0.0-alpha5</slf4j.version>
+    <module.name>org.apache.logging.log4j.slf4j</module.name>
+    <maven.doap.skip>true</maven.doap.skip>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>${slf4j.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-ext</artifactId>
+      <version>${slf4j.version}</version>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-csv</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-to-slf4j</artifactId>
+      <scope>test</scope>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.junit.vintage</groupId>
+      <artifactId>junit-vintage-engine</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-engine</artifactId>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <!-- Include the standard NOTICE and LICENSE -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>process</goal>
+            </goals>
+            <configuration>
+              <skip>false</skip>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>loop-test</id>
+            <phase>test</phase>
+            <goals>
+              <goal>test</goal>
+            </goals>
+            <configuration>
+              <includes>
+                <include>**/OverflowTest.java</include>
+              </includes>
+            </configuration>
+          </execution>
+          <execution>
+            <id>default-test</id>
+            <phase>test</phase>
+            <goals>
+              <goal>test</goal>
+            </goals>
+            <configuration>
+              <includes>
+                <include>**/*Test.java</include>
+              </includes>
+              <excludes>
+                <exclude>**/OverflowTest.java</exclude>
+              </excludes>
+              <classpathDependencyExcludes>
+                <classpathDependencyExcludes>org.apache.logging.log4j:log4j-to-slf4j</classpathDependencyExcludes>
+              </classpathDependencyExcludes>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.apache.logging.slf4j,
+              org.slf4j.impl
+            </Export-Package>
+            <Require-Capability>
+              osgi.extender;filter:="(osgi.extender=osgi.serviceloader.registrar)"
+            </Require-Capability>
+            <Provide-Capability>
+              osgi.serviceloader;osgi.serviceloader=org.slf4j.spi.SLF4JServiceProvider
+            </Provide-Capability>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-changes-plugin</artifactId>
+        <version>${changes.plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>changes-report</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+        <configuration>
+          <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
+          <useJql>true</useJql>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${checkstyle.plugin.version}</version>
+        <configuration>
+          <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation> -->
+          <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
+          <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
+          <enableRulesSummary>false</enableRulesSummary>
+          <propertyExpansion>basedir=${basedir}</propertyExpansion>
+          <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>${javadoc.plugin.version}</version>
+        <configuration>
+          <bottom><![CDATA[<p align="center">Copyright &#169; {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
+            Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo,
+            and the Apache Log4j logo are trademarks of The Apache Software Foundation.</p>]]></bottom>
+          <!-- module link generation is completely broken in the javadoc plugin for a multi-module non-aggregating
+               project -->
+          <detectOfflineLinks>false</detectOfflineLinks>
+          <linksource>true</linksource>
+        </configuration>
+        <reportSets>
+          <reportSet>
+            <id>non-aggregate</id>
+            <reports>
+              <report>javadoc</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>com.github.spotbugs</groupId>
+        <artifactId>spotbugs-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jxr-plugin</artifactId>
+        <version>${jxr.plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <id>non-aggregate</id>
+            <reports>
+              <report>jxr</report>
+            </reports>
+          </reportSet>
+          <reportSet>
+            <id>aggregate</id>
+            <reports>
+              <report>aggregate</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+        <version>${pmd.plugin.version}</version>
+        <configuration>
+          <targetJdk>${maven.compiler.target}</targetJdk>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>
+
diff --git a/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java
new file mode 100644
index 0000000000..10ad49ca7e
--- /dev/null
+++ b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java
@@ -0,0 +1,420 @@
+/*
+ * 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.slf4j;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.ParameterizedMessage;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.spi.ExtendedLogger;
+import org.slf4j.Marker;
+import org.slf4j.spi.LocationAwareLogger;
+
+/**
+ * SLF4J logger implementation that uses Log4j.
+ */
+public class Log4jLogger implements LocationAwareLogger, Serializable {
+
+    public static final String FQCN = Log4jLogger.class.getName();
+
+    private static final long serialVersionUID = 7869000638091304316L;
+    private transient ExtendedLogger logger;
+    private final String name;
+    private transient Log4jMarkerFactory markerFactory;
+
+    public Log4jLogger(final Log4jMarkerFactory markerFactory, final ExtendedLogger logger, final String name) {
+        this.markerFactory = markerFactory;
+        this.logger = logger;
+        this.name = name;
+    }
+
+    @Override
+    public void trace(final String format) {
+        logger.logIfEnabled(FQCN, Level.TRACE, null, format);
+    }
+
+    @Override
+    public void trace(final String format, final Object o) {
+        logger.logIfEnabled(FQCN, Level.TRACE, null, format, o);
+    }
+
+    @Override
+    public void trace(final String format, final Object arg1, final Object arg2) {
+        logger.logIfEnabled(FQCN, Level.TRACE, null, format, arg1, arg2);
+    }
+
+    @Override
+    public void trace(final String format, final Object... args) {
+        logger.logIfEnabled(FQCN, Level.TRACE, null, format, args);
+    }
+
+    @Override
+    public void trace(final String format, final Throwable t) {
+        logger.logIfEnabled(FQCN, Level.TRACE, null, format, t);
+    }
+
+    @Override
+    public boolean isTraceEnabled() {
+        return logger.isEnabled(Level.TRACE, null, null);
+    }
+
+    @Override
+    public boolean isTraceEnabled(final Marker marker) {
+        return logger.isEnabled(Level.TRACE, getMarker(marker), null);
+    }
+
+    @Override
+    public void trace(final Marker marker, final String s) {
+        logger.logIfEnabled(FQCN, Level.TRACE, getMarker(marker), s);
+    }
+
+    @Override
+    public void trace(final Marker marker, final String s, final Object o) {
+        logger.logIfEnabled(FQCN, Level.TRACE, getMarker(marker), s, o);
+    }
+
+    @Override
+    public void trace(final Marker marker, final String s, final Object o, final Object o1) {
+        logger.logIfEnabled(FQCN, Level.TRACE, getMarker(marker), s, o, o1);
+    }
+
+    @Override
+    public void trace(final Marker marker, final String s, final Object... objects) {
+        logger.logIfEnabled(FQCN, Level.TRACE, getMarker(marker), s, objects);
+    }
+
+    @Override
+    public void trace(final Marker marker, final String s, final Throwable throwable) {
+        logger.logIfEnabled(FQCN, Level.TRACE, getMarker(marker), s, throwable);
+    }
+
+    @Override
+    public void debug(final String format) {
+        logger.logIfEnabled(FQCN, Level.DEBUG, null, format);
+    }
+
+    @Override
+    public void debug(final String format, final Object o) {
+        logger.logIfEnabled(FQCN, Level.DEBUG, null, format, o);
+    }
+
+    @Override
+    public void debug(final String format, final Object arg1, final Object arg2) {
+        logger.logIfEnabled(FQCN, Level.DEBUG, null, format, arg1, arg2);
+    }
+
+    @Override
+    public void debug(final String format, final Object... args) {
+        logger.logIfEnabled(FQCN, Level.DEBUG, null, format, args);
+    }
+
+    @Override
+    public void debug(final String format, final Throwable t) {
+        logger.logIfEnabled(FQCN, Level.DEBUG, null, format, t);
+    }
+
+    @Override
+    public boolean isDebugEnabled() {
+        return logger.isEnabled(Level.DEBUG, null, null);
+    }
+
+    @Override
+    public boolean isDebugEnabled(final Marker marker) {
+        return logger.isEnabled(Level.DEBUG, getMarker(marker), null);
+    }
+
+    @Override
+    public void debug(final Marker marker, final String s) {
+        logger.logIfEnabled(FQCN, Level.DEBUG, getMarker(marker), s);
+    }
+
+    @Override
+    public void debug(final Marker marker, final String s, final Object o) {
+        logger.logIfEnabled(FQCN, Level.DEBUG, getMarker(marker), s, o);
+    }
+
+    @Override
+    public void debug(final Marker marker, final String s, final Object o, final Object o1) {
+        logger.logIfEnabled(FQCN, Level.DEBUG, getMarker(marker), s, o, o1);
+    }
+
+    @Override
+    public void debug(final Marker marker, final String s, final Object... objects) {
+        logger.logIfEnabled(FQCN, Level.DEBUG, getMarker(marker), s, objects);
+    }
+
+    @Override
+    public void debug(final Marker marker, final String s, final Throwable throwable) {
+        logger.logIfEnabled(FQCN, Level.DEBUG, getMarker(marker), s, throwable);
+    }
+
+    @Override
+    public void info(final String format) {
+        logger.logIfEnabled(FQCN, Level.INFO, null, format);
+    }
+
+    @Override
+    public void info(final String format, final Object o) {
+        logger.logIfEnabled(FQCN, Level.INFO, null, format, o);
+    }
+
+    @Override
+    public void info(final String format, final Object arg1, final Object arg2) {
+        logger.logIfEnabled(FQCN, Level.INFO, null, format, arg1, arg2);
+    }
+
+    @Override
+    public void info(final String format, final Object... args) {
+        logger.logIfEnabled(FQCN, Level.INFO, null, format, args);
+    }
+
+    @Override
+    public void info(final String format, final Throwable t) {
+        logger.logIfEnabled(FQCN, Level.INFO, null, format, t);
+    }
+
+    @Override
+    public boolean isInfoEnabled() {
+        return logger.isEnabled(Level.INFO, null, null);
+    }
+
+    @Override
+    public boolean isInfoEnabled(final Marker marker) {
+        return logger.isEnabled(Level.INFO, getMarker(marker), null);
+    }
+
+    @Override
+    public void info(final Marker marker, final String s) {
+        logger.logIfEnabled(FQCN, Level.INFO, getMarker(marker), s);
+    }
+
+    @Override
+    public void info(final Marker marker, final String s, final Object o) {
+        logger.logIfEnabled(FQCN, Level.INFO, getMarker(marker), s, o);
+    }
+
+    @Override
+    public void info(final Marker marker, final String s, final Object o, final Object o1) {
+        logger.logIfEnabled(FQCN, Level.INFO, getMarker(marker), s, o, o1);
+    }
+
+    @Override
+    public void info(final Marker marker, final String s, final Object... objects) {
+        logger.logIfEnabled(FQCN, Level.INFO, getMarker(marker), s, objects);
+    }
+
+    @Override
+    public void info(final Marker marker, final String s, final Throwable throwable) {
+        logger.logIfEnabled(FQCN, Level.INFO, getMarker(marker), s, throwable);
+    }
+
+    @Override
+    public void warn(final String format) {
+        logger.logIfEnabled(FQCN, Level.WARN, null, format);
+    }
+
+    @Override
+    public void warn(final String format, final Object o) {
+        logger.logIfEnabled(FQCN, Level.WARN, null, format, o);
+    }
+
+    @Override
+    public void warn(final String format, final Object arg1, final Object arg2) {
+        logger.logIfEnabled(FQCN, Level.WARN, null, format, arg1, arg2);
+    }
+
+    @Override
+    public void warn(final String format, final Object... args) {
+        logger.logIfEnabled(FQCN, Level.WARN, null, format, args);
+    }
+
+    @Override
+    public void warn(final String format, final Throwable t) {
+        logger.logIfEnabled(FQCN, Level.WARN, null, format, t);
+    }
+
+    @Override
+    public boolean isWarnEnabled() {
+        return logger.isEnabled(Level.WARN, null, null);
+    }
+
+    @Override
+    public boolean isWarnEnabled(final Marker marker) {
+        return logger.isEnabled(Level.WARN, getMarker(marker), null);
+    }
+
+    @Override
+    public void warn(final Marker marker, final String s) {
+        logger.logIfEnabled(FQCN, Level.WARN, getMarker(marker), s);
+    }
+
+    @Override
+    public void warn(final Marker marker, final String s, final Object o) {
+        logger.logIfEnabled(FQCN, Level.WARN, getMarker(marker), s, o);
+    }
+
+    @Override
+    public void warn(final Marker marker, final String s, final Object o, final Object o1) {
+        logger.logIfEnabled(FQCN, Level.WARN, getMarker(marker), s, o, o1);
+    }
+
+    @Override
+    public void warn(final Marker marker, final String s, final Object... objects) {
+        logger.logIfEnabled(FQCN, Level.WARN, getMarker(marker), s, objects);
+    }
+
+    @Override
+    public void warn(final Marker marker, final String s, final Throwable throwable) {
+        logger.logIfEnabled(FQCN, Level.WARN, getMarker(marker), s, throwable);
+    }
+
+    @Override
+    public void error(final String format) {
+        logger.logIfEnabled(FQCN, Level.ERROR, null, format);
+    }
+
+    @Override
+    public void error(final String format, final Object o) {
+        logger.logIfEnabled(FQCN, Level.ERROR, null, format, o);
+    }
+
+    @Override
+    public void error(final String format, final Object arg1, final Object arg2) {
+        logger.logIfEnabled(FQCN, Level.ERROR, null, format, arg1, arg2);
+    }
+
+    @Override
+    public void error(final String format, final Object... args) {
+        logger.logIfEnabled(FQCN, Level.ERROR, null, format, args);
+    }
+
+    @Override
+    public void error(final String format, final Throwable t) {
+        logger.logIfEnabled(FQCN, Level.ERROR, null, format, t);
+    }
+
+    @Override
+    public boolean isErrorEnabled() {
+        return logger.isEnabled(Level.ERROR, null, null);
+    }
+
+    @Override
+    public boolean isErrorEnabled(final Marker marker) {
+        return logger.isEnabled(Level.ERROR, getMarker(marker), null);
+    }
+
+    @Override
+    public void error(final Marker marker, final String s) {
+        logger.logIfEnabled(FQCN, Level.ERROR, getMarker(marker), s);
+    }
+
+    @Override
+    public void error(final Marker marker, final String s, final Object o) {
+        logger.logIfEnabled(FQCN, Level.ERROR, getMarker(marker), s, o);
+    }
+
+    @Override
+    public void error(final Marker marker, final String s, final Object o, final Object o1) {
+        logger.logIfEnabled(FQCN, Level.ERROR, getMarker(marker), s, o, o1);
+    }
+
+    @Override
+    public void error(final Marker marker, final String s, final Object... objects) {
+        logger.logIfEnabled(FQCN, Level.ERROR, getMarker(marker), s, objects);
+    }
+
+    @Override
+    public void error(final Marker marker, final String s, final Throwable throwable) {
+        logger.logIfEnabled(FQCN, Level.ERROR, getMarker(marker), s, throwable);
+    }
+
+    @Override
+    public void log(final Marker marker, final String fqcn, final int level, final String message, final Object[] params, Throwable throwable) {
+        final Level log4jLevel = getLevel(level);
+        final org.apache.logging.log4j.Marker log4jMarker = getMarker(marker);
+
+        if (!logger.isEnabled(log4jLevel, log4jMarker, message, params)) {
+            return;
+        }
+        final Message msg;
+        if (params == null) {
+            msg = new SimpleMessage(message);
+        } else {
+            msg = new ParameterizedMessage(message, params, throwable);
+            if (throwable != null) {
+                throwable = msg.getThrowable();
+            }
+        }
+        logger.logMessage(fqcn, log4jLevel, log4jMarker, msg, throwable);
+    }
+
+    private org.apache.logging.log4j.Marker getMarker(final Marker marker) {
+        if (marker == null) {
+            return null;
+        } else if (marker instanceof Log4jMarker) {
+            return ((Log4jMarker) marker).getLog4jMarker();
+        } else {
+            return ((Log4jMarker) markerFactory.getMarker(marker)).getLog4jMarker();
+        }
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Always treat de-serialization as a full-blown constructor, by validating the final state of
+     * the de-serialized object.
+     */
+    private void readObject(final ObjectInputStream aInputStream) throws ClassNotFoundException, IOException {
+        // always perform the default de-serialization first
+        aInputStream.defaultReadObject();
+        logger = LogManager.getContext().getLogger(name);
+        markerFactory = ((Log4jLoggerFactory) org.slf4j.LoggerFactory.getILoggerFactory()).getMarkerFactory();
+    }
+
+    /**
+     * This is the default implementation of writeObject. Customise if necessary.
+     */
+    private void writeObject(final ObjectOutputStream aOutputStream) throws IOException {
+        // perform the default serialization for all non-transient, non-static fields
+        aOutputStream.defaultWriteObject();
+    }
+
+    private static Level getLevel(final int i) {
+        switch (i) {
+        case TRACE_INT:
+            return Level.TRACE;
+        case DEBUG_INT:
+            return Level.DEBUG;
+        case INFO_INT:
+            return Level.INFO;
+        case WARN_INT:
+            return Level.WARN;
+        case ERROR_INT:
+            return Level.ERROR;
+        }
+        return Level.ERROR;
+    }
+}
diff --git a/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jLoggerFactory.java b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jLoggerFactory.java
new file mode 100644
index 0000000000..99e6817a1a
--- /dev/null
+++ b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jLoggerFactory.java
@@ -0,0 +1,75 @@
+/*
+ * 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.slf4j;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.LoggingException;
+import org.apache.logging.log4j.spi.AbstractLoggerAdapter;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.StackLocatorUtil;
+import org.slf4j.ILoggerFactory;
+import org.slf4j.Logger;
+
+import java.util.function.Predicate;
+
+/**
+ * Log4j implementation of SLF4J ILoggerFactory interface.
+ */
+public class Log4jLoggerFactory extends AbstractLoggerAdapter<Logger> implements ILoggerFactory {
+
+    private static final StatusLogger LOGGER = StatusLogger.getLogger();
+    private static final String SLF4J_PACKAGE = "org.slf4j";
+    private static final Predicate<Class<?>> CALLER_PREDICATE = clazz ->
+            !AbstractLoggerAdapter.class.equals(clazz) && !clazz.getName().startsWith(SLF4J_PACKAGE);
+    private static final String TO_SLF4J_CONTEXT = "org.apache.logging.slf4j.SLF4JLoggerContext";
+
+    private final Log4jMarkerFactory markerFactory;
+
+    public Log4jLoggerFactory(final Log4jMarkerFactory markerFactory) {
+        this.markerFactory = markerFactory;
+    }
+
+
+    @Override
+    protected Logger newLogger(final String name, final LoggerContext context) {
+        final String key = Logger.ROOT_LOGGER_NAME.equals(name) ? LogManager.ROOT_LOGGER_NAME : name;
+        return new Log4jLogger(markerFactory, validateContext(context).getLogger(key), name);
+    }
+
+    @Override
+    protected LoggerContext getContext() {
+        final Class<?> anchor = LogManager.getFactory().isClassLoaderDependent()
+                ? StackLocatorUtil.getCallerClass(Log4jLoggerFactory.class, CALLER_PREDICATE)
+                : null;
+        LOGGER.trace("Log4jLoggerFactory.getContext() found anchor {}", anchor);
+        return anchor == null
+                ? LogManager.getContext(false)
+                : getContext(anchor);
+    }
+
+    Log4jMarkerFactory getMarkerFactory() {
+        return markerFactory;
+    }
+
+    private LoggerContext validateContext(final LoggerContext context) {
+        if (TO_SLF4J_CONTEXT.equals(context.getClass().getName())) {
+            throw new LoggingException("log4j-slf4j-impl cannot be present with log4j-to-slf4j");
+        }
+        return context;
+    }
+}
diff --git a/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jMDCAdapter.java b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jMDCAdapter.java
new file mode 100644
index 0000000000..b12c297ac3
--- /dev/null
+++ b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jMDCAdapter.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.slf4j;
+
+import java.util.Map;
+
+import org.apache.logging.log4j.ThreadContext;
+import org.slf4j.spi.MDCAdapter;
+
+/**
+ *
+ */
+public class Log4jMDCAdapter implements MDCAdapter {
+
+    @Override
+    public void put(final String key, final String val) {
+        ThreadContext.put(key, val);
+    }
+
+    @Override
+    public String get(final String key) {
+        return ThreadContext.get(key);
+    }
+
+    @Override
+    public void remove(final String key) {
+        ThreadContext.remove(key);
+    }
+
+    @Override
+    public void clear() {
+        ThreadContext.clearMap();
+    }
+
+    @Override
+    public Map<String, String> getCopyOfContextMap() {
+        return ThreadContext.getContext();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked") // nothing we can do about this, restricted by SLF4J API
+    public void setContextMap(@SuppressWarnings("rawtypes") final Map map) {
+        ThreadContext.clearMap();
+        ThreadContext.putAll(map);
+    }
+}
diff --git a/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jMarker.java b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jMarker.java
new file mode 100644
index 0000000000..fb21659103
--- /dev/null
+++ b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jMarker.java
@@ -0,0 +1,126 @@
+/*
+ * 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.slf4j;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.logging.log4j.MarkerManager;
+import org.slf4j.IMarkerFactory;
+import org.slf4j.Marker;
+
+/**
+ * Log4j/SLF4J {@link Marker} type bridge.
+ */
+class Log4jMarker implements Marker {
+
+    public static final long serialVersionUID = 1590472L;
+
+    private final IMarkerFactory factory;
+
+    private final org.apache.logging.log4j.Marker marker;
+
+    /**
+     * Constructs a Log4jMarker using an existing Log4j {@link org.apache.logging.log4j.Marker}.
+     * @param marker The Log4j Marker upon which to base this Marker.
+     */
+    public Log4jMarker(final IMarkerFactory markerFactory, final org.apache.logging.log4j.Marker marker) {
+        this.factory = markerFactory;
+        this.marker = marker;
+    }
+
+    @Override
+    public void add(final Marker marker) {
+		if (marker == null) {
+			throw new IllegalArgumentException();
+		}
+        final Marker m = factory.getMarker(marker.getName());
+        this.marker.addParents(((Log4jMarker)m).getLog4jMarker());
+    }
+
+    @Override
+	public boolean contains(final Marker marker) {
+		if (marker == null) {
+			throw new IllegalArgumentException();
+		}
+		return this.marker.isInstanceOf(marker.getName());
+	}
+
+    @Override
+	public boolean contains(final String s) {
+		return s != null ? this.marker.isInstanceOf(s) : false;
+	}
+
+    @Override
+	public boolean equals(final Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (obj == null) {
+			return false;
+		}
+		if (!(obj instanceof Log4jMarker)) {
+			return false;
+		}
+		final Log4jMarker other = (Log4jMarker) obj;
+		if (!Objects.equals(marker, other.marker)) {
+			return false;
+		}
+		return true;
+	}
+
+    public org.apache.logging.log4j.Marker getLog4jMarker() {
+        return marker;
+    }
+
+    @Override
+    public String getName() {
+        return marker.getName();
+    }
+
+    @Override
+    public boolean hasChildren() {
+        return marker.hasParents();
+    }
+
+    @Override
+	public int hashCode() {
+		return 31 + Objects.hashCode(marker);
+	}
+
+    @Override
+    public boolean hasReferences() {
+        return marker.hasParents();
+    }
+
+	@Override
+    public Iterator<Marker> iterator() {
+        final org.apache.logging.log4j.Marker[] log4jParents = this.marker.getParents();
+        final List<Marker> parents = new ArrayList<>(log4jParents.length);
+		for (final org.apache.logging.log4j.Marker m : log4jParents) {
+            parents.add(factory.getMarker(m.getName()));
+        }
+        return parents.iterator();
+    }
+
+	@Override
+	public boolean remove(final Marker marker) {
+		return marker != null ? this.marker.remove(MarkerManager.getMarker(marker.getName())) : false;
+	}
+}
diff --git a/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jMarkerFactory.java b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jMarkerFactory.java
new file mode 100644
index 0000000000..69ea94b33c
--- /dev/null
+++ b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jMarkerFactory.java
@@ -0,0 +1,138 @@
+/*
+ * 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.slf4j;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.MarkerManager;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.slf4j.IMarkerFactory;
+import org.slf4j.Marker;
+
+/**
+ * Log4j/SLF4J bridge to create SLF4J Markers based on name or based on existing SLF4J Markers.
+ */
+public class Log4jMarkerFactory implements IMarkerFactory {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    private final ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<>();
+
+    /**
+     * Returns a Log4j Marker that is compatible with SLF4J.
+     * @param name The name of the Marker.
+     * @return A Marker.
+     */
+    @Override
+    public Marker getMarker(final String name) {
+        if (name == null) {
+            throw new IllegalArgumentException("Marker name must not be null");
+        }
+        final Marker marker = markerMap.get(name);
+        if (marker != null) {
+            return marker;
+        }
+        final org.apache.logging.log4j.Marker log4jMarker = MarkerManager.getMarker(name);
+        return addMarkerIfAbsent(name, log4jMarker);
+    }
+
+    private Marker addMarkerIfAbsent(final String name, final org.apache.logging.log4j.Marker log4jMarker) {
+        final Marker marker = new Log4jMarker(this, log4jMarker);
+        final Marker existing = markerMap.putIfAbsent(name, marker);
+        return existing == null ? marker : existing;
+    }
+
+    /**
+     * Returns a Log4j Marker converted from an existing custom SLF4J Marker.
+     * @param marker The SLF4J Marker to convert.
+     * @return A converted Log4j/SLF4J Marker.
+     * @since 2.1
+     */
+    public Marker getMarker(final Marker marker) {
+        if (marker == null) {
+            throw new IllegalArgumentException("Marker must not be null");
+        }
+        final Marker m = markerMap.get(marker.getName());
+        if (m != null) {
+            return m;
+        }
+        return addMarkerIfAbsent(marker.getName(), convertMarker(marker));
+    }
+
+    private static org.apache.logging.log4j.Marker convertMarker(final Marker original) {
+        if (original == null) {
+            throw new IllegalArgumentException("Marker must not be null");
+        }
+        return convertMarker(original, new ArrayList<Marker>());
+    }
+
+    private static org.apache.logging.log4j.Marker convertMarker(final Marker original,
+                                                                 final Collection<Marker> visited) {
+        final org.apache.logging.log4j.Marker marker = MarkerManager.getMarker(original.getName());
+        if (original.hasReferences()) {
+            final Iterator<Marker> it = original.iterator();
+            while (it.hasNext()) {
+                final Marker next = it.next();
+                if (visited.contains(next)) {
+                    LOGGER.warn("Found a cycle in Marker [{}]. Cycle will be broken.", next.getName());
+                } else {
+                    visited.add(next);
+                    marker.addParents(convertMarker(next, visited));
+                }
+            }
+        }
+        return marker;
+    }
+
+    /**
+     * Returns true if the Marker exists.
+     * @param name The Marker name.
+     * @return {@code true} if the Marker exists, {@code false} otherwise.
+     */
+    @Override
+    public boolean exists(final String name) {
+        return markerMap.containsKey(name);
+    }
+
+    /**
+     * Log4j does not support detached Markers. This method always returns false.
+     * @param name The Marker name.
+     * @return {@code false}
+     */
+    @Override
+    public boolean detachMarker(final String name) {
+        return false;
+    }
+
+    /**
+     * Log4j does not support detached Markers for performance reasons. The returned Marker is attached.
+     * @param name The Marker name.
+     * @return The named Marker (unmodified).
+     */
+    @Override
+    public Marker getDetachedMarker(final String name) {
+        LOGGER.warn("Log4j does not support detached Markers. Returned Marker [{}] will be unchanged.", name);
+        return getMarker(name);
+    }
+
+
+}
diff --git a/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/SLF4JLoggingException.java b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/SLF4JLoggingException.java
new file mode 100644
index 0000000000..0a41215383
--- /dev/null
+++ b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/SLF4JLoggingException.java
@@ -0,0 +1,41 @@
+/*
+ * 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.slf4j;
+
+/**
+ * Exception thrown when the SLF4J adapter encounters a problem.
+ *
+ */
+public class SLF4JLoggingException extends RuntimeException {
+
+    /**
+     * Generated serial version ID.
+     */
+    private static final long serialVersionUID = -1618650972455089998L;
+
+    public SLF4JLoggingException(final String msg) {
+        super(msg);
+    }
+
+    public SLF4JLoggingException(final String msg, final Exception ex) {
+        super(msg, ex);
+    }
+
+    public SLF4JLoggingException(final Exception ex) {
+        super(ex);
+    }
+}
diff --git a/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/SLF4JServiceProvider.java b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/SLF4JServiceProvider.java
new file mode 100644
index 0000000000..b711941a91
--- /dev/null
+++ b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/SLF4JServiceProvider.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.slf4j;
+
+import org.slf4j.ILoggerFactory;
+import org.slf4j.IMarkerFactory;
+import org.slf4j.spi.MDCAdapter;
+
+public class SLF4JServiceProvider implements org.slf4j.spi.SLF4JServiceProvider {
+
+    public static final String REQUESTED_API_VERSION = "2.0.99";
+
+    private ILoggerFactory loggerFactory;
+    private Log4jMarkerFactory markerFactory;
+    private MDCAdapter mdcAdapter;
+
+    @Override
+    public ILoggerFactory getLoggerFactory() {
+        return loggerFactory;
+    }
+
+    @Override
+    public IMarkerFactory getMarkerFactory() {
+        return markerFactory;
+    }
+
+    @Override
+    public MDCAdapter getMDCAdapter() {
+        return mdcAdapter;
+    }
+
+    @Override
+    public String getRequestedApiVersion() {
+        return REQUESTED_API_VERSION;
+    }
+
+    @Override
+    public void initialize() {
+        markerFactory = new Log4jMarkerFactory();
+        loggerFactory = new Log4jLoggerFactory(markerFactory);
+        mdcAdapter = new Log4jMDCAdapter();
+    }
+
+
+}
diff --git a/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/package-info.java b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/package-info.java
new file mode 100644
index 0000000000..ec0f031c37
--- /dev/null
+++ b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * SLF4J support. Note that this does indeed share the same package namespace as the one found in log4j-to-slf4j;
+ * this is intentional. The two JARs should <em>not</em> be used at the same time! Thus, in an OSGi environment
+ * where split packages are not allowed, this error is prevented due to both JARs sharing an exported package name.
+ */
+package org.apache.logging.slf4j;
diff --git a/log4j-slf4j20-impl/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider b/log4j-slf4j20-impl/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider
new file mode 100644
index 0000000000..1577f12daf
--- /dev/null
+++ b/log4j-slf4j20-impl/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider
@@ -0,0 +1 @@
+org.apache.logging.slf4j.SLF4JServiceProvider
\ No newline at end of file
diff --git a/log4j-slf4j20-impl/src/site/markdown/index.md b/log4j-slf4j20-impl/src/site/markdown/index.md
new file mode 100644
index 0000000000..6e3f3f69d1
--- /dev/null
+++ b/log4j-slf4j20-impl/src/site/markdown/index.md
@@ -0,0 +1,40 @@
+<!-- vim: set syn=markdown : -->
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+# Log4j 2 SLF4J Binding
+
+The Log4j 2 SLF4J Binding allows applications coded to the SLF4J API to use
+Log4j 2 as the implementation.
+
+## Requirements
+
+The Log4j 2 SLF4J Binding has a dependency on the Log4j 2 API as well as the SLF4J API.
+For more information, see [Runtime Dependencies](../runtime-dependencies.html).
+
+## Usage
+
+The SLF4J binding provided in this component cause all the SLF4J APIs to be routed to Log4j 2. Simply
+include the Log4j 2 SLF4J Binding jar along with the Log4j 2 jars and SLF4J API jar to cause all SLF4J
+logging to be handled by Log4j 2.
+
+<div class="alert alert-danger">
+Use of the Log4j 2 SLF4J Binding (log4j-slf4j-impl-2.0.jar) together with 
+the SLF4J adapter (log4j-to-slf4j-2.0.jar) should 
+never be attempted, as it will cause events to endlessly be routed between
+SLF4J and Log4j 2.
+</div>
diff --git a/log4j-slf4j20-impl/src/site/site.xml b/log4j-slf4j20-impl/src/site/site.xml
new file mode 100644
index 0000000000..a1f9106932
--- /dev/null
+++ b/log4j-slf4j20-impl/src/site/site.xml
@@ -0,0 +1,52 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project name="SLF4J Binding Using Log4j"
+         xmlns="http://maven.apache.org/DECORATION/1.4.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 http://maven.apache.org/xsd/decoration-1.4.0.xsd">
+  <body>
+    <links>
+      <item name="Apache" href="http://www.apache.org/" />
+      <item name="Logging Services" href="http://logging.apache.org/"/>
+      <item name="Log4j" href="../index.html"/>
+    </links>
+
+    <!-- Component-specific reports -->
+    <menu ref="reports"/>
+
+	<!-- Overall Project Info -->
+    <menu name="Log4j Project Information" img="icon-info-sign">
+      <item name="Dependencies" href="../dependencies.html" />
+      <item name="Dependency Convergence" href="../dependency-convergence.html" />
+      <item name="Dependency Management" href="../dependency-management.html" />
+      <item name="Project Team" href="../team-list.html" />
+      <item name="Mailing Lists" href="../mail-lists.html" />
+      <item name="Issue Tracking" href="../issue-tracking.html" />
+      <item name="Project License" href="../license.html" />
+      <item name="Source Repository" href="../source-repository.html" />
+      <item name="Project Summary" href="../project-summary.html" />
+    </menu>
+
+    <menu name="Log4j Project Reports" img="icon-cog">
+      <item name="Changes Report" href="../changes-report.html" />
+      <item name="JIRA Report" href="../jira-report.html" />
+      <item name="Surefire Report" href="../surefire-report.html" />
+      <item name="RAT Report" href="../rat-report.html" />
+    </menu>
+  </body>
+</project>
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/other/pkg/LoggerContextAnchorTest.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/other/pkg/LoggerContextAnchorTest.java
new file mode 100644
index 0000000000..2b0fe91c20
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/other/pkg/LoggerContextAnchorTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.other.pkg;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.status.StatusData;
+import org.apache.logging.log4j.status.StatusListener;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.junit.Test;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test LoggerContext lookups by verifying the anchor class representing calling code.
+ */
+public class LoggerContextAnchorTest {
+    private static final String PREFIX = "Log4jLoggerFactory.getContext() found anchor class ";
+
+    @Test
+    public void testLoggerFactoryLookupClass() {
+        String fqcn = getAnchorFqcn(() -> LoggerFactory.getLogger(LoggerContextAnchorTest.class));
+        assertEquals(getClass().getName(), fqcn);
+    }
+
+    @Test
+    public void testLoggerFactoryLookupString() {
+        String fqcn = getAnchorFqcn(() -> LoggerFactory.getLogger("custom.logger"));
+        assertEquals(getClass().getName(), fqcn);
+    }
+
+    @Test
+    public void testLoggerFactoryGetILoggerFactoryLookup() {
+        String fqcn = getAnchorFqcn(() -> LoggerFactory.getILoggerFactory().getLogger("custom.logger"));
+        assertEquals(getClass().getName(), fqcn);
+    }
+
+    private static String getAnchorFqcn(Runnable runnable) {
+        List<String> results = new CopyOnWriteArrayList<>();
+        StatusListener listener = new StatusListener() {
+            @Override
+            public void log(StatusData data) {
+                String formattedMessage = data.getMessage().getFormattedMessage();
+                if (formattedMessage.startsWith(PREFIX)) {
+                    results.add(formattedMessage.substring(PREFIX.length()));
+                }
+            }
+
+            @Override
+            public Level getStatusLevel() {
+                return Level.TRACE;
+            }
+
+            @Override
+            public void close() {
+                // nop
+            }
+        };
+        StatusLogger statusLogger = StatusLogger.getLogger();
+        statusLogger.registerListener(listener);
+        try {
+            runnable.run();
+            if (results.isEmpty()) {
+                throw new AssertionError("Failed to locate an anchor lookup status message");
+            }
+            if (results.size() > 1) {
+                throw new AssertionError("Found multiple anchor lines: " + results);
+            }
+            return results.get(0);
+        } finally {
+            statusLogger.removeListener(listener);
+        }
+    }
+}
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/CallerInformationTest.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/CallerInformationTest.java
new file mode 100644
index 0000000000..7efc0e5090
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/CallerInformationTest.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.slf4j;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CallerInformationTest {
+
+    // config from log4j-core test-jar
+    private static final String CONFIG = "log4j2-calling-class.xml";
+
+    @ClassRule
+    public static final LoggerContextRule ctx = new LoggerContextRule(CONFIG);
+
+    @Test
+    public void testClassLogger() throws Exception {
+        final ListAppender app = ctx.getListAppender("Class").clear();
+        final Logger logger = LoggerFactory.getLogger("ClassLogger");
+        logger.info("Ignored message contents.");
+        logger.warn("Verifying the caller class is still correct.");
+        logger.error("Hopefully nobody breaks me!");
+        final List<String> messages = app.getMessages();
+        assertEquals("Incorrect number of messages.", 3, messages.size());
+        for (final String message : messages) {
+            assertEquals("Incorrect caller class name.", this.getClass().getName(), message);
+        }
+    }
+
+    @Test
+    public void testMethodLogger() throws Exception {
+        final ListAppender app = ctx.getListAppender("Method").clear();
+        final Logger logger = LoggerFactory.getLogger("MethodLogger");
+        logger.info("More messages.");
+        logger.warn("CATASTROPHE INCOMING!");
+        logger.error("ZOMBIES!!!");
+        logger.warn("brains~~~");
+        logger.info("Itchy. Tasty.");
+        final List<String> messages = app.getMessages();
+        assertEquals("Incorrect number of messages.", 5, messages.size());
+        for (final String message : messages) {
+            assertEquals("Incorrect caller method name.", "testMethodLogger", message);
+        }
+    }
+}
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/CustomFlatMarker.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/CustomFlatMarker.java
new file mode 100644
index 0000000000..0138cead6e
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/CustomFlatMarker.java
@@ -0,0 +1,76 @@
+/*
+ * 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.slf4j;
+
+import java.util.Iterator;
+
+import org.slf4j.Marker;
+
+/**
+ * Test Marker that may contain no reference/parent Markers.
+ * @see <a href="https://issues.apache.org/jira/browse/LOG4J2-793">LOG4J2-793</a>
+ */
+public class CustomFlatMarker implements Marker {
+    private static final long serialVersionUID = -4115520883240247266L;
+
+    private final String name;
+
+    public CustomFlatMarker(final String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void add(final Marker reference) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean remove(final Marker reference) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean hasChildren() {
+        return hasReferences();
+    }
+
+    @Override
+    public boolean hasReferences() {
+        return false;
+    }
+
+    @Override
+    public Iterator<Marker> iterator() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean contains(final Marker other) {
+        return false;
+    }
+
+    @Override
+    public boolean contains(final String name) {
+        return false;
+    }
+}
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/Log4j1222Test.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/Log4j1222Test.java
new file mode 100644
index 0000000000..59f69e0d2d
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/Log4j1222Test.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.slf4j;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests logging during shutdown.
+ */
+public class Log4j1222Test
+{
+
+	@Test
+	public void homepageRendersSuccessfully()
+	{
+        System.setProperty("log4j.configurationFile", "log4j2-console.xml");
+		Runtime.getRuntime().addShutdownHook(new ShutdownHook());
+	}
+
+	private static class ShutdownHook extends Thread {
+
+		private static class Holder {
+			private static final Logger LOGGER = LoggerFactory.getLogger(Log4j1222Test.class);
+		}
+
+		@Override
+		public void run()
+		{
+			super.run();
+			trigger();
+		}
+
+		private void trigger() {
+			Holder.LOGGER.info("Attempt to trigger");
+			assertTrue("Logger is of type " + Holder.LOGGER.getClass().getName(), Holder.LOGGER instanceof Log4jLogger);
+
+		}
+	}
+}
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/Log4j2_1482_Slf4jTest.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/Log4j2_1482_Slf4jTest.java
new file mode 100644
index 0000000000..8934f29a77
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/Log4j2_1482_Slf4jTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.slf4j;
+
+import org.apache.logging.log4j.core.layout.Log4j2_1482_Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tests https://issues.apache.org/jira/browse/LOG4J2-1482
+ */
+public class Log4j2_1482_Slf4jTest extends Log4j2_1482_Test {
+
+	@Override
+	protected void log(final int runNumber) {
+		if (runNumber == 2) {
+			// System.out.println("Set a breakpoint here.");
+		}
+		final Logger logger = LoggerFactory.getLogger("auditcsvfile");
+		final int val1 = 9, val2 = 11, val3 = 12;
+		logger.info("Info Message!", val1, val2, val3);
+		logger.info("Info Message!", val1, val2, val3);
+		logger.info("Info Message!", val1, val2, val3);
+	}
+
+}
\ No newline at end of file
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/Log4jMarkerTest.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/Log4jMarkerTest.java
new file mode 100644
index 0000000000..ac6ad22b39
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/Log4jMarkerTest.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.slf4j;
+
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class Log4jMarkerTest {
+
+    private static Log4jMarkerFactory markerFactory;
+
+    @BeforeClass
+    public static void startup() {
+        markerFactory = ((Log4jLoggerFactory) org.slf4j.LoggerFactory.getILoggerFactory()).getMarkerFactory();
+
+    }
+
+	@Test
+	public void testEquals() {
+		final Marker markerA = MarkerManager.getMarker(Log4jMarkerTest.class.getName() + "-A");
+		final Marker markerB = MarkerManager.getMarker(Log4jMarkerTest.class.getName() + "-B");
+		final Log4jMarker marker1 = new Log4jMarker(markerFactory, markerA);
+		final Log4jMarker marker2 = new Log4jMarker(markerFactory, markerA);
+		final Log4jMarker marker3 = new Log4jMarker(markerFactory, markerB);
+		Assert.assertEquals(marker1, marker2);
+		Assert.assertNotEquals(marker1, null);
+		Assert.assertNotEquals(null, marker1);
+		Assert.assertNotEquals(marker1, marker3);
+	}
+}
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/LoggerContextTest.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/LoggerContextTest.java
new file mode 100644
index 0000000000..de37a3614f
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/LoggerContextTest.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.slf4j;
+
+import org.apache.logging.log4j.core.LifeCycle;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.junit.Test;
+import org.slf4j.LoggerFactory;
+
+import java.util.Set;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests cleanup of the LoggerContexts.
+ */
+public class LoggerContextTest {
+
+    @Test
+    public void testCleanup() throws Exception {
+        Log4jLoggerFactory factory = (Log4jLoggerFactory) LoggerFactory.getILoggerFactory();
+        factory.getLogger("test");
+        Set<LoggerContext> set = factory.getLoggerContexts();
+        LoggerContext ctx1 = set.toArray(LoggerContext.EMPTY_ARRAY)[0];
+        assertTrue("LoggerContext is not enabled for shutdown", ctx1 instanceof LifeCycle);
+        ((LifeCycle) ctx1).stop();
+        set = factory.getLoggerContexts();
+        assertTrue("Expected no LoggerContexts", set.isEmpty());
+    }
+}
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/LoggerTest.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/LoggerTest.java
new file mode 100644
index 0000000000..7c8e71379f
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/LoggerTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.slf4j;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.slf4j.Marker;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+import org.slf4j.spi.LocationAwareLogger;
+
+/**
+ *
+ */
+public class LoggerTest {
+
+    private static final String CONFIG = "log4j-test1.xml";
+
+    @ClassRule
+    public static LoggerContextRule ctx = new LoggerContextRule(CONFIG);
+
+    Logger logger = LoggerFactory.getLogger("LoggerTest");
+    XLogger xlogger = XLoggerFactory.getXLogger("LoggerTest");
+
+    @Test
+    public void basicFlow() {
+        xlogger.entry();
+        verify("List", "o.a.l.s.LoggerTest entry MDC{}" + Strings.LINE_SEPARATOR);
+        xlogger.exit();
+        verify("List", "o.a.l.s.LoggerTest exit MDC{}" + Strings.LINE_SEPARATOR);
+    }
+
+    @Test
+    public void simpleFlow() {
+        xlogger.entry(CONFIG);
+        verify("List", "o.a.l.s.LoggerTest entry with (log4j-test1.xml) MDC{}" + Strings.LINE_SEPARATOR);
+        xlogger.exit(0);
+        verify("List", "o.a.l.s.LoggerTest exit with (0) MDC{}" + Strings.LINE_SEPARATOR);
+    }
+
+    @Test
+    public void throwing() {
+        xlogger.throwing(new IllegalArgumentException("Test Exception"));
+        verify("List", "o.a.l.s.LoggerTest throwing MDC{}" + Strings.LINE_SEPARATOR);
+    }
+
+    @Test
+    public void catching() {
+        try {
+            throw new NullPointerException();
+        } catch (final Exception e) {
+            xlogger.catching(e);
+            verify("List", "o.a.l.s.LoggerTest catching MDC{}" + Strings.LINE_SEPARATOR);
+        }
+    }
+
+    @Test
+    public void debug() {
+        logger.debug("Debug message");
+        verify("List", "o.a.l.s.LoggerTest Debug message MDC{}" + Strings.LINE_SEPARATOR);
+    }
+
+    @Test
+    public void debugNoParms() {
+        logger.debug("Debug message {}");
+        verify("List", "o.a.l.s.LoggerTest Debug message {} MDC{}" + Strings.LINE_SEPARATOR);
+        logger.debug("Debug message {}", (Object[]) null);
+        verify("List", "o.a.l.s.LoggerTest Debug message {} MDC{}" + Strings.LINE_SEPARATOR);
+        ((LocationAwareLogger)logger).log(null, Log4jLogger.class.getName(), LocationAwareLogger.DEBUG_INT,
+            "Debug message {}", null, null);
+        verify("List", "o.a.l.s.LoggerTest Debug message {} MDC{}" + Strings.LINE_SEPARATOR);
+    }
+
+
+    @Test
+    public void debugWithParms() {
+        logger.debug("Hello, {}", "World");
+        verify("List", "o.a.l.s.LoggerTest Hello, World MDC{}" + Strings.LINE_SEPARATOR);
+    }
+
+    @Test
+    public void mdc() {
+
+        MDC.put("TestYear", "2010");
+        logger.debug("Debug message");
+        verify("List", "o.a.l.s.LoggerTest Debug message MDC{TestYear=2010}" + Strings.LINE_SEPARATOR);
+        MDC.clear();
+        logger.debug("Debug message");
+        verify("List", "o.a.l.s.LoggerTest Debug message MDC{}" + Strings.LINE_SEPARATOR);
+    }
+
+    /**
+     * @see <a href="https://issues.apache.org/jira/browse/LOG4J2-793">LOG4J2-793</a>
+     */
+    @Test
+    public void supportsCustomSLF4JMarkers() {
+        final Marker marker = new CustomFlatMarker("TEST");
+        logger.debug(marker, "Test");
+        verify("List", "o.a.l.s.LoggerTest Test MDC{}" + Strings.LINE_SEPARATOR);
+    }
+
+    @Test
+    public void testRootLogger() {
+        final Logger l = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+        assertNotNull("No Root Logger", l);
+        assertEquals(Logger.ROOT_LOGGER_NAME, l.getName());
+    }
+
+    @Test
+    public void doubleSubst() {
+        logger.debug("Hello, {}", "Log4j {}");
+        verify("List", "o.a.l.s.LoggerTest Hello, Log4j {} MDC{}" + Strings.LINE_SEPARATOR);
+        xlogger.debug("Hello, {}", "Log4j {}");
+        verify("List", "o.a.l.s.LoggerTest Hello, Log4j {} MDC{}" + Strings.LINE_SEPARATOR);
+    }
+
+    private void verify(final String name, final String expected) {
+        final ListAppender listApp = ctx.getListAppender(name);
+        assertNotNull("Missing Appender", listApp);
+        final List<String> events = listApp.getMessages();
+        assertTrue("Incorrect number of messages. Expected 1 Actual " + events.size(), events.size()== 1);
+        final String actual = events.get(0);
+        assertEquals("Incorrect message. Expected " + expected + ". Actual " + actual, expected, actual);
+        listApp.clear();
+    }
+
+    @Before
+    @After
+    public void cleanup() {
+        MDC.clear();
+        ctx.getListAppender("List").clear();
+    }
+}
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/MarkerTest.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/MarkerTest.java
new file mode 100644
index 0000000000..c078fe03fe
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/MarkerTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.slf4j;
+
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class MarkerTest {
+
+	private static final String CHILD_MAKER_NAME = MarkerTest.class.getSimpleName() + "-TEST";
+	private static final String PARENT_MARKER_NAME = MarkerTest.class.getSimpleName() + "-PARENT";
+	private static Log4jMarkerFactory markerFactory;
+
+	@BeforeClass
+    public static void startup() {
+	    markerFactory = ((Log4jLoggerFactory) org.slf4j.LoggerFactory.getILoggerFactory()).getMarkerFactory();
+
+    }
+
+    @Before
+	@After
+	public void clearMarkers() {
+		MarkerManager.clear();
+	}
+
+	@Test
+	public void testAddMarker() {
+		final String childMakerName = CHILD_MAKER_NAME + "-AM";
+		final String parentMarkerName = PARENT_MARKER_NAME + "-AM";
+		final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMakerName);
+		final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMarkerName);
+		slf4jMarker.add(slf4jParent);
+		final Marker log4jParent = MarkerManager.getMarker(parentMarkerName);
+		final Marker log4jMarker = MarkerManager.getMarker(childMakerName);
+
+		assertTrue("Incorrect Marker class", slf4jMarker instanceof Log4jMarker);
+		assertTrue(String.format("%s (log4jMarker=%s) is not an instance of %s (log4jParent=%s) in Log4j",
+				childMakerName, parentMarkerName, log4jMarker, log4jParent), log4jMarker.isInstanceOf(log4jParent));
+		assertTrue(String.format("%s (slf4jMarker=%s) is not an instance of %s (log4jParent=%s) in SLF4J",
+				childMakerName, parentMarkerName, slf4jMarker, slf4jParent), slf4jMarker.contains(slf4jParent));
+	}
+
+	@Test
+	public void testAddNullMarker() {
+		final String childMarkerName = CHILD_MAKER_NAME + "-ANM";
+		final String parentMakerName = PARENT_MARKER_NAME + "-ANM";
+		final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMarkerName);
+		final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
+		slf4jMarker.add(slf4jParent);
+		final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
+		final Marker log4jMarker = MarkerManager.getMarker(childMarkerName);
+		final Log4jMarker log4jSlf4jParent = new Log4jMarker(markerFactory, log4jParent);
+		final Log4jMarker log4jSlf4jMarker = new Log4jMarker(markerFactory, log4jMarker);
+		final org.slf4j.Marker nullMarker = null;
+		try {
+			log4jSlf4jParent.add(nullMarker);
+			fail("Expected " + IllegalArgumentException.class.getName());
+		} catch (final IllegalArgumentException e) {
+			// expected
+		}
+		try {
+			log4jSlf4jMarker.add(nullMarker);
+			fail("Expected " + IllegalArgumentException.class.getName());
+		} catch (final IllegalArgumentException e) {
+			// expected
+		}
+	}
+
+	@Test
+	public void testAddSameMarker() {
+		final String childMarkerName = CHILD_MAKER_NAME + "-ASM";
+		final String parentMakerName = PARENT_MARKER_NAME + "-ASM";
+		final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMarkerName);
+		final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
+		slf4jMarker.add(slf4jParent);
+		slf4jMarker.add(slf4jParent);
+		final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
+		final Marker log4jMarker = MarkerManager.getMarker(childMarkerName);
+		assertTrue(String.format("%s (log4jMarker=%s) is not an instance of %s (log4jParent=%s) in Log4j",
+				childMarkerName, parentMakerName, log4jMarker, log4jParent), log4jMarker.isInstanceOf(log4jParent));
+		assertTrue(String.format("%s (slf4jMarker=%s) is not an instance of %s (log4jParent=%s) in SLF4J",
+				childMarkerName, parentMakerName, slf4jMarker, slf4jParent), slf4jMarker.contains(slf4jParent));
+	}
+
+	@Test
+	public void testEquals() {
+		final String childMarkerName = CHILD_MAKER_NAME + "-ASM";
+		final String parentMakerName = PARENT_MARKER_NAME + "-ASM";
+		final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMarkerName);
+		final org.slf4j.Marker slf4jMarker2 = org.slf4j.MarkerFactory.getMarker(childMarkerName);
+		final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
+		slf4jMarker.add(slf4jParent);
+		final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
+		final Marker log4jMarker = MarkerManager.getMarker(childMarkerName);
+		final Marker log4jMarker2 = MarkerManager.getMarker(childMarkerName);
+		assertEquals(log4jParent, log4jParent);
+		assertEquals(log4jMarker, log4jMarker);
+		assertEquals(log4jMarker, log4jMarker2);
+		assertEquals(slf4jMarker, slf4jMarker2);
+		assertNotEquals(log4jParent, log4jMarker);
+		assertNotEquals(log4jMarker, log4jParent);
+	}
+
+	@Test
+	public void testContainsNullMarker() {
+		final String childMarkerName = CHILD_MAKER_NAME + "-CM";
+		final String parentMakerName = PARENT_MARKER_NAME + "-CM";
+		final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMarkerName);
+		final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
+		slf4jMarker.add(slf4jParent);
+		final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
+		final Marker log4jMarker = MarkerManager.getMarker(childMarkerName);
+		final Log4jMarker log4jSlf4jParent = new Log4jMarker(markerFactory, log4jParent);
+		final Log4jMarker log4jSlf4jMarker = new Log4jMarker(markerFactory, log4jMarker);
+		final org.slf4j.Marker nullMarker = null;
+		try {
+			Assert.assertFalse(log4jSlf4jParent.contains(nullMarker));
+			fail("Expected " + IllegalArgumentException.class.getName());
+		} catch (final IllegalArgumentException e) {
+			// expected
+		}
+		try {
+			Assert.assertFalse(log4jSlf4jMarker.contains(nullMarker));
+			fail("Expected " + IllegalArgumentException.class.getName());
+		} catch (final IllegalArgumentException e) {
+			// expected
+		}
+	}
+
+	@Test
+	public void testContainsNullString() {
+		final String childMarkerName = CHILD_MAKER_NAME + "-CS";
+		final String parentMakerName = PARENT_MARKER_NAME + "-CS";
+		final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMarkerName);
+		final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
+		slf4jMarker.add(slf4jParent);
+		final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
+		final Marker log4jMarker = MarkerManager.getMarker(childMarkerName);
+		final Log4jMarker log4jSlf4jParent = new Log4jMarker(markerFactory, log4jParent);
+		final Log4jMarker log4jSlf4jMarker = new Log4jMarker(markerFactory, log4jMarker);
+		final String nullStr = null;
+		Assert.assertFalse(log4jSlf4jParent.contains(nullStr));
+		Assert.assertFalse(log4jSlf4jMarker.contains(nullStr));
+	}
+
+	@Test
+	public void testRemoveNullMarker() {
+		final String childMakerName = CHILD_MAKER_NAME + "-CM";
+		final String parentMakerName = PARENT_MARKER_NAME + "-CM";
+		final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMakerName);
+		final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
+		slf4jMarker.add(slf4jParent);
+		final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
+		final Marker log4jMarker = MarkerManager.getMarker(childMakerName);
+		final Log4jMarker log4jSlf4jParent = new Log4jMarker(markerFactory, log4jParent);
+		final Log4jMarker log4jSlf4jMarker = new Log4jMarker(markerFactory, log4jMarker);
+		final org.slf4j.Marker nullMarker = null;
+		Assert.assertFalse(log4jSlf4jParent.remove(nullMarker));
+		Assert.assertFalse(log4jSlf4jMarker.remove(nullMarker));
+	}
+
+}
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/OverflowTest.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/OverflowTest.java
new file mode 100644
index 0000000000..bcb9d0b669
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/OverflowTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.slf4j;
+
+import org.apache.logging.log4j.LoggingException;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.fail;
+
+/**
+ * Tests StackOverflow when slf4j-impl and to-slf4j are both present.
+ */
+public class OverflowTest {
+
+    @Test
+    public void log() {
+        try {
+            final Logger logger = LoggerFactory.getLogger(OverflowTest.class);
+            fail("Failed to detect inclusion of log4j-to-slf4j");
+        } catch (LoggingException ex) {
+            // Expected exception.
+        } catch (StackOverflowError error) {
+            fail("Failed to detect inclusion of log4j-to-slf4j, caught StackOverflowError");
+        }
+    }
+
+}
diff --git a/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.java b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.java
new file mode 100644
index 0000000000..d3d3db6c03
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.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.slf4j;
+
+import java.io.Serializable;
+
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.logging.log4j.SerializableMatchers.serializesRoundTrip;
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class SerializeTest {
+
+    private static final String CONFIG = "log4j-test1.xml";
+
+    @ClassRule
+    public static final LoggerContextRule CTX = new LoggerContextRule(CONFIG);
+
+    Logger logger = LoggerFactory.getLogger("LoggerTest");
+
+    @Test
+    public void testLogger() throws Exception {
+        assertThat((Serializable) logger, serializesRoundTrip());
+    }
+}
diff --git a/log4j-slf4j20-impl/src/test/resources/log4j-test1.xml b/log4j-slf4j20-impl/src/test/resources/log4j-test1.xml
new file mode 100644
index 0000000000..07a2be6316
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/resources/log4j-test1.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration status="error" name="LoggerTest">
+  <properties>
+    <property name="filename">target/test.log</property>
+  </properties>
+  <ThresholdFilter level="trace"/>
+
+  <Appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%C{1.} %m MDC%X%n"/>
+    </Console>
+    <File name="File" fileName="${filename}">
+      <PatternLayout>
+        <pattern>%d %p %C{1.} [%t] %m%n</pattern>
+      </PatternLayout>
+    </File>
+    <List name="List">
+      <PatternLayout pattern="%C{1.} %m MDC%X%n%ex{0}"/>
+    </List>
+    <SLF4J name="SLF4J"/>
+  </Appenders>
+
+  <Loggers>
+    <Logger name="org.apache.logging.log4j.test2" level="debug" additivity="false">
+      <AppenderRef ref="File"/>
+    </Logger>
+
+    <Root level="trace">
+      <AppenderRef ref="List"/>
+    </Root>
+  </Loggers>
+
+</configuration>
diff --git a/log4j-slf4j20-impl/src/test/resources/log4j2-1482.xml b/log4j-slf4j20-impl/src/test/resources/log4j2-1482.xml
new file mode 100644
index 0000000000..e17953ca93
--- /dev/null
+++ b/log4j-slf4j20-impl/src/test/resources/log4j2-1482.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="warn" name="MyApp" packages="">
+  <Properties>
+    <Property name="audit-path">target/log4j2-1482</Property>
+    <Property name="file-name">audit</Property>
+    <Property name="file-header">param1,param2,param3${sys:line.separator}
+    </Property>
+  </Properties>
+
+  <Appenders>
+    <RollingFile name="auditfile" fileName="${audit-path}/${file-name}.tmp"
+      filePattern="${audit-path}/${file-name}-%d{yyyy-MM-dd}-%i.csv">
+      <CsvParameterLayout delimiter="," header="${file-header}">
+      </CsvParameterLayout>
+      <Policies>
+        <SizeBasedTriggeringPolicy size="80 B" />
+      </Policies>
+      <DefaultRolloverStrategy max="2" />
+    </RollingFile>
+  </Appenders>
+
+  <Loggers>
+    <Root level="info">
+      <AppenderRef ref="auditfile" />
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 11ccfd43da..e816010853 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1621,6 +1621,7 @@
     <module>log4j-1.2-api</module>
     <module>log4j-slf4j-impl</module>
     <module>log4j-slf4j18-impl</module>
+    <module>log4j-slf4j20-impl</module>
     <module>log4j-to-slf4j</module>
     <module>log4j-to-jul</module>
     <module>log4j-jcl</module>