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/08/26 19:32:14 UTC

[logging-log4j2] branch release-2.x updated: [LOG4J2-3370] Initial SLF4J 2.0.x support (#1023)

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

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


The following commit(s) were added to refs/heads/release-2.x by this push:
     new 73db342e91 [LOG4J2-3370] Initial SLF4J 2.0.x support (#1023)
73db342e91 is described below

commit 73db342e9116044acad5ad649f753cb385c5395f
Author: Piotr P. Karwasz <pi...@karwasz.org>
AuthorDate: Fri Aug 26 21:32:08 2022 +0200

    [LOG4J2-3370] Initial SLF4J 2.0.x support (#1023)
    
    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  |  83 ++++
 .../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, 2232 insertions(+)

diff --git a/log4j-slf4j20-impl/pom.xml b/log4j-slf4j20-impl/pom.xml
new file mode 100644
index 0000000000..5f72a38614
--- /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.18.1-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>/slf4j20</projectDir>
+    <slf4j.version>2.0.0</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..11f52de5b0
--- /dev/null
+++ b/log4j-slf4j20-impl/src/main/java/org/apache/logging/slf4j/Log4jMDCAdapter.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.slf4j;
+
+import java.util.Deque;
+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);
+    }
+
+    @Override
+    public void pushByKey(String key, String value) {
+        // not implemented yet
+    }
+
+    @Override
+    public String popByKey(String key) {
+        // not implemented yet
+        return null;
+    }
+
+    @Override
+    public Deque<String> getCopyOfDequeByKey(String key) {
+        // not implemented yet
+        return null;
+    }
+
+    @Override
+    public void clearDequeByKey(String key) {
+        // not implemented yet
+    }
+}
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 ab737f7a56..5fe11b79d3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1726,6 +1726,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>