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