Compare commits

..

No commits in common. "master" and "v_2.1.0-alpha0" have entirely different histories.

72 changed files with 893 additions and 1426 deletions

View File

@ -1,22 +0,0 @@
# Agent Rules
**Never commit or push changes.**
### Strict Rules:
- Do not run `git commit`, `git push`, `git add`, or any git command
that modifies the repository history.
- You may edit files multiple times in one session.
- You may run tests, build commands, invoke linters to validate
changes or check your work as needed.
- If you believe a commit or any other git action is needed, ask me
first.
- The code is widely used. Thus, any changes must preserve backward
compatibility, especially changes in interfaces or super classes.
Follow these rules at all times.

View File

@ -2,33 +2,31 @@
The Simple Logging Facade for Java (SLF4J) serves as a simple facade The Simple Logging Facade for Java (SLF4J) serves as a simple facade
or abstraction for various logging frameworks (e.g. java.util.logging, or abstraction for various logging frameworks (e.g. java.util.logging,
logback, reload4j, log4j 2.x, logevents, penna, rainbowgum, tinylog) logback, reload4j, log4j 2.x) allowing the end user to plug in the desired logging
allowing the end user to plug in the desired logging framework at framework at deployment time.
deployment time.
More information can be found on the [SLF4J website](http://www.slf4j.org). More information can be found on the [SLF4J website](http://www.slf4j.org).
# Build Status
[![Build Status](https://travis-ci.org/qos-ch/slf4j.svg)](https://travis-ci.org/qos-ch/slf4j)
# Search org.slf4j artifacts on Maven Central # Search org.slf4j artifacts on Maven Central
[![Maven Central](https://img.shields.io/badge/Search%20org%2Eslf4j%20artifacts%20on%20Maven%20Central-2.0.x-green)](https://central.sonatype.com/search?namespace=org.slf4j) [![Maven Central](https://img.shields.io/badge/Search%20org%2Eslf4j%20artifacts%20on%20Maven%20Central-2.0.x-green)](https://search.maven.org/search?q=g:org.slf4j%20AND%20v:2.0.%3F)
# In case of problems # In case of problems
In case of problems please do not hesitate to post an e-mail message In case of problems please do not hesitate to post an e-mail message
on the [slf4j-user@qos.ch](https://mailman.qos.ch/cgi-bin/mailman/listinfo/slf4j-user) on the slf4j-user@qos.ch mailing list. However, please do not
mailing list or to start a <a directly e-mail SLF4J developers. The answer to your question might
href="https://github.com/qos-ch/slf4j/discussions">discussion</a> on be useful to other users. Moreover, there are many knowledgeable users
github. However, please do not directly e-mail SLF4J developers. The on the slf4j-user mailing lists who can quickly answer your
answer to your question might be useful to other users. Moreover, questions.
there are many knowledgeable users on the slf4j-user mailing lists who
can quickly answer your questions.
# Urgent issues # Urgent issues
For urgent issues do not hesitate to [champion a For urgent issues do not hesitate to [champion a release](https://github.com/sponsors/qos-ch/sponsorships?tier_id=77436).
release](https://github.com/sponsors/qos-ch/sponsorships?tier_id=77436). In principle, most championed issues are solved within 3 business days ensued by a release.
In principle, most championed issues are solved within 3 business days
ensued by a release.
# How to build SLF4J # How to build SLF4J
@ -45,13 +43,14 @@ process:
1. Start a discussion on the [slf4j-dev mailing 1. Start a discussion on the [slf4j-dev mailing
list](http://www.slf4j.org/mailing-lists.html) about your proposed list](http://www.slf4j.org/mailing-lists.html) about your proposed
change. Alternately, file a [bug change. Alternately, file a [bug
report](https://github.com/qos-ch/slf4j/issues) on github to initiate the report](http://www.slf4j.org/bug-reporting.html) to initiate the
discussion. discussion. Note that we ask pull requests to be linked to a [Jira
ticket](https://jira.qos.ch/).
2. Fork qos-ch/slf4j. Ideally, create a new branch from your fork for 2. Fork qos-ch/slf4j. Ideally, create a new branch from your fork for
your contribution to make it easier to merge your changes back. your contribution to make it easier to merge your changes back.
3. Make your changes on the branch created in Step 2. Be 3. Make your changes on the branch you hopefully created in Step 2. Be
sure that your code passes existing unit tests. Please add unit tests sure that your code passes existing unit tests. Please add unit tests
for your work if appropriate. It usually is. for your work if appropriate. It usually is.
@ -62,8 +61,10 @@ will be automatically rejected by the [DCO GitHub
check](https://probot.github.io/apps/dco/) application. check](https://probot.github.io/apps/dco/) application.
5. Push your changes to your fork/branch in GitHub. Don't push it to 5. Push your changes to your fork/branch in GitHub. Don't push it to
your master! If you do, it will make it harder to submit new changes your master! If you do it will make it harder to submit new changes
later. later.
6. Submit a pull request to SLF4J from your commit page on GitHub. 6. Submit a pull request to SLF4J from your commit page on GitHub.
7. Did we mention that you will be asked to link your pull request
with a Jira ticket?

View File

@ -82,12 +82,12 @@
</target> </target>
<target name="testAll" depends="init, <target name="testAll" depends="init,
testNoProvider150, testNoProvider150,
testMismatch, testMismatch,
testMatch, testMatch,
testMultiBinding, testMultiBinding,
testFuture_16Series" testFuture_16Series,
> testActiveSecurityManager">
</target> </target>
@ -201,7 +201,7 @@
<property name="path_to_policy" value="file:./src/policy/java-under-ant.policy"/> <property name="path_to_policy" value="file:./src/policy/java-under-ant.policy"/>
</target> </target>
<!-- no longer supported in JDK 24 and later -->
<target name="testActiveSecurityManager" depends="setPathToPolicy_FromTop, setPathToPolicy_FromIntegration"> <target name="testActiveSecurityManager" depends="setPathToPolicy_FromTop, setPathToPolicy_FromIntegration">
<junit printsummary="yes" fork="no" haltonfailure="yes"> <junit printsummary="yes" fork="no" haltonfailure="yes">
<jvmarg value="-Djava.security.manager"/> <jvmarg value="-Djava.security.manager"/>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>

View File

@ -27,7 +27,6 @@ package org.slf4j;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.slf4j.helpers.Reporter.SLF4J_INTERNAL_VERBOSITY_KEY;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.Random; import java.util.Random;
@ -44,13 +43,11 @@ public class CompatibilityAssertionTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
System.setProperty(SLF4J_INTERNAL_VERBOSITY_KEY, "debug");
System.setErr(sps); System.setErr(sps);
} }
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
System.clearProperty(SLF4J_INTERNAL_VERBOSITY_KEY);
System.setErr(old); System.setErr(old);
} }
@ -60,10 +57,8 @@ public class CompatibilityAssertionTest {
String msg = "hello world " + diff; String msg = "hello world " + diff;
logger.info(msg); logger.info(msg);
assertEquals(2, sps.stringList.size()); assertEquals(2, sps.stringList.size());
String s0 = (String) sps.stringList.get(0); String s0 = (String) sps.stringList.get(0);
assertTrue(s0.startsWith("SLF4J(D): Connected with provider of type [org.slf4j.simple.SimpleServiceProvider]")); assertTrue(s0.startsWith("SLF4J(I): Connected with provider of type [org.slf4j.simple.SimpleServiceProvider"));
String s1 = (String) sps.stringList.get(1); String s1 = (String) sps.stringList.get(1);
assertTrue(s1.contains(msg)); assertTrue(s1.contains(msg));

View File

@ -55,12 +55,11 @@ public class MultiBindingAssertionTest {
String msg = "hello world " + diff; String msg = "hello world " + diff;
logger.info(msg); logger.info(msg);
List<String> list = sps.stringList; List<String> list = sps.stringList;
int line = 0; assertMsgContains(list, 0, "Class path contains multiple SLF4J providers.");
assertMsgContains(list, 1, "Found provider");
assertMsgContains(list, line++, "Class path contains multiple SLF4J providers."); assertMsgContains(list, 2, "Found provider");
assertMsgContains(list, line++, "Found provider"); assertMsgContains(list, 3, "See https://www.slf4j.org/codes.html#multiple_bindings for an explanation.");
assertMsgContains(list, line++, "Found provider"); assertMsgContains(list, 4, "SLF4J(I): Connected with provider of type [org.slf4j.simple.SimpleServiceProvider");
assertMsgContains(list, line++, "See https://www.slf4j.org/codes.html#multiple_bindings for an explanation.");
} }
void assertMsgContains(List<String> strList, int index, String msg) { void assertMsgContains(List<String> strList, int index, String msg) {

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -26,6 +26,7 @@
</licenses> </licenses>
<properties> <properties>
</properties> </properties>
<dependencies> <dependencies>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -19,7 +19,7 @@
<licenses> <licenses>
<license> <license>
<name>Apache-2.0</name> <name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url> <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution> <distribution>repo</distribution>
</license> </license>

0
jcl-over-slf4j/src/main/java/module-info.java Normal file → Executable file
View File

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -26,6 +26,7 @@
</licenses> </licenses>
<properties> <properties>
</properties> </properties>
<dependencies> <dependencies>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -26,6 +26,7 @@
</licenses> </licenses>
<properties> <properties>
</properties> </properties>
<dependencies> <dependencies>

View File

@ -0,0 +1,137 @@
<project name="testing-log4j-bridge" default="usage" basedir=".">
<property name="lbversion" value="0.9.8-SNAPSHOT" />
<property name="slf4jversion" value="1.4.2" />
<property name="source.home" value="./src/main/java/" />
<property name="javac.dest.12" value="./target/classes12/" />
<property name="javac.dest.13" value="./target/classes13/" />
<property name="lib" value="./lib" />
<property name="deprecation" value="on" />
<path id="basic.classpath">
<pathelement location="${source.home}" />
<pathelement location="${lib}/junit-3.8.1.jar" />
</path>
<path id="log4j12.classpath">
<path refid="basic.classpath" />
<pathelement location="${javac.dest.12}" />
<pathelement location="${lib}/log4j-1.2.14.jar" />
</path>
<path id="log4j13.classpath">
<path refid="basic.classpath" />
<pathelement location="${javac.dest.13}" />
<pathelement location="${lib}/log4j-1.3alpha-8.jar" />
</path>
<path id="los.classpath">
<path refid="basic.classpath" />
<pathelement location="${lib}/log4j-over-slf4j-${slf4jversion}.jar" />
<pathelement location="${lib}/logback-classic-${lbversion}.jar" />
<pathelement location="${lib}/logback-core-${lbversion}.jar" />
<pathelement location="${lib}/slf4j-api-${slf4jversion}.jar" />
</path>
<!-- ================================================================= -->
<!-- Default target -->
<!-- ================================================================= -->
<target name="usage">
<echo>
These are some of the targets supported by this ANT build script:
all - run all available tests
refresh - copy required jar files to the lib directory
</echo>
</target>
<delete>
<fileset dir="." includes="**/*.bak"/>
</delete>
<target name="refresh">
<delete>
<fileset dir="lib">
<include name="logback-*.jar"/>
<include name="log4j-bridge-*.jar"/>
</fileset>
</delete>
<copy file="../../slf4j-api/target/slf4j-api-${slf4jversion}.jar" todir="lib/"/>
<copy file="../target/log4j-over-slf4j-${slf4jversion}.jar" todir="lib/"/>
</target>
<target name="init">
<mkdir dir="${javac.dest.12}" />
<mkdir dir="${javac.dest.13}" />
</target>
<target name="clean">
<delete>
<fileset dir="${javac.dest.12}" includes="**" />
<fileset dir="${javac.dest.13}" includes="**" />
</delete>
</target>
<target name="build_log4j12" depends="init">
<javac srcdir="${source.home}"
destdir="${javac.dest.12}"
includes="**/Log4j12Calls.java"
deprecation="${deprecation}" debug="on">
<classpath refid="log4j12.classpath" />
</javac>
</target>
<target name="build_log4j13" depends="init">
<javac srcdir="${source.home}"
destdir="${javac.dest.13}"
includes="**/Log4j13Calls.java" deprecation="${deprecation}" debug="on">
<classpath refid="log4j13.classpath" />
</javac>
</target>
<target name="build_loggerTest" depends="init">
<javac srcdir="${source.home}"
destdir="${javac.dest.12}"
includes="**/LoggerTest.java"
deprecation="${deprecation}" debug="on">
<classpath refid="los.classpath" />
</javac>
</target>
<!-- ================================================================= -->
<!-- Run tests -->
<!-- ================================================================= -->
<target name="all" depends="test12, test13, loggerTest" />
<target name="loggerTest" depends="build_loggerTest">
<junit printsummary="yes" fork="yes" haltonfailure="yes">
<classpath refid="los.classpath" />
<classpath location="${javac.dest.12}" />
<formatter type="plain" usefile="false" />
<test name="test.LoggerTest" />
</junit>
</target>
<target name="test12" depends="build_log4j12">
<junit printsummary="yes" fork="yes" haltonfailure="yes">
<classpath refid="los.classpath" />
<classpath location="${javac.dest.12}" />
<formatter type="plain" usefile="false" />
<test name="test.Log4j12Calls" />
</junit>
</target>
<target name="test13" depends="build_log4j13">
<junit printsummary="yes" fork="yes" haltonfailure="yes">
<classpath refid="los.classpath" />
<classpath location="${javac.dest.13}" />
<formatter type="plain" usefile="false" />
<test name="test.Log4j13Calls" />
</junit>
</target>
</project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,17 @@
This directory is used to test the module against various log4j calls.
Two test cases simulate the typical calls that one can find in an application
that uses either log4j 1.2.x, or log4j 1.3.x.
In the same directory is a build.xml file that uses ant to
compile the test cases with the corresponding log4j version,
and to run these tests without log4j in the classpath but with
logback jars instead.
To run the tests, one must have ant installed. Issuing the following command,
once in the compatibility directory will launch the tests:
ant all
To obtain more information about the use of the log4j-over-slf4j module,
please visit http://www.slf4j.org/log4j-over-slf4j.html

View File

@ -0,0 +1,8 @@
package test;
public class DummyObject {
public String toString() {
return "dummy";
}
}

View File

@ -0,0 +1,39 @@
/**
* Logback: the reliable, generic, fast and flexible logging framework.
*
* Copyright (C) 1999-2006, QOS.ch
*
* This library is free software, you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation.
*/
package test;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
/**
*
* A test case that issues the typical calls
* that an application using log4j 1.2 would do.
*
* @author Ceki G&uuml;lc&uuml;
* @author S&eacute;bastien Pennec
*/
public class Log4j12Calls extends TestCase {
public static final Logger logger = Logger.getLogger(Log4j12Calls.class);
public void testLog() {
MDC.put("key", "value1");
logger.trace("Trace level can be noisy");
logger.debug("Entering application");
logger.info("Violets are blue");
logger.warn("Here is a warning");
logger.error("Exiting application", new Exception("just testing"));
MDC.remove("key");
}
}

View File

@ -0,0 +1,46 @@
/**
* Logback: the reliable, generic, fast and flexible logging framework.
*
* Copyright (C) 1999-2006, QOS.ch
*
* This library is free software, you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation.
*/
package test;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
/**
*
* A test case that issues the typical calls
* that an application using log4j 1.3 would do.
*
* @author Ceki G&uuml;lc&uuml;
* @author S&eacute;bastien Pennec
*/
public class Log4j13Calls extends TestCase {
public static final Logger logger = Logger.getLogger(Log4j12Calls.class);
public void testLog() {
MDC.put("key", "value1");
logger.trace("Trace level can be noisy");
logger.debug("Entering application");
logger.info("Violets are blue");
logger.warn("Here is a warning");
logger.info("The answer is {}.", new Integer(42));
logger.info("Number: {} and another one: {}.", new Integer(42), new Integer(24));
logger.error("Exiting application", new Exception("just testing"));
MDC.remove("key");
MDC.clear();
}
}

View File

@ -0,0 +1,169 @@
package test;
import junit.framework.TestCase;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import org.apache.log4j.Level;
/**
* A class that tests the invocation of the org.apache.log4j.Logger class that
* belongs to the log4j-bridge package
*
* @author S&eacute;bastien Pennec
* @author Ceki G&uuml;lc&uuml;
*/
public class LoggerTest extends TestCase {
LoggerContext context;
ListAppender<LoggingEvent> appender;
ch.qos.logback.classic.Logger logbackLogger;
org.apache.log4j.Logger log4jLogger;
public void setUp() throws Exception {
context = (LoggerContext) LoggerFactory.getILoggerFactory();
context.shutdownAndReset();
appender = new ListAppender<LoggingEvent>();
appender.setContext(context);
appender.setName("listAppender");
appender.start();
ch.qos.logback.classic.Logger lbLogger = context
.getLogger(LoggerContext.ROOT_NAME);
lbLogger.addAppender(appender);
log4jLogger = org.apache.log4j.Logger.getLogger(LoggerTest.class);
logbackLogger = context.getLogger(LoggerTest.class);
super.setUp();
}
public void tearDown() throws Exception {
appender.stop();
context.stop();
appender = null;
context = null;
logbackLogger = null;
log4jLogger = null;
super.tearDown();
}
public void testLogWithObjectMessages() {
LoggingEvent event;
log4jLogger.debug("test");
event = appender.list.get(0);
assertEquals("test", event.getMessage());
appender.list.clear();
log4jLogger.debug(null);
event = appender.list.get(0);
assertEquals(null, event.getMessage());
appender.list.clear();
DummyObject dummy = new DummyObject();
log4jLogger.debug(dummy);
event = appender.list.get(0);
assertEquals(dummy.toString(), event.getMessage());
appender.list.clear();
}
public void testIsEnabledAPI() {
assertFalse(log4jLogger.isTraceEnabled());
assertTrue(log4jLogger.isDebugEnabled());
assertTrue(log4jLogger.isInfoEnabled());
assertTrue(log4jLogger.isWarnEnabled());
assertTrue(log4jLogger.isErrorEnabled());
}
public void testPrintAPI() {
Exception e = new Exception("just testing");
log4jLogger.trace(null);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.debug(null);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.debug("debug message");
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.info(null);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.info("info message");
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.warn(null);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.warn("warn message");
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.error(null);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.error("error message");
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.debug(null, e);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.debug("debug message", e);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.info(null, e);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.info("info message", e);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.warn(null, e);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.warn("warn message", e);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.error(null, e);
assertEquals(1, appender.list.size());
appender.list.clear();
log4jLogger.error("error message", e);
assertEquals(1, appender.list.size());
appender.list.clear();
}
public void testLogAPI() {
log4jLogger.log("x", Level.TRACE, "x", null);
assertEquals(0, appender.list.size());
log4jLogger.log("x", Level.DEBUG, "x", null);
log4jLogger.log("x", Level.INFO, "x", null);
log4jLogger.log("x", Level.WARN, "x", null);
log4jLogger.log("x", Level.ERROR, "x", null);
log4jLogger.log("x", Level.FATAL, "x", null);
assertEquals(5, appender.list.size());
appender.list.clear();
}
}

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -21,8 +21,8 @@
<licenses> <licenses>
<license> <license>
<name>Apache-2.0</name> <name>Apache Software Licenses</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url> <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license> </license>
</licenses> </licenses>

0
log4j-over-slf4j/src/main/java/module-info.java Normal file → Executable file
View File

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-bom</artifactId> <artifactId>slf4j-bom</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
@ -26,13 +26,12 @@
<properties> <properties>
<!-- yyyy-MM-dd'T'HH:mm:ss'Z' --> <!-- yyyy-MM-dd'T'HH:mm:ss'Z' -->
<project.build.outputTimestamp>2026-08-07T12:57:07Z</project.build.outputTimestamp> <project.build.outputTimestamp>2023-12-28T19:21:00Z</project.build.outputTimestamp>
<latest.1.version>1.7.36</latest.1.version> <latest.1.version>1.7.36</latest.1.version>
<!-- java.util.ServiceLoader requires Java 6 --> <!-- java.util.ServiceLoader requires Java 6 -->
<jdk.version>11</jdk.version> <jdk.version>11</jdk.version>
<maven.compiler.source>${jdk.version}</maven.compiler.source> <maven.compiler.source>${jdk.version}</maven.compiler.source>
<maven.compiler.target>${jdk.version}</maven.compiler.target> <maven.compiler.target>${jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.resourceEncoding>UTF-8</project.build.resourceEncoding> <project.build.resourceEncoding>UTF-8</project.build.resourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@ -96,10 +95,8 @@
<filtering>true</filtering> <filtering>true</filtering>
</resource> </resource>
<!-- Use each module's own LICENSE.txt (e.g. Apache-2.0 for jcl-over-slf4j
and log4j-over-slf4j) rather than the repo-root MIT LICENSE. -->
<resource> <resource>
<directory>${project.basedir}</directory> <directory>..</directory>
<targetPath>META-INF</targetPath> <targetPath>META-INF</targetPath>
<includes> <includes>
<include>LICENSE.txt</include> <include>LICENSE.txt</include>

62
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-bom</artifactId> <artifactId>slf4j-bom</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<url>http://www.slf4j.org</url> <url>http://www.slf4j.org</url>
@ -16,8 +16,8 @@
<licenses> <licenses>
<license> <license>
<name>MIT</name> <name>MIT License</name>
<url>https://opensource.org/license/mit</url> <url>http://www.opensource.org/licenses/mit-license.php</url>
<distribution>repo</distribution> <distribution>repo</distribution>
</license> </license>
</licenses> </licenses>
@ -166,68 +166,16 @@
<configuration> <configuration>
<verbose>true</verbose> <verbose>true</verbose>
<skippedModules> <skippedModules>
slf4j-testing,slf4j-jdk-platform-logging,jcl-over-slf4j-blackbox,log4j-over-slf4j-blackbox,jul-to-slf4j-blackbox,slf4j-migrator,osgi-over-slf4j slf4j-testing,slf4j-ext,log4j-over-slf4j,log4j-over-slf4j-blackbox,jul-to-slf4j-blackbox,slf4j-migrator,osgi-over-slf4j
</skippedModules> </skippedModules>
<detectLinks>true</detectLinks> <detectLinks>true</detectLinks>
<doctitle>SLF4J project modules 2.1.0-alpha1</doctitle> <doctitle>SLF4J project modules 2.1.0-alpha0</doctitle>
<windowtitle>SLF4J javadoc</windowtitle> <windowtitle>SLF4J javadoc</windowtitle>
<bottom><![CDATA[Copyright &copy; 2005-{currentYear} QOS.CH Sarl. All rights reserved]]></bottom> <bottom><![CDATA[Copyright &copy; 2005-{currentYear} QOS.CH Sarl. All rights reserved]]></bottom>
<linksource>true</linksource> <linksource>true</linksource>
<additionalOptions> <additionalOptions>
<additionalOption>-Xdoclint:none</additionalOption> <additionalOption>-Xdoclint:none</additionalOption>
</additionalOptions> </additionalOptions>
<groups>
<group>
<title>SLF4J API packages</title>
<packages>org.slf4j:org.slf4j.spi:org.slf4j.event:org.slf4j.helpers</packages>
</group>
<group>
<title>slf4j-simple package</title>
<packages>org.slf4j.simple</packages>
</group>
<group>
<title>slf4j-nop package</title>
<packages>org.slf4j.nop</packages>
</group>
<group>
<title>slf4j-jdk14 package</title>
<packages>org.slf4j.jul</packages>
</group>
<group>
<title>slf4j-reload4j package</title>
<packages>org.slf4j.reload4j</packages>
</group>
<group>
<title>SLF4J extensions</title>
<packages>
org.slf4j.cal10n:org.slf4j.profiler:org.slf4j.ext:org.slf4j.instrumentation:org.slf4j.agent
</packages>
</group>
<group>
<title>Jakarta Commons Logging packages</title>
<packages>org.apache.commons.*</packages>
</group>
<group>
<title>java.util.logging (JUL) to SLF4J bridge</title>
<packages>org.slf4j.bridge</packages>
</group>
<group>
<title>log4j-over-slf4j redirection</title>
<packages>org.apache.log4j:org.apache.log4j.*</packages>
</group>
</groups>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>

View File

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <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"> 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> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -59,8 +59,7 @@
<artifactId>maven-bundle-plugin</artifactId> <artifactId>maven-bundle-plugin</artifactId>
<configuration> <configuration>
<instructions> <instructions>
<Import-Package>org.slf4j.spi;version="${range;[===,+);${version_cleanup;${project.version}}}" <Import-Package>org.slf4j.spi;version="${range;[===,+);${version_cleanup;${project.version}}}"</Import-Package>
</Import-Package>
<!-- Export the client/user package of slf4j-api version 1 to make the slf4j-api bundle in version 2 usable for bundles that only import slf4j-1.x --> <!-- Export the client/user package of slf4j-api version 1 to make the slf4j-api bundle in version 2 usable for bundles that only import slf4j-1.x -->
<_exportcontents><![CDATA[ <_exportcontents><![CDATA[
*,\ *,\
@ -76,6 +75,7 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -47,7 +47,6 @@ import org.slf4j.helpers.Reporter;
import org.slf4j.helpers.SubstituteLogger; import org.slf4j.helpers.SubstituteLogger;
import org.slf4j.helpers.SubstituteServiceProvider; import org.slf4j.helpers.SubstituteServiceProvider;
import org.slf4j.helpers.Util; import org.slf4j.helpers.Util;
import org.slf4j.spi.MDCAdapter;
import org.slf4j.spi.SLF4JServiceProvider; import org.slf4j.spi.SLF4JServiceProvider;
/** /**
@ -196,7 +195,6 @@ public final class LoggerFactory {
reportMultipleBindingAmbiguity(providersList); reportMultipleBindingAmbiguity(providersList);
if (providersList != null && !providersList.isEmpty()) { if (providersList != null && !providersList.isEmpty()) {
PROVIDER = providersList.get(0); PROVIDER = providersList.get(0);
earlyBindMDCAdapter();
// SLF4JServiceProvider.initialize() is intended to be called here and nowhere else. // SLF4JServiceProvider.initialize() is intended to be called here and nowhere else.
PROVIDER.initialize(); PROVIDER.initialize();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION; INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
@ -217,19 +215,6 @@ public final class LoggerFactory {
} }
} }
/**
* The value of PROVIDER.getMDCAdapter() can be null while PROVIDER has not yet initialized.
*
* However, SLF4JServiceProvider implementations are expected to initialize their internal
* MDCAdapter field in their constructor or on field declaration.
*/
private static void earlyBindMDCAdapter() {
MDCAdapter mdcAdapter = PROVIDER.getMDCAdapter();
if(mdcAdapter != null) {
MDC.setMDCAdapter(mdcAdapter);
}
}
static SLF4JServiceProvider loadExplicitlySpecified(ClassLoader classLoader) { static SLF4JServiceProvider loadExplicitlySpecified(ClassLoader classLoader) {
String explicitlySpecified = System.getProperty(PROVIDER_PROPERTY_KEY); String explicitlySpecified = System.getProperty(PROVIDER_PROPERTY_KEY);
if (null == explicitlySpecified || explicitlySpecified.isEmpty()) { if (null == explicitlySpecified || explicitlySpecified.isEmpty()) {
@ -421,16 +406,9 @@ public final class LoggerFactory {
} }
private static void reportActualBinding(List<SLF4JServiceProvider> providerList) { private static void reportActualBinding(List<SLF4JServiceProvider> providerList) {
// impossible since a provider has been found if (!providerList.isEmpty()) {
if (providerList.isEmpty()) {
throw new IllegalStateException("No providers were found which is impossible after successful initialization.");
}
if (isAmbiguousProviderList(providerList)) {
Reporter.info("Actual provider is of type [" + providerList.get(0) + "]");
} else {
SLF4JServiceProvider provider = providerList.get(0); SLF4JServiceProvider provider = providerList.get(0);
Reporter.debug(CONNECTED_WITH_MSG + provider.getClass().getName() + "]"); Reporter.info(CONNECTED_WITH_MSG + provider.getClass().getName() + "]");
} }
} }

View File

@ -28,7 +28,10 @@ import java.io.Closeable;
import java.util.Deque; import java.util.Deque;
import java.util.Map; import java.util.Map;
import org.slf4j.helpers.*; import org.slf4j.helpers.BasicMDCAdapter;
import org.slf4j.helpers.NOPMDCAdapter;
import org.slf4j.helpers.Reporter;
import org.slf4j.helpers.Util;
import org.slf4j.spi.MDCAdapter; import org.slf4j.spi.MDCAdapter;
import org.slf4j.spi.SLF4JServiceProvider; import org.slf4j.spi.SLF4JServiceProvider;
@ -63,9 +66,9 @@ import org.slf4j.spi.SLF4JServiceProvider;
public class MDC { public class MDC {
static final String NULL_MDCA_URL = "http://www.slf4j.org/codes.html#null_MDCA"; static final String NULL_MDCA_URL = "http://www.slf4j.org/codes.html#null_MDCA";
private static final String MDC_ADAPTER_CANNOT_BE_NULL_MESSAGE = "MDCAdapter cannot be null. See also " + NULL_MDCA_URL; private static final String MDC_APAPTER_CANNOT_BE_NULL_MESSAGE = "MDCAdapter cannot be null. See also " + NULL_MDCA_URL;
static final String NO_STATIC_MDC_BINDER_URL = "http://www.slf4j.org/codes.html#no_static_mdc_binder"; static final String NO_STATIC_MDC_BINDER_URL = "http://www.slf4j.org/codes.html#no_static_mdc_binder";
static MDCAdapter MDC_ADAPTER; static MDCAdapter mdcAdapter;
/** /**
* An adapter to remove the key when done. * An adapter to remove the key when done.
@ -85,30 +88,14 @@ public class MDC {
private MDC() { private MDC() {
} }
private static MDCAdapter getMDCAdapterGivenByProvider() { static {
SLF4JServiceProvider provider = LoggerFactory.getProvider(); SLF4JServiceProvider provider = LoggerFactory.getProvider();
if(provider != null) { if (provider != null) {
// If you wish to change the mdc adapter, setting the MDC.MDCAdapter variable might be insufficient. mdcAdapter = provider.getMDCAdapter();
// Keep in mind that the provider *might* perform additional internal mdcAdapter assignments that
// you would also need to replicate/adapt.
// obtain and attach the MDCAdapter from the provider
final MDCAdapter anAdapter = provider.getMDCAdapter();
emitTemporaryMDCAdapterWarningIfNeeded(provider);
return anAdapter;
} else { } else {
Reporter.error("Failed to find provider."); Reporter.error("Failed to find provider.");
Reporter.error("Defaulting to no-operation MDCAdapter implementation."); Reporter.error("Defaulting to no-operation MDCAdapter implementation.");
return new NOPMDCAdapter(); mdcAdapter = new NOPMDCAdapter();
}
}
private static void emitTemporaryMDCAdapterWarningIfNeeded(SLF4JServiceProvider provider) {
boolean isSubstitute = provider instanceof SubstituteServiceProvider;
if(isSubstitute) {
Reporter.info("Temporary mdcAdapter given by SubstituteServiceProvider.");
Reporter.info("This mdcAdapter will be replaced after backend initialization has completed.");
} }
} }
@ -131,10 +118,10 @@ public class MDC {
if (key == null) { if (key == null) {
throw new IllegalArgumentException("key parameter cannot be null"); throw new IllegalArgumentException("key parameter cannot be null");
} }
if (getMDCAdapter() == null) { if (mdcAdapter == null) {
throw new IllegalStateException(MDC_ADAPTER_CANNOT_BE_NULL_MESSAGE); throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
} }
getMDCAdapter().put(key, val); mdcAdapter.put(key, val);
} }
/** /**
@ -187,8 +174,10 @@ public class MDC {
throw new IllegalArgumentException("key parameter cannot be null"); throw new IllegalArgumentException("key parameter cannot be null");
} }
mdcAdapterNullCheck(); if (mdcAdapter == null) {
return getMDCAdapter().get(key); throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
return mdcAdapter.get(key);
} }
/** /**
@ -206,16 +195,20 @@ public class MDC {
throw new IllegalArgumentException("key parameter cannot be null"); throw new IllegalArgumentException("key parameter cannot be null");
} }
mdcAdapterNullCheck(); if (mdcAdapter == null) {
getMDCAdapter().remove(key); throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
mdcAdapter.remove(key);
} }
/** /**
* Clear all entries in the MDC of the underlying implementation. * Clear all entries in the MDC of the underlying implementation.
*/ */
public static void clear() { public static void clear() {
mdcAdapterNullCheck(); if (mdcAdapter == null) {
getMDCAdapter().clear(); throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
mdcAdapter.clear();
} }
/** /**
@ -226,8 +219,10 @@ public class MDC {
* @since 1.5.1 * @since 1.5.1
*/ */
public static Map<String, String> getCopyOfContextMap() { public static Map<String, String> getCopyOfContextMap() {
mdcAdapterNullCheck(); if (mdcAdapter == null) {
return getMDCAdapter().getCopyOfContextMap(); throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
return mdcAdapter.getCopyOfContextMap();
} }
/** /**
@ -242,38 +237,23 @@ public class MDC {
* @since 1.5.1 * @since 1.5.1
*/ */
public static void setContextMap(Map<String, String> contextMap) { public static void setContextMap(Map<String, String> contextMap) {
mdcAdapterNullCheck(); if (mdcAdapter == null) {
getMDCAdapter().setContextMap(contextMap); throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
mdcAdapter.setContextMap(contextMap);
} }
/** /**
* Returns the MDCAdapter instance currently in use. * Returns the MDCAdapter instance currently in use.
* *
* Since 2.0.17, if the MDCAdapter instance is null, then this method set it to use
* the adapter returned by the SLF4JProvider. However, in the vast majority of cases
* the MDCAdapter will be set earlier (during initialization) by {@link LoggerFactory}.
*
* @return the MDcAdapter instance currently in use. * @return the MDcAdapter instance currently in use.
* @since 1.4.2 * @since 1.4.2
*/ */
public static MDCAdapter getMDCAdapter() { public static MDCAdapter getMDCAdapter() {
if(MDC_ADAPTER == null) { return mdcAdapter;
MDC_ADAPTER = getMDCAdapterGivenByProvider();
}
return MDC_ADAPTER;
} }
/**
* Set MDCAdapter instance to use.
*
* @since 2.0.17
*/
static void setMDCAdapter(MDCAdapter anMDCAdapter) {
if(anMDCAdapter == null) {
throw new IllegalStateException(MDC_ADAPTER_CANNOT_BE_NULL_MESSAGE);
}
MDC_ADAPTER = anMDCAdapter;
}
/** /**
* Push a value into the deque(stack) referenced by 'key'. * Push a value into the deque(stack) referenced by 'key'.
@ -283,24 +263,28 @@ public class MDC {
* @since 2.0.0 * @since 2.0.0
*/ */
static public void pushByKey(String key, String value) { static public void pushByKey(String key, String value) {
mdcAdapterNullCheck(); if (mdcAdapter == null) {
getMDCAdapter().pushByKey(key, value); throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
mdcAdapter.pushByKey(key, value);
} }
/** /**
* Pop the <b>stack</b> referenced by 'key' and return the value possibly null. * Pop the stack referenced by 'key' and return the value possibly null.
* *
* @param key identifies the deque(stack) * @param key identifies the deque(stack)
* @return the value just popped. May be null/ * @return the value just popped. May be null/
* @since 2.0.0 * @since 2.0.0
*/ */
static public String popByKey(String key) { static public String popByKey(String key) {
mdcAdapterNullCheck(); if (mdcAdapter == null) {
return getMDCAdapter().popByKey(key); throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
return mdcAdapter.popByKey(key);
} }
/** /**
* Returns a copy of the <b>deque(stack)</b> referenced by 'key'. May be null. * Returns a copy of the deque(stack) referenced by 'key'. May be null.
* *
* @param key identifies the stack * @param key identifies the stack
* @return copy of stack referenced by 'key'. May be null. * @return copy of stack referenced by 'key'. May be null.
@ -308,13 +292,9 @@ public class MDC {
* @since 2.0.0 * @since 2.0.0
*/ */
public Deque<String> getCopyOfDequeByKey(String key) { public Deque<String> getCopyOfDequeByKey(String key) {
mdcAdapterNullCheck(); if (mdcAdapter == null) {
return getMDCAdapter().getCopyOfDequeByKey(key); throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
private static void mdcAdapterNullCheck() {
if (getMDCAdapter() == null) {
throw new IllegalStateException(MDC_ADAPTER_CANNOT_BE_NULL_MESSAGE);
} }
return mdcAdapter.getCopyOfDequeByKey(key);
} }
} }

View File

@ -60,7 +60,7 @@ import java.util.concurrent.Callable;
* doSomething(); * doSomething();
* } finally { * } finally {
* // MDC remove "k0", "k1", "k2", clear the set of tracked keys * // MDC remove "k0", "k1", "k2", clear the set of tracked keys
* mdca.clear(); * mdch.clear();
* } * }
* </pre> * </pre>
* *
@ -71,7 +71,7 @@ import java.util.concurrent.Callable;
* </p> * </p>
* *
* <pre> * <pre>
* MDCAmbit mdca = new MDCAmbit(); * DCAmbit mdca = new MDCAmbit();
* Runnable runnable = ...; * Runnable runnable = ...;
* mdca.put("k0", "v0").run(runnable); * mdca.put("k0", "v0").run(runnable);
* </pre> * </pre>

View File

@ -23,10 +23,6 @@ public interface LoggingEvent {
Object[] getArgumentArray(); Object[] getArgumentArray();
/**
* List of markers in the event, might be null.
* @return markers in the event, might be null.
*/
List<Marker> getMarkers(); List<Marker> getMarkers();
List<KeyValuePair> getKeyValuePairs(); List<KeyValuePair> getKeyValuePairs();

View File

@ -3,13 +3,11 @@ package org.slf4j.helpers;
import java.io.PrintStream; import java.io.PrintStream;
/** /**
* An internally used class for reporting internal messages generated by SLF4J itself, typically * An internally used class for reporting internal messages generated by SLF4J itself during initialization.
* during initialization.
* *
* <p> * <p>
* Internal reporting is performed by calling the {@link #debug(String)}, {@link #info(String)}, * Internal reporting is performed by calling the {@link #info(String)}, {@link #warn(String)} (String)}
* {@link #warn(String)} (String)} {@link #error(String)} (String)} and * {@link #error(String)} (String)} and {@link #error(String, Throwable)} methods.
* {@link #error(String, Throwable)} methods.
* </p> * </p>
* <p>See {@link #SLF4J_INTERNAL_VERBOSITY_KEY} and {@link #SLF4J_INTERNAL_REPORT_STREAM_KEY} for * <p>See {@link #SLF4J_INTERNAL_VERBOSITY_KEY} and {@link #SLF4J_INTERNAL_REPORT_STREAM_KEY} for
* configuration options.</p> * configuration options.</p>
@ -25,7 +23,7 @@ public class Reporter {
* this class is used internally by Reporter * this class is used internally by Reporter
*/ */
private enum Level { private enum Level {
DEBUG(0), INFO(1), WARN(2), ERROR(3); INFO(1), WARN(2), ERROR(3);
int levelInt; int levelInt;
@ -42,7 +40,6 @@ public class Reporter {
Stderr, Stdout; Stderr, Stdout;
} }
static final String SLF4J_DEBUG_PREFIX = "SLF4J(D): ";
static final String SLF4J_INFO_PREFIX = "SLF4J(I): "; static final String SLF4J_INFO_PREFIX = "SLF4J(I): ";
static final String SLF4J_WARN_PREFIX = "SLF4J(W): "; static final String SLF4J_WARN_PREFIX = "SLF4J(W): ";
static final String SLF4J_ERROR_PREFIX = "SLF4J(E): "; static final String SLF4J_ERROR_PREFIX = "SLF4J(E): ";
@ -65,11 +62,11 @@ public class Reporter {
public static final String SLF4J_INTERNAL_VERBOSITY_KEY = "slf4j.internal.verbosity"; public static final String SLF4J_INTERNAL_VERBOSITY_KEY = "slf4j.internal.verbosity";
static private final TargetChoice TARGET_CHOICE = getTargetChoice(); static private final TargetChoice TARGET_CHOICE = initTargetChoice();
static private final Level INTERNAL_VERBOSITY = initVerbosity(); static private final Level INTERNAL_VERBOSITY = initVerbosity();
static private TargetChoice getTargetChoice() { static private TargetChoice initTargetChoice() {
String reportStreamStr = System.getProperty(SLF4J_INTERNAL_REPORT_STREAM_KEY); String reportStreamStr = System.getProperty(SLF4J_INTERNAL_REPORT_STREAM_KEY);
if(reportStreamStr == null || reportStreamStr.isEmpty()) { if(reportStreamStr == null || reportStreamStr.isEmpty()) {
@ -91,10 +88,6 @@ public class Reporter {
return Level.INFO; return Level.INFO;
} }
if(verbosityStr.equalsIgnoreCase("DEBUG")) {
return Level.DEBUG;
}
if(verbosityStr.equalsIgnoreCase("ERROR")) { if(verbosityStr.equalsIgnoreCase("ERROR")) {
return Level.ERROR; return Level.ERROR;
} }
@ -104,7 +97,6 @@ public class Reporter {
return Level.WARN; return Level.WARN;
} }
// anything else including verbosityStr.equalsIgnoreCase("INFO")
return Level.INFO; return Level.INFO;
} }
@ -122,30 +114,13 @@ public class Reporter {
} }
} }
/**
* Report an internal message of level DEBUG. Message text is prefixed with the string "SLF4J(D)",
* with (D) standing as a shorthand for DEBUG.
*
* <p>Messages of level DEBUG are be enabled when the {@link #SLF4J_INTERNAL_VERBOSITY_KEY}
* system property is set to "DEBUG" and disabled when set to "INFO", "WARN" or "ERROR". By default,
* {@link #SLF4J_INTERNAL_VERBOSITY_KEY} is set to "INFO".</p>
*
* @param msg the message text
* @since 2.0.16
*/
public static void debug(String msg) {
if(isEnabledFor(Level.DEBUG)) {
getTarget().println(SLF4J_DEBUG_PREFIX + msg);
}
}
/** /**
* Report an internal message of level INFO. Message text is prefixed with the string "SLF4J(I)", with * Report an internal message of level INFO. Message text is prefixed with the string "SLF4J(I)", with
* (I) standing as a shorthand for INFO. * (I) standing as a shorthand for INFO.
* *
* <p>Messages of level INFO are be enabled when the {@link #SLF4J_INTERNAL_VERBOSITY_KEY} system property is * <p>Messages of level INFO are be enabled when the {@link #SLF4J_INTERNAL_VERBOSITY_KEY} system property is
* set to "DEBUG" or "INFO" and disabled when set to "WARN" or "ERROR". By default, * set to "INFO" and disabled when set to "WARN" or "ERROR". By default, {@link #SLF4J_INTERNAL_VERBOSITY_KEY} is
* {@link #SLF4J_INTERNAL_VERBOSITY_KEY} is set to "INFO".</p> * set to "INFO".</p>
* *
* @param msg the message text * @param msg the message text
*/ */
@ -161,8 +136,8 @@ public class Reporter {
* (W) standing as a shorthand for WARN. * (W) standing as a shorthand for WARN.
* *
* <p>Messages of level WARN are be enabled when the {@link #SLF4J_INTERNAL_VERBOSITY_KEY} system property is * <p>Messages of level WARN are be enabled when the {@link #SLF4J_INTERNAL_VERBOSITY_KEY} system property is
* set to "DEBUG", "INFO" or "WARN" and disabled when set to "ERROR". By default, * set to "INFO" or "WARN" and disabled when set to "ERROR". By default, {@link #SLF4J_INTERNAL_VERBOSITY_KEY} is
* {@link #SLF4J_INTERNAL_VERBOSITY_KEY} is set to "INFO".</p> * set to "INFO".</p>
* *
* @param msg the message text * @param msg the message text
*/ */
@ -172,6 +147,7 @@ public class Reporter {
} }
} }
/** /**
* Report an internal message of level "ERROR accompanied by a {@link Throwable}. * Report an internal message of level "ERROR accompanied by a {@link Throwable}.
* Message text is prefixed with the string "SLF4J(E)", with (E) standing as a shorthand for ERROR. * Message text is prefixed with the string "SLF4J(E)", with (E) standing as a shorthand for ERROR.
@ -188,9 +164,10 @@ public class Reporter {
t.printStackTrace(getTarget()); t.printStackTrace(getTarget());
} }
/** /**
* Report an internal message of level "ERROR". Message text is prefixed with the string "SLF4J(E)", * Report an internal message of level "ERROR". Message text is prefixed with the string "SLF4J(E)", with
* with (E) standing as a shorthand for ERROR. * (E) standing as a shorthand for ERROR.
* *
* <p>Messages of level ERROR are always enabled. * <p>Messages of level ERROR are always enabled.
* *

View File

@ -1,76 +0,0 @@
/*
* Copyright (c) 2004-2024 QOS.ch
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.slf4j.helpers;
import java.lang.module.ModuleDescriptor;
import java.util.Optional;
/**
* Various utility methods
*
* @since 2.0.14
*/
public class Slf4jEnvUtil {
/**
* Returns the current version of slf4j, or null if data is not available.
*
* @return current version or null if missing version data
* @since 2.0.14
*/
static public String slf4jVersion() {
String moduleVersion = slf4jVersionByModule();
if(moduleVersion != null)
return moduleVersion;
Package pkg = Slf4jEnvUtil.class.getPackage();
if(pkg == null) {
return null;
}
final String pkgVersion = pkg.getImplementationVersion();
return pkgVersion;
}
/**
* Returns the current version of slf4j via class.getModule()
* or null if data is not available.
*
* @return current version or null if missing version data
* @since 2.0.14
*/
static private String slf4jVersionByModule() {
Module module = Slf4jEnvUtil.class.getModule();
if (module == null)
return null;
ModuleDescriptor md = module.getDescriptor();
if (md == null)
return null;
Optional<String> opt = md.rawVersion();
return opt.orElse(null);
}
}

View File

@ -7,18 +7,8 @@ import org.slf4j.spi.SLF4JServiceProvider;
public class SubstituteServiceProvider implements SLF4JServiceProvider { public class SubstituteServiceProvider implements SLF4JServiceProvider {
private final SubstituteLoggerFactory loggerFactory = new SubstituteLoggerFactory(); private final SubstituteLoggerFactory loggerFactory = new SubstituteLoggerFactory();
private final IMarkerFactory markerFactory = new BasicMarkerFactory();
// LoggerFactory expects providers to initialize markerFactory as early as possible. private final MDCAdapter mdcAdapter = new BasicMDCAdapter();
private final IMarkerFactory markerFactory;
// LoggerFactory expects providers to initialize their MDCAdapter field
// as early as possible, preferably at construction time.
private final MDCAdapter mdcAdapter;
public SubstituteServiceProvider() {
markerFactory = new BasicMarkerFactory();
mdcAdapter = new BasicMDCAdapter();
}
@Override @Override
public ILoggerFactory getLoggerFactory() { public ILoggerFactory getLoggerFactory() {
@ -46,5 +36,6 @@ public class SubstituteServiceProvider implements SLF4JServiceProvider {
@Override @Override
public void initialize() { public void initialize() {
} }
} }

View File

@ -117,28 +117,14 @@ public final class Util {
return trace[i + 2]; return trace[i + 2];
} }
/** // private static final void report(String msg, Throwable t) {
* See {@link Reporter#error(String, Throwable)} class for alternative. // System.err.println(msg);
* // System.err.println("Reported exception:");
* @deprecated replaced by the {@link Reporter#error(String, Throwable)} method. // t.printStackTrace();
* @param msg message to print // }
* @param t throwable to print //
*/ // static final private void report(String msg) {
static final public void report(String msg, Throwable t) { // System.err.println("SLF4J: " + msg);
System.err.println(msg); // }
System.err.println("Reported exception:");
t.printStackTrace();
}
/**
* See {@link Reporter} class for alternatives.
*
* @deprecated replaced by one of {@link Reporter#info(String)},
* {@link Reporter#warn(String)} or {@link Reporter#error(String)} methods.
* @param msg message to print
*/
static final public void report(String msg) {
System.err.println("SLF4J: " + msg);
}
} }

View File

@ -1,7 +1,7 @@
/** /**
* Copyright (c) 2004-2022 QOS.ch * Copyright (c) 2004-2022 QOS.ch
* All rights reserved. * All rights reserved.
* <p> *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
@ -9,10 +9,10 @@
* distribute, sublicense, and/or sell copies of the Software, and to * distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * the following conditions:
* <p> *
* The above copyright notice and this permission notice shall be * The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software. * included in all copies or substantial portions of the Software.
* <p> *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@ -20,10 +20,10 @@
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/ */
package org.slf4j.spi; package org.slf4j.spi;
import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -32,7 +32,6 @@ import org.slf4j.event.DefaultLoggingEvent;
import org.slf4j.event.KeyValuePair; import org.slf4j.event.KeyValuePair;
import org.slf4j.event.Level; import org.slf4j.event.Level;
import org.slf4j.event.LoggingEvent; import org.slf4j.event.LoggingEvent;
import org.slf4j.helpers.Reporter;
/** /**
* Default implementation of {@link LoggingEventBuilder}. * Default implementation of {@link LoggingEventBuilder}.
@ -58,7 +57,7 @@ public class DefaultLoggingEventBuilder implements LoggingEventBuilder, CallerBo
/** /**
* Add a marker to the current logging event being built. * Add a marker to the current logging event being built.
* <p> *
* It is possible to add multiple markers to the same logging event. * It is possible to add multiple markers to the same logging event.
* *
* @param marker the marker to add * @param marker the marker to add
@ -77,17 +76,166 @@ public class DefaultLoggingEventBuilder implements LoggingEventBuilder, CallerBo
@Override @Override
public LoggingEventBuilder addArgument(Object p) { public LoggingEventBuilder addArgument(Object p) {
this.loggingEvent.addArgument(p); loggingEvent.addArgument(p);
return this; return this;
} }
@Override @Override
public LoggingEventBuilder addArgument(Supplier<?> objectSupplier) { public LoggingEventBuilder addArgument(Supplier<?> objectSupplier) {
this.loggingEvent.addArgument(objectSupplier.get()); loggingEvent.addArgument(objectSupplier.get());
return this; return this;
} }
@Override
public void setCallerBoundary(String fqcn) {
loggingEvent.setCallerBoundary(fqcn);
}
@Override
public void log() {
log(loggingEvent);
}
@Override
public LoggingEventBuilder setMessage(String message) {
loggingEvent.setMessage(message);
return this;
}
@Override
public LoggingEventBuilder setMessage(Supplier<String> messageSupplier) {
loggingEvent.setMessage(messageSupplier.get());
return this;
}
@Override
public void log(String message) {
loggingEvent.setMessage(message);
log(loggingEvent);
}
@Override
public void log(String message, Object arg) {
loggingEvent.setMessage(message);
loggingEvent.addArgument(arg);
log(loggingEvent);
}
@Override
public void log(String message, Object arg0, Object arg1) {
loggingEvent.setMessage(message);
loggingEvent.addArgument(arg0);
loggingEvent.addArgument(arg1);
log(loggingEvent);
}
@Override
public void log(String message, Object... args) {
loggingEvent.setMessage(message);
loggingEvent.addArguments(args);
log(loggingEvent);
}
@Override
public void log(Supplier<String> messageSupplier) {
if (messageSupplier == null) {
log((String) null);
} else {
log(messageSupplier.get());
}
}
protected void log(LoggingEvent aLoggingEvent) {
setCallerBoundary(DLEB_FQCN);
if (logger instanceof LoggingEventAware) {
((LoggingEventAware) logger).log(aLoggingEvent);
} else {
logViaPublicSLF4JLoggerAPI(aLoggingEvent);
}
}
private void logViaPublicSLF4JLoggerAPI(LoggingEvent aLoggingEvent) {
Object[] argArray = aLoggingEvent.getArgumentArray();
int argLen = argArray == null ? 0 : argArray.length;
Throwable t = aLoggingEvent.getThrowable();
int tLen = t == null ? 0 : 1;
String msg = aLoggingEvent.getMessage();
Object[] combinedArguments = new Object[argLen + tLen];
if (argArray != null) {
System.arraycopy(argArray, 0, combinedArguments, 0, argLen);
}
if (t != null) {
combinedArguments[argLen] = t;
}
msg = mergeMarkersAndKeyValuePairs(aLoggingEvent, msg);
switch (aLoggingEvent.getLevel()) {
case TRACE:
logger.trace(msg, combinedArguments);
break;
case DEBUG:
logger.debug(msg, combinedArguments);
break;
case INFO:
logger.info(msg, combinedArguments);
break;
case WARN:
logger.warn(msg, combinedArguments);
break;
case ERROR:
logger.error(msg, combinedArguments);
break;
}
}
/**
* Prepend markers and key-value pairs to the message.
*
* @param aLoggingEvent
* @param msg
* @return
*/
private String mergeMarkersAndKeyValuePairs(LoggingEvent aLoggingEvent, String msg) {
StringBuilder sb = null;
if (aLoggingEvent.getMarkers() != null) {
sb = new StringBuilder();
for (Marker marker : aLoggingEvent.getMarkers()) {
sb.append(marker);
sb.append(' ');
}
}
if (aLoggingEvent.getKeyValuePairs() != null) {
if (sb == null) {
sb = new StringBuilder();
}
for (KeyValuePair kvp : aLoggingEvent.getKeyValuePairs()) {
sb.append(kvp.key);
sb.append('=');
sb.append(kvp.value);
sb.append(' ');
}
}
if (sb != null) {
sb.append(msg);
return sb.toString();
} else {
return msg;
}
}
@Override @Override
public LoggingEventBuilder addKeyValue(String key, Object value) { public LoggingEventBuilder addKeyValue(String key, Object value) {
loggingEvent.addKeyValue(key, value); loggingEvent.addKeyValue(key, value);
@ -100,205 +248,4 @@ public class DefaultLoggingEventBuilder implements LoggingEventBuilder, CallerBo
return this; return this;
} }
@Override
public void setCallerBoundary(String fqcn) {
this.loggingEvent.setCallerBoundary(fqcn);
}
@Override
public void log() {
log(this.loggingEvent);
}
@Override
public LoggingEventBuilder setMessage(String message) {
this.loggingEvent.setMessage(message);
return this;
}
@Override
public LoggingEventBuilder setMessage(Supplier<String> messageSupplier) {
this.loggingEvent.setMessage(messageSupplier.get());
return this;
}
@Override
public void log(String message) {
this.loggingEvent.setMessage(message);
log(this.loggingEvent);
}
@Override
public void log(String message, Object arg) {
this.loggingEvent.setMessage(message);
this.loggingEvent.addArgument(arg);
log(this.loggingEvent);
}
@Override
public void log(String message, Object arg0, Object arg1) {
this.loggingEvent.setMessage(message);
this.loggingEvent.addArgument(arg0);
this.loggingEvent.addArgument(arg1);
log(this.loggingEvent);
}
@Override
public void log(String message, Object... args) {
this.loggingEvent.setMessage(message);
this.loggingEvent.addArguments(args);
log(this.loggingEvent);
}
@Override
public void log(Supplier<String> messageSupplier) {
if(messageSupplier == null) {
log((String) null);
} else {
log(messageSupplier.get());
}
}
protected void log(LoggingEvent aLoggingEvent) {
if(aLoggingEvent.getCallerBoundary() == null) {
setCallerBoundary(DLEB_FQCN);
}
if(logger instanceof LoggingEventAware) {
((LoggingEventAware) logger).log(aLoggingEvent);
} else if(logger instanceof LocationAwareLogger) {
logViaLocationAwareLoggerAPI((LocationAwareLogger) logger, aLoggingEvent);
} else {
logViaPublicSLF4JLoggerAPI(aLoggingEvent);
}
}
private void logViaLocationAwareLoggerAPI(LocationAwareLogger locationAwareLogger, LoggingEvent aLoggingEvent) {
List<Marker> markerList = aLoggingEvent.getMarkers();
Marker firstMarker = (markerList != null && !markerList.isEmpty()) ? markerList.get(0) : null;
String mergedMessage = mergeMarkersAndKeyValuePairsAndMessage(aLoggingEvent);
locationAwareLogger.log(firstMarker, aLoggingEvent.getCallerBoundary(), aLoggingEvent.getLevel().toInt(),
mergedMessage,
aLoggingEvent.getArgumentArray(), aLoggingEvent.getThrowable());
}
private void logViaPublicSLF4JLoggerAPI(LoggingEvent aLoggingEvent) {
Object[] argArray = aLoggingEvent.getArgumentArray();
int argLen = argArray == null ? 0 : argArray.length;
Throwable t = aLoggingEvent.getThrowable();
int tLen = t == null ? 0 : 1;
Object[] combinedArguments = new Object[argLen + tLen];
if(argArray != null) {
System.arraycopy(argArray, 0, combinedArguments, 0, argLen);
}
if(t != null) {
combinedArguments[argLen] = t;
}
String mergedMessage = mergeMarkersAndKeyValuePairsAndMessage(aLoggingEvent);
switch(aLoggingEvent.getLevel()) {
case TRACE:
logger.trace(mergedMessage, combinedArguments);
break;
case DEBUG:
logger.debug(mergedMessage, combinedArguments);
break;
case INFO:
logger.info(mergedMessage, combinedArguments);
break;
case WARN:
logger.warn(mergedMessage, combinedArguments);
break;
case ERROR:
logger.error(mergedMessage, combinedArguments);
break;
}
}
/**
* Prepend markers and key-value pairs to the message.
*
* @param aLoggingEvent
*
* @return
*/
private String mergeMarkersAndKeyValuePairsAndMessage(LoggingEvent aLoggingEvent) {
StringBuilder sb = mergeMarkers(aLoggingEvent.getMarkers(), null);
sb = mergeKeyValuePairs(aLoggingEvent.getKeyValuePairs(), sb);
final String mergedMessage = mergeMessage(aLoggingEvent.getMessage(), sb);
return mergedMessage;
}
private StringBuilder mergeMarkers(List<Marker> markerList, StringBuilder sb) {
if(markerList == null || markerList.isEmpty())
return sb;
if(sb == null)
sb = new StringBuilder();
for(Marker marker : markerList) {
sb.append(marker);
sb.append(' ');
}
return sb;
}
private StringBuilder mergeKeyValuePairs(List<KeyValuePair> keyValuePairList, StringBuilder sb) {
if(keyValuePairList == null || keyValuePairList.isEmpty())
return sb;
if(sb == null)
sb = new StringBuilder();
for(KeyValuePair kvp : keyValuePairList) {
sb.append(kvp.key);
sb.append('=');
// Same protection as MessageFormatter.safeObjectAppend: a failing
// toString() (including StackOverflowError) must not abort logging.
// See https://github.com/qos-ch/slf4j/issues/448
safeObjectAppend(sb, kvp.value);
sb.append(' ');
}
return sb;
}
/**
* Append {@code o} to {@code sb}, catching any {@link Throwable} thrown by
* {@link Object#toString()} and substituting {@code [FAILED toString()]}.
* Mirrors {@code MessageFormatter.safeObjectAppend}.
*/
private static void safeObjectAppend(StringBuilder sb, Object o) {
if (o == null) {
sb.append("null");
return;
}
try {
sb.append(o.toString());
} catch (Throwable t) {
Reporter.error("Failed toString() invocation on an object of type [" + o.getClass().getName() + "]", t);
sb.append("[FAILED toString()]");
}
}
private String mergeMessage(String msg, StringBuilder sb) {
if(sb != null) {
sb.append(msg);
return sb.toString();
} else {
return msg;
}
}
} }

View File

@ -93,7 +93,7 @@ public interface MDCAdapter {
public void setContextMap(Map<String, String> contextMap); public void setContextMap(Map<String, String> contextMap);
/** /**
* Push a value into the <b>deque(stack)</b> referenced by 'key'. * Push a value into the deque(stack) referenced by 'key'.
* *
* @param key identifies the appropriate stack * @param key identifies the appropriate stack
* @param value the value to push into the stack * @param value the value to push into the stack
@ -102,7 +102,7 @@ public interface MDCAdapter {
public void pushByKey(String key, String value); public void pushByKey(String key, String value);
/** /**
* Pop the <b>stack</b> referenced by 'key' and return the value possibly null. * Pop the stack referenced by 'key' and return the value possibly null.
* *
* @param key identifies the deque(stack) * @param key identifies the deque(stack)
* @return the value just popped. May be null/ * @return the value just popped. May be null/
@ -111,7 +111,7 @@ public interface MDCAdapter {
public String popByKey(String key); public String popByKey(String key);
/** /**
* Returns a copy of the <b>deque(stack)</b> referenced by 'key'. May be null. * Returns a copy of the deque(stack) referenced by 'key'. May be null.
* *
* @param key identifies the stack * @param key identifies the stack
* @return copy of stack referenced by 'key'. May be null. * @return copy of stack referenced by 'key'. May be null.
@ -122,7 +122,7 @@ public interface MDCAdapter {
/** /**
* Clear the <b>deque(stack)</b> referenced by 'key'. * Clear the deque(stack) referenced by 'key'.
* *
* @param key identifies the stack * @param key identifies the stack
* *

View File

@ -11,7 +11,7 @@ import org.slf4j.event.Level;
* <p></p> * <p></p>
* <p>As the name indicates, the methods in this class do nothing. In case a return value is expected, a singleton, * <p>As the name indicates, the methods in this class do nothing. In case a return value is expected, a singleton,
* i.e. the unique instance of this class, is returned. * i.e. the unique instance of this class, is returned.
* </p> * </p
* <p></p> * <p></p>
* <p>Note that the default implementations of {@link Logger#atTrace()}, {@link Logger#atDebug()} , {@link Logger#atInfo()}, * <p>Note that the default implementations of {@link Logger#atTrace()}, {@link Logger#atDebug()} , {@link Logger#atInfo()},
* {@link Logger#atWarn()} and {@link Logger#atError()}, return an instance of {@link NOPLoggingEventBuilder} * {@link Logger#atWarn()} and {@link Logger#atError()}, return an instance of {@link NOPLoggingEventBuilder}

View File

@ -29,8 +29,6 @@ import static org.junit.Assert.assertTrue;
import java.util.Random; import java.util.Random;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -39,21 +37,11 @@ import org.slf4j.Marker;
import org.slf4j.MarkerFactory; import org.slf4j.MarkerFactory;
import org.slf4j.helpers.BasicMarker; import org.slf4j.helpers.BasicMarker;
import org.slf4j.helpers.NOPLogger; import org.slf4j.helpers.NOPLogger;
import org.slf4j.helpers.Reporter;
public class NoBindingTest { public class NoBindingTest {
int diff = new Random().nextInt(10000); int diff = new Random().nextInt(10000);
@Before
public void setUp() throws Exception {
System.setProperty(Reporter.SLF4J_INTERNAL_VERBOSITY_KEY, "debug");
}
@After
public void tearDown() throws Exception {
System.clearProperty(Reporter.SLF4J_INTERNAL_VERBOSITY_KEY);
}
@Test @Test
public void testLogger() { public void testLogger() {
Logger logger = LoggerFactory.getLogger(NoBindingTest.class); Logger logger = LoggerFactory.getLogger(NoBindingTest.class);

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -67,7 +67,7 @@
<configuration> <configuration>
<archive> <archive>
<manifestEntries> <manifestEntries>
<!-- <Automatic-Module-Name>org.slf4j.ext</Automatic-Module-Name>--> <Automatic-Module-Name>org.slf4j.ext</Automatic-Module-Name>
<Premain-Class>org.slf4j.agent.AgentPremain</Premain-Class> <Premain-Class>org.slf4j.agent.AgentPremain</Premain-Class>
<!-- what is the proper way to specify the maven full name? /ravn --> <!-- what is the proper way to specify the maven full name? /ravn -->
<Boot-Class-Path>../../../../javassist/javassist/3.4.GA/javassist-3.4.GA.jar javassist-3.4.GA.jar javassist.jar</Boot-Class-Path> <Boot-Class-Path>../../../../javassist/javassist/3.4.GA/javassist-3.4.GA.jar javassist-3.4.GA.jar javassist.jar</Boot-Class-Path>

View File

@ -8,7 +8,7 @@
<parent> <parent>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -19,9 +19,6 @@
<url>https://www.slf4j.org</url> <url>https://www.slf4j.org</url>
<properties>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
@ -38,6 +35,37 @@
<build> <build>
<plugins> <plugins>
<!-- target Java 9+ -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<executions>
<execution>
<id>default-compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<source>9</source>
<target>9</target>
<release>9</release>
</configuration>
</execution>
<execution>
<id>default-testCompile</id>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<source>9</source>
<target>9</target>
<release>9</release>
</configuration>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>

View File

@ -1,7 +1,7 @@
/** /**
* Copyright (c) 2004-2021 QOS.ch * Copyright (c) 2004-2021 QOS.ch
* All rights reserved. * All rights reserved.
* <p> *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
@ -9,10 +9,10 @@
* distribute, sublicense, and/or sell copies of the Software, and to * distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * the following conditions:
* <p> *
* The above copyright notice and this permission notice shall be * The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software. * included in all copies or substantial portions of the Software.
* <p> *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@ -60,12 +60,12 @@ class SLF4JPlatformLogger implements System.Logger {
@Override @Override
public boolean isLoggable(Level jplLevel) { public boolean isLoggable(Level jplLevel) {
// If called via log method, fixExtremeLevels has been called. System.Logger.Level.ALL and Level.OFF have if (jplLevel == Level.ALL)
// been respectively mapped to Level.TRACE and Level.ERROR. return true;
// However, if isLoggable is called directly, we must fix the extreme levels here as well. if (jplLevel == Level.OFF)
final Level jplLevelReduced = fixExtremeLevels(jplLevel); return true;
org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevelReduced); org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevel);
return slf4jLogger.isEnabledForLevel(slf4jLevel); return slf4jLogger.isEnabledForLevel(slf4jLevel);
} }
@ -80,20 +80,20 @@ class SLF4JPlatformLogger implements System.Logger {
* @return * @return
*/ */
private org.slf4j.event.Level jplLevelToSLF4JLevel(Level jplLevel) { private org.slf4j.event.Level jplLevelToSLF4JLevel(Level jplLevel) {
switch(jplLevel) { switch (jplLevel) {
case TRACE: case TRACE:
return org.slf4j.event.Level.TRACE; return org.slf4j.event.Level.TRACE;
case DEBUG: case DEBUG:
return org.slf4j.event.Level.DEBUG; return org.slf4j.event.Level.DEBUG;
case INFO: case INFO:
return org.slf4j.event.Level.INFO; return org.slf4j.event.Level.INFO;
case WARNING: case WARNING:
return org.slf4j.event.Level.WARN; return org.slf4j.event.Level.WARN;
case ERROR: case ERROR:
return org.slf4j.event.Level.ERROR; return org.slf4j.event.Level.ERROR;
default: default:
reportUnknownLevel(jplLevel); reportUnknownLevel(jplLevel);
return null; return null;
} }
} }
@ -116,54 +116,38 @@ class SLF4JPlatformLogger implements System.Logger {
* @param thrown * @param thrown
* @param params * @param params
*/ */
private void log(final Level jplLevel, final ResourceBundle bundle, final String msg, final Throwable thrown, final Object... params) { private void log(Level jplLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params) {
if (jplLevel == Level.OFF)
return;
final Level jplLevelReduced = fixExtremeLevels(jplLevel); if (jplLevel == Level.ALL) {
performLog(org.slf4j.event.Level.TRACE, bundle, msg, thrown, params);
return;
}
org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevelReduced); org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevel);
boolean isEnabled = slf4jLogger.isEnabledForLevel(slf4jLevel); boolean isEnabled = slf4jLogger.isEnabledForLevel(slf4jLevel);
if(isEnabled) { if (isEnabled) {
performLog(slf4jLevel, bundle, msg, thrown, params); performLog(slf4jLevel, bundle, msg, thrown, params);
} }
} }
/**
* <p>Level.OFF and Level.ALL levels are not supposed to be used when calling log printing methods.
* </p>
*
* <p>We compensate for such incorrect usage by transforming Level.OFF as Level.ERROR and
* Level.ALL as Level.TRACE.
* </p>
*
* @param jplLevel
* @return
*/
private Level fixExtremeLevels(Level jplLevel) {
if(jplLevel == Level.OFF)
return Level.ERROR;
if(jplLevel == Level.ALL)
return Level.TRACE;
return jplLevel;
}
private void performLog(org.slf4j.event.Level slf4jLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params) { private void performLog(org.slf4j.event.Level slf4jLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params) {
String message = getResourceStringOrMessage(bundle, msg); String message = getResourceStringOrMessage(bundle, msg);
LoggingEventBuilder leb = slf4jLogger.makeLoggingEventBuilder(slf4jLevel); LoggingEventBuilder leb = slf4jLogger.makeLoggingEventBuilder(slf4jLevel);
if(thrown != null) { if (thrown != null) {
leb = leb.setCause(thrown); leb = leb.setCause(thrown);
} }
if(params != null && params.length > 0) { if (params != null && params.length > 0) {
// add the arguments to the logging event for possible processing by the backend // add the arguments to the logging event for possible processing by the backend
for(Object p : params) { for (Object p : params) {
leb = leb.addArgument(p); leb = leb.addArgument(p);
} }
// The JDK uses a different formatting convention. We must invoke it now. // The JDK uses a different formatting convention. We must invoke it now.
message = MessageFormat.format(message, params); message = MessageFormat.format(message, params);
} }
if(leb instanceof CallerBoundaryAware) { if (leb instanceof CallerBoundaryAware) {
CallerBoundaryAware cba = (CallerBoundaryAware) leb; CallerBoundaryAware cba = (CallerBoundaryAware) leb;
cba.setCallerBoundary(PRESUMED_CALLER_BOUNDARY); cba.setCallerBoundary(PRESUMED_CALLER_BOUNDARY);
} }
@ -177,7 +161,7 @@ class SLF4JPlatformLogger implements System.Logger {
} }
private static String getResourceStringOrMessage(ResourceBundle bundle, String msg) { private static String getResourceStringOrMessage(ResourceBundle bundle, String msg) {
if(bundle == null || msg == null) if (bundle == null || msg == null)
return msg; return msg;
// ResourceBundle::getString throws: // ResourceBundle::getString throws:
// //

View File

@ -24,6 +24,9 @@
*/ */
package org.slf4j.jdk.platform.logging.test; package org.slf4j.jdk.platform.logging.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.System.Logger; import java.lang.System.Logger;
@ -38,8 +41,6 @@ import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static org.junit.Assert.*;
/** /**
* The present test is fragile in the sense that it sets up SimpleLogger * The present test is fragile in the sense that it sets up SimpleLogger
* with a StringPrintStream and reverts to the old stream when done. * with a StringPrintStream and reverts to the old stream when done.
@ -110,38 +111,13 @@ public class SLF4JPlatformLoggingTest {
// java.lang.Exception // java.lang.Exception
// at org.slf4j.jdk.platform.logging/org.slf4j.jdk.platform.logging.SLF4JPlatformLoggingTest.throwTest(SLF4JPlatformLoggingTest.java:92) // at org.slf4j.jdk.platform.logging/org.slf4j.jdk.platform.logging.SLF4JPlatformLoggingTest.throwTest(SLF4JPlatformLoggingTest.java:92)
int line = 0; String firstLine = results.get(0);
//assertTrue(results.get(0).startsWith("SLF4J(I): Connected with provider of type [")); assertTrue(firstLine.startsWith("SLF4J(I): Connected with provider of type [org.slf4j.simple.SimpleServiceProvider"));
assertEquals("INFO throwTest - we have a problem", results.get(line++)); assertEquals("INFO throwTest - we have a problem", results.get(1));
assertEquals(Exception.class.getName(), results.get(line++)); assertEquals(Exception.class.getName(), results.get(2));
assertTrue(results.get(line).contains("at ")); assertTrue(results.get(3).contains("at "));
assertTrue(results.get(line++).contains(this.getClass().getName())); assertTrue(results.get(3).contains(this.getClass().getName()));
} }
@Test
public void extremeLevels() throws IOException {
LoggerFinder finder = System.LoggerFinder.getLoggerFinder();
assertEquals(EXPECTED_FINDER_CLASS, finder.getClass().getName());
Logger systemLogger = finder.getLogger("extremeLevels", null);
systemLogger.log(Level.OFF, "hello");
systemLogger.log(Level.ALL, "world");
List<String> results = SPS.stringList;
assertEquals(1, results.size());
assertEquals("ERROR extremeLevels - hello", results.get(0));
}
@Test
public void extremeLevels_isLoggableTest() throws IOException {
LoggerFinder finder = System.LoggerFinder.getLoggerFinder();
assertEquals(EXPECTED_FINDER_CLASS, finder.getClass().getName());
Logger systemLogger = finder.getLogger("extremeLevels", null);
boolean offResult = systemLogger.isLoggable(Level.OFF);
assertTrue(offResult);
boolean allResult = systemLogger.isLoggable(Level.ALL);
assertFalse(allResult);
}
} }

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -38,9 +38,4 @@
</dependencies> </dependencies>
<build>
<plugins>
</plugins>
</build>
</project> </project>

View File

@ -5,9 +5,8 @@ module org.slf4j.jul {
requires org.slf4j; requires org.slf4j;
requires java.logging; requires java.logging;
provides org.slf4j.spi.SLF4JServiceProvider with org.slf4j.jul.JULServiceProvider; provides org.slf4j.spi.SLF4JServiceProvider with org.slf4j.jul.JULServiceProvider;
exports org.slf4j.jul;
opens org.slf4j.jul to org.slf4j; opens org.slf4j.jul to org.slf4j;
exports org.slf4j.jul;
} }

View File

@ -55,8 +55,6 @@ public final class JDK14LoggerAdapter extends LegacyAbstractLogger implements Lo
transient final java.util.logging.Logger logger; transient final java.util.logging.Logger logger;
static int NOT_FOUND = -1;
// WARN: JDK14LoggerAdapter constructor should have only package access so // WARN: JDK14LoggerAdapter constructor should have only package access so
// that only JDK14LoggerFactory be able to create one. // that only JDK14LoggerFactory be able to create one.
JDK14LoggerAdapter(java.util.logging.Logger logger) { JDK14LoggerAdapter(java.util.logging.Logger logger) {
@ -183,10 +181,26 @@ public final class JDK14LoggerAdapter extends LegacyAbstractLogger implements Lo
final private void fillCallerData(String callerFQCN, LogRecord record) { final private void fillCallerData(String callerFQCN, LogRecord record) {
StackTraceElement[] steArray = new Throwable().getStackTrace(); StackTraceElement[] steArray = new Throwable().getStackTrace();
int furthestIndex = findFurthestIndex(callerFQCN, steArray); int selfIndex = -1;
for (int i = 0; i < steArray.length; i++) {
final String className = steArray[i].getClassName();
if (furthestIndex != NOT_FOUND) { if (barrierMatch(callerFQCN, className)) {
int found = furthestIndex+1; selfIndex = i;
break;
}
}
int found = -1;
for (int i = selfIndex + 1; i < steArray.length; i++) {
final String className = steArray[i].getClassName();
if (!(barrierMatch(callerFQCN, className))) {
found = i;
break;
}
}
if (found != -1) {
StackTraceElement ste = steArray[found]; StackTraceElement ste = steArray[found];
// setting the class name has the side effect of setting // setting the class name has the side effect of setting
// the needToInferCaller variable to false. // the needToInferCaller variable to false.
@ -195,24 +209,7 @@ public final class JDK14LoggerAdapter extends LegacyAbstractLogger implements Lo
} }
} }
// find the furthest index which matches any of the barrier classes static String SELF = JDK14LoggerAdapter.class.getName();
// We assume that the actual caller is at most MAX_SEARCH_DEPTH calls away
private int findFurthestIndex(String callerFQCN, StackTraceElement[] steArray) {
final int maxIndex = Math.min(MAX_SEARCH_DEPTH, steArray.length);
int furthestIndex = NOT_FOUND;
for (int i = 0; i < maxIndex; i++) {
final String className = steArray[i].getClassName();
if (barrierMatch(callerFQCN, className)) {
furthestIndex = i;
}
}
return furthestIndex;
}
static final int MAX_SEARCH_DEPTH = 12;
static String SELF = JDK14LoggerAdapter.class.getName();
static String SUPER = LegacyAbstractLogger.class.getName(); static String SUPER = LegacyAbstractLogger.class.getName();
static String SUPER_OF_SUPER = AbstractLogger.class.getName(); static String SUPER_OF_SUPER = AbstractLogger.class.getName();

View File

@ -17,16 +17,8 @@ public class JULServiceProvider implements SLF4JServiceProvider {
public static String REQUESTED_API_VERSION = "2.0.99"; // !final public static String REQUESTED_API_VERSION = "2.0.99"; // !final
private ILoggerFactory loggerFactory; private ILoggerFactory loggerFactory;
// LoggerFactory expects providers to initialize markerFactory as early as possible. private IMarkerFactory markerFactory;
private final IMarkerFactory markerFactory; private MDCAdapter mdcAdapter;
// LoggerFactory expects providers to initialize their MDCAdapter field
// as early as possible, preferably at construction time.
private final MDCAdapter mdcAdapter;
public JULServiceProvider() {
markerFactory = new BasicMarkerFactory();
mdcAdapter = new BasicMDCAdapter();
}
@Override @Override
public ILoggerFactory getLoggerFactory() { public ILoggerFactory getLoggerFactory() {
@ -50,5 +42,7 @@ public class JULServiceProvider implements SLF4JServiceProvider {
@Override @Override
public void initialize() { public void initialize() {
loggerFactory = new JDK14LoggerFactory(); loggerFactory = new JDK14LoggerFactory();
markerFactory = new BasicMarkerFactory();
mdcAdapter = new BasicMDCAdapter();
} }
} }

View File

@ -20,8 +20,6 @@ import org.slf4j.helpers.SubstituteLogger;
import org.slf4j.helpers.SubstituteServiceProvider; import org.slf4j.helpers.SubstituteServiceProvider;
import org.slf4j.jul.JDK14LoggerAdapter; import org.slf4j.jul.JDK14LoggerAdapter;
import org.slf4j.jul.ListHandler; import org.slf4j.jul.ListHandler;
import org.slf4j.spi.CallerBoundaryAware;
import org.slf4j.spi.LoggingEventBuilder;
public class CallerInfoTest { public class CallerInfoTest {
Level oldLevel; Level oldLevel;
@ -80,22 +78,6 @@ public class CallerInfoTest {
assertEquals(this.getClass().getName(), logRecod.getSourceClassName()); assertEquals(this.getClass().getName(), logRecod.getSourceClassName());
} }
@Test
public void testCallerInfoWithFluentAPIAndAWrapper() {
Logger logger = LoggerFactory.getLogger("bla");
LoggingWrapper wrappedLogger = new LoggingWrapper(logger);
wrappedLogger.logWithEvent("hello");
List<LogRecord> recordList = listHandler.recordList;
assertEquals(1, recordList.size());
LogRecord logRecod = recordList.get(0);
assertEquals(this.getClass().getName(), logRecod.getSourceClassName());
}
@Test @Test
public void testPostInitializationCallerInfoWithSubstituteLogger() { public void testPostInitializationCallerInfoWithSubstituteLogger() {
Logger logger = LoggerFactory.getLogger("bla"); Logger logger = LoggerFactory.getLogger("bla");
@ -139,22 +121,4 @@ public class CallerInfoTest {
assertEquals(EventConstants.NA_SUBST, logRecod.getSourceClassName()); assertEquals(EventConstants.NA_SUBST, logRecod.getSourceClassName());
} }
static class LoggingWrapper {
Logger underlyingLogger;
LoggingWrapper(Logger aLogger) {
this.underlyingLogger = aLogger;
}
public void logWithEvent(String msg) {
LoggingEventBuilder lev = underlyingLogger.atInfo();
// setting the caller boundary to LoggingWrapper
if(lev instanceof CallerBoundaryAware) {
// builder is CallerBoundaryAware
((CallerBoundaryAware) lev).setCallerBoundary(LoggingWrapper.class.getName());
}
lev.log(msg);
}
}
} }

View File

@ -130,35 +130,6 @@ public class FluentApiInvocationTest {
} }
/**
* Regression for https://github.com/qos-ch/slf4j/issues/448:
* a toString() that throws (including StackOverflowError) on an
* addKeyValue value must not abort logging; same as message args.
*/
@Test
public void keyValuePairWithFailingToString() {
Object bad = new Object() {
@Override
public String toString() {
throw new IllegalStateException("boom");
}
};
logger.atDebug().addKeyValue("key", bad).log("msg with key/value");
assertLogMessage("key=[FAILED toString()] msg with key/value", 0);
}
@Test
public void keyValuePairWithStackOverflowInToString() {
Object overflow = new Object() {
@Override
public String toString() {
return super.toString() + this.toString();
}
};
logger.atDebug().addKeyValue("key", overflow).log("msg with key/value");
assertLogMessage("key=[FAILED toString()] msg with key/value", 0);
}
private void assertLogMessage(String expected, int index) { private void assertLogMessage(String expected, int index) {
LogRecord logRecord = listHandler.recordList.get(index); LogRecord logRecord = listHandler.recordList.get(index);
Assert.assertNotNull(logRecord); Assert.assertNotNull(logRecord);

View File

@ -8,7 +8,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -24,7 +24,7 @@
<relocation> <relocation>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId> <artifactId>slf4j-reload4j</artifactId>
<version>2.1.0-alpha2-SNAPSHOT</version> <version>2.1.0-alpha0</version>
</relocation> </relocation>
</distributionManagement> </distributionManagement>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -38,8 +38,4 @@
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
</plugins>
</build>
</project> </project>

1
slf4j-nop/src/main/java/module-info.java Normal file → Executable file
View File

@ -4,6 +4,5 @@
module org.slf4j.nop { module org.slf4j.nop {
requires org.slf4j; requires org.slf4j;
exports org.slf4j.nop; exports org.slf4j.nop;
opens org.slf4j.nop to org.slf4j;
provides org.slf4j.spi.SLF4JServiceProvider with org.slf4j.nop.NOPServiceProvider; provides org.slf4j.spi.SLF4JServiceProvider with org.slf4j.nop.NOPServiceProvider;
} }

View File

@ -23,18 +23,9 @@ public class NOPServiceProvider implements SLF4JServiceProvider {
public static String REQUESTED_API_VERSION = "2.0.99"; // !final public static String REQUESTED_API_VERSION = "2.0.99"; // !final
private final ILoggerFactory loggerFactory = new NOPLoggerFactory(); private final ILoggerFactory loggerFactory = new NOPLoggerFactory();
private final IMarkerFactory markerFactory = new BasicMarkerFactory();
private final MDCAdapter mdcAdapter = new NOPMDCAdapter();
// LoggerFactory expects providers to initialize markerFactory as early as possible.
private final IMarkerFactory markerFactory;
// LoggerFactory expects providers to initialize their MDCAdapter field
// as early as possible, preferably at construction time.
private final MDCAdapter mdcAdapter;
public NOPServiceProvider() {
markerFactory = new BasicMarkerFactory();
mdcAdapter = new NOPMDCAdapter();
}
public ILoggerFactory getLoggerFactory() { public ILoggerFactory getLoggerFactory() {
return loggerFactory; return loggerFactory;
} }
@ -53,6 +44,7 @@ public class NOPServiceProvider implements SLF4JServiceProvider {
} }
public void initialize() { public void initialize() {
} }

View File

@ -1,7 +1,7 @@
/** /**
* Copyright (c) 2004-2016 QOS.ch * Copyright (c) 2004-2016 QOS.ch
* All rights reserved. * All rights reserved.
* <p> *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
@ -9,10 +9,10 @@
* distribute, sublicense, and/or sell copies of the Software, and to * distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * the following conditions:
* <p> *
* The above copyright notice and this permission notice shall be * The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software. * included in all copies or substantial portions of the Software.
* <p> *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@ -20,15 +20,11 @@
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/ */
package org.slf4j.nop; package org.slf4j.nop;
import org.junit.After; import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.LoggerFactoryFriend;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.ArrayList; import java.util.ArrayList;
@ -38,8 +34,12 @@ import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import static org.junit.Assert.assertEquals; import org.junit.After;
import static org.slf4j.helpers.Reporter.SLF4J_INTERNAL_VERBOSITY_KEY; import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.LoggerFactoryFriend;
public class MultithreadedInitializationTest { public class MultithreadedInitializationTest {
@ -56,14 +56,12 @@ public class MultithreadedInitializationTest {
@Before @Before
public void setup() { public void setup() {
System.setProperty(SLF4J_INTERNAL_VERBOSITY_KEY, "debug");
LoggerFactoryFriend.reset(); LoggerFactoryFriend.reset();
System.setErr(sps); System.setErr(sps);
} }
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
System.clearProperty(SLF4J_INTERNAL_VERBOSITY_KEY);
LoggerFactoryFriend.reset(); LoggerFactoryFriend.reset();
System.setErr(oldErr); System.setErr(oldErr);
} }
@ -73,7 +71,7 @@ public class MultithreadedInitializationTest {
System.out.println("THREAD_COUNT=" + THREAD_COUNT); System.out.println("THREAD_COUNT=" + THREAD_COUNT);
LoggerAccessingThread[] accessors = harness(); LoggerAccessingThread[] accessors = harness();
for(LoggerAccessingThread accessor : accessors) { for (LoggerAccessingThread accessor : accessors) {
EVENT_COUNT.getAndIncrement(); EVENT_COUNT.getAndIncrement();
accessor.logger.info("post harness"); accessor.logger.info("post harness");
} }
@ -89,13 +87,13 @@ public class MultithreadedInitializationTest {
private static LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { private static LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException {
LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT]; LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT];
final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1);
for(int i = 0; i < THREAD_COUNT; i++) { for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new LoggerAccessingThread(barrier, i); threads[i] = new LoggerAccessingThread(barrier, i);
threads[i].start(); threads[i].start();
} }
barrier.await(); barrier.await();
for(int i = 0; i < THREAD_COUNT; i++) { for (int i = 0; i < THREAD_COUNT; i++) {
threads[i].join(); threads[i].join();
} }
return threads; return threads;
@ -121,9 +119,7 @@ public class MultithreadedInitializationTest {
logger.info("in run method"); logger.info("in run method");
EVENT_COUNT.getAndIncrement(); EVENT_COUNT.getAndIncrement();
} }
} };
;
public static class StringPrintStream extends PrintStream { public static class StringPrintStream extends PrintStream {

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -51,54 +51,20 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration> <configuration>
<!-- <forkCount>1</forkCount>
java.lang.IllegalAccessException: class org.apache.log4j.helpers.OptionConverter <reuseForks>false</reuseForks>
(in module ch.qos.reload4j) cannot access class org.slf4j.reload4j.testHarness.RecursiveAppender <reportFormat>plain</reportFormat>
(in module org.slf4j.reload4j) because module org.slf4j.reload4j does not export org.slf4j.reload4j.testHarness <trimStackTrace>false</trimStackTrace>
to module ch.qos.reload4j <excludes>
<exclude>**/AllTest.java</exclude>
--> <exclude>**/PackageTest.java</exclude>
<argLine> </excludes>
--add-opens org.slf4j.reload4j/org.slf4j.reload4j.testHarness=ch.qos.reload4j <argLine>-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8001</argLine>
</argLine> <!--<argLine>XXadd-opens log4j/org.apache.log4j=org.slf4j.log4j12</argLine>-->
</configuration> </configuration>
</plugin> </plugin>
<!-- <executions>-->
<!-- <execution>-->
<!-- <id>default-test</id>-->
<!-- <configuration>-->
<!-- <parallel>classes</parallel>-->
<!-- <threadCount>8</threadCount>-->
<!-- <forkCount>1C</forkCount>-->
<!-- <reuseForks>true</reuseForks>-->
<!-- <reportFormat>plain</reportFormat>-->
<!-- <trimStackTrace>false</trimStackTrace>-->
<!-- <excludes>-->
<!-- <exclude>**/AllTest.java</exclude>-->
<!-- <exclude>**/PackageTest.java</exclude>-->
<!-- <exclude>org.slf4j.reload4j.EventFieldsTest</exclude>-->
<!-- <exclude>org.slf4j.testing.MultithreadedInitializationTest</exclude>-->
<!-- </excludes>-->
<!-- </configuration>-->
<!-- </execution>-->
<!-- <execution>-->
<!-- <id>singleJVM</id>-->
<!-- <goals>-->
<!-- <goal>test</goal>-->
<!-- </goals>-->
<!-- <configuration>-->
<!-- <forkCount>4</forkCount>-->
<!-- <reuseForks>false</reuseForks>-->
<!-- <includes>-->
<!-- <include>org.slf4j.testing.MultithreadedInitializationTest</include>-->
<!-- <include>org.slf4j.reload4j.EventFieldsTest</include>-->
<!-- </includes>-->
<!-- </configuration>-->
<!-- </execution>-->
<!-- </executions>-->
<!-- </plugin>-->
</plugins> </plugins>
</build> </build>

View File

@ -19,17 +19,10 @@ public class Reload4jServiceProvider implements SLF4JServiceProvider {
public static String REQUESTED_API_VERSION = "2.0.99"; // !final public static String REQUESTED_API_VERSION = "2.0.99"; // !final
private ILoggerFactory loggerFactory; private ILoggerFactory loggerFactory;
private IMarkerFactory markerFactory;
// LoggerFactory expects providers to initialize markerFactory as early as possible. private MDCAdapter mdcAdapter;
private final IMarkerFactory markerFactory;
// LoggerFactory expects providers to have a valid MDCAdapter field
// as early as possible, preferably at construction time.
private final MDCAdapter mdcAdapter;
public Reload4jServiceProvider() { public Reload4jServiceProvider() {
markerFactory = new BasicMarkerFactory();
mdcAdapter = new Reload4jMDCAdapter();
try { try {
@SuppressWarnings("unused") @SuppressWarnings("unused")
Level level = Level.TRACE; Level level = Level.TRACE;
@ -41,6 +34,8 @@ public class Reload4jServiceProvider implements SLF4JServiceProvider {
@Override @Override
public void initialize() { public void initialize() {
loggerFactory = new Reload4jLoggerFactory(); loggerFactory = new Reload4jLoggerFactory();
markerFactory = new BasicMarkerFactory();
mdcAdapter = new Reload4jMDCAdapter();
} }
@Override @Override

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -19,7 +19,6 @@
<properties> <properties>
<module-name>org.slf4j.simple</module-name> <module-name>org.slf4j.simple</module-name>
<slf4j.provider.implementation>org.slf4j.simple.SimpleServiceProvider</slf4j.provider.implementation> <slf4j.provider.implementation>org.slf4j.simple.SimpleServiceProvider</slf4j.provider.implementation>
<slf4j.provider.type>simple</slf4j.provider.type> <slf4j.provider.type>simple</slf4j.provider.type>
</properties> </properties>
@ -39,10 +38,4 @@
</dependencies> </dependencies>
<build>
<plugins>
</plugins>
</build>
</project> </project>

0
slf4j-simple/src/main/java/module-info.java Normal file → Executable file
View File

View File

@ -221,10 +221,10 @@ public class SimpleLogger extends LegacyAbstractLogger {
public static final String DEFAULT_LOG_LEVEL_KEY = SimpleLogger.SYSTEM_PREFIX + "defaultLogLevel"; public static final String DEFAULT_LOG_LEVEL_KEY = SimpleLogger.SYSTEM_PREFIX + "defaultLogLevel";
/** /**
* Protected access allows only {@link SimpleLoggerFactory} and also derived classes to instantiate * Package access allows only {@link SimpleLoggerFactory} to instantiate
* SimpleLogger instances. * SimpleLogger instances.
*/ */
protected SimpleLogger(String name) { SimpleLogger(String name) {
this.name = name; this.name = name;
String levelString = recursivelyComputeLevelString(); String levelString = recursivelyComputeLevelString();
@ -409,7 +409,7 @@ public class SimpleLogger extends LegacyAbstractLogger {
buf.append('['); buf.append('[');
// Append a readable representation of the log level // Append a readable representation of the log level
String levelStr = renderLevel(level.toInt()); String levelStr = level.name();
buf.append(levelStr); buf.append(levelStr);
if (CONFIG_PARAMS.levelInBrackets) if (CONFIG_PARAMS.levelInBrackets)
buf.append(']'); buf.append(']');
@ -439,22 +439,6 @@ public class SimpleLogger extends LegacyAbstractLogger {
write(buf, t); write(buf, t);
} }
protected String renderLevel(int levelInt) {
switch (levelInt) {
case LOG_LEVEL_TRACE:
return "TRACE";
case LOG_LEVEL_DEBUG:
return("DEBUG");
case LOG_LEVEL_INFO:
return "INFO";
case LOG_LEVEL_WARN:
return CONFIG_PARAMS.warnLevelString;
case LOG_LEVEL_ERROR:
return "ERROR";
}
throw new IllegalStateException("Unrecognized level ["+levelInt+"]");
}
public void log(LoggingEvent event) { public void log(LoggingEvent event) {
int levelInt = event.getLevel().toInt(); int levelInt = event.getLevel().toInt();

View File

@ -47,19 +47,16 @@ public class SimpleLoggerFactory implements ILoggerFactory {
/** /**
* Return an appropriate {@link SimpleLogger} instance by name. * Return an appropriate {@link SimpleLogger} instance by name.
*
* This method will call {@link #createLogger(String)} if the logger
* has not been created yet.
*/ */
public Logger getLogger(String name) { public Logger getLogger(String name) {
return loggerMap.computeIfAbsent(name, this::createLogger); Logger simpleLogger = loggerMap.get(name);
} if (simpleLogger != null) {
return simpleLogger;
/** } else {
* Actually creates the logger for the given name. Logger newInstance = new SimpleLogger(name);
*/ Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
protected Logger createLogger(String name) { return oldInstance == null ? newInstance : oldInstance;
return new SimpleLogger(name); }
} }
/** /**
@ -71,7 +68,7 @@ public class SimpleLoggerFactory implements ILoggerFactory {
* *
* You are strongly discouraged from calling this method in production code. * You are strongly discouraged from calling this method in production code.
*/ */
protected void reset() { void reset() {
loggerMap.clear(); loggerMap.clear();
} }
} }

View File

@ -17,16 +17,8 @@ public class SimpleServiceProvider implements SLF4JServiceProvider {
public static String REQUESTED_API_VERSION = "2.0.99"; // !final public static String REQUESTED_API_VERSION = "2.0.99"; // !final
private ILoggerFactory loggerFactory; private ILoggerFactory loggerFactory;
// LoggerFactory expects providers to initialize markerFactory as early as possible. private IMarkerFactory markerFactory;
private final IMarkerFactory markerFactory; private MDCAdapter mdcAdapter;
// LoggerFactory expects providers to initialize their MDCAdapter field
// as early as possible, preferably at construction time.
private final MDCAdapter mdcAdapter;
public SimpleServiceProvider() {
markerFactory = new BasicMarkerFactory();
mdcAdapter = new NOPMDCAdapter();
}
public ILoggerFactory getLoggerFactory() { public ILoggerFactory getLoggerFactory() {
return loggerFactory; return loggerFactory;
@ -49,8 +41,10 @@ public class SimpleServiceProvider implements SLF4JServiceProvider {
@Override @Override
public void initialize() { public void initialize() {
loggerFactory = new SimpleLoggerFactory();
loggerFactory = new SimpleLoggerFactory();
markerFactory = new BasicMarkerFactory();
mdcAdapter = new NOPMDCAdapter();
} }
} }

View File

@ -1,53 +0,0 @@
package org.slf4j.simple;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.event.Level;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertTrue;
/**
* Test class to verify configuration parameters of SimpleLogger
*
* @since 2.0.18
*/
public class ConfigParamsTest {
private ListAppendingOutputStream prepareSink(List<String> outputList) {
return new ListAppendingOutputStream(outputList);
}
@BeforeClass
static public void resetConfigParams() {
SimpleLogger.CONFIG_PARAMS.init();
}
public Logger createLogger(ListAppendingOutputStream outputStream, Level level, String warnLevelString) {
SimpleLogger.CONFIG_PARAMS.outputChoice = new OutputChoice(new PrintStream(outputStream));
SimpleLogger.CONFIG_PARAMS.warnLevelString = warnLevelString;
SimpleLogger logger = new SimpleLogger(ConfigParamsTest.class.getName());
logger.currentLogLevel = SimpleLoggerConfiguration.stringToLevel(level.toString());
return logger;
}
@Test
public void simpleTest(){
String WARN_LEVEL_STRING = "WXYZ";
ArrayList<String> outputList = new ArrayList<>();
Logger configuredLogger = createLogger(prepareSink(outputList), Level.TRACE, WARN_LEVEL_STRING);
configuredLogger.warn("This is a test");
String str0 = outputList.get(0);
assertTrue(str0.contains(WARN_LEVEL_STRING));
}
}

View File

@ -1,25 +0,0 @@
package org.slf4j.simple;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class ListAppendingOutputStream extends OutputStream {
private final StringBuilder stringBuilder = new StringBuilder();
private final List<String> targetList;
ListAppendingOutputStream(List<String> list) {this.targetList = list;}
@Override
public void write(int b) throws IOException {
stringBuilder.append((char) b);
}
@Override
public void flush() {
targetList.add(stringBuilder.toString());
stringBuilder.delete(0, stringBuilder.length());
}
}

View File

@ -1,359 +0,0 @@
package org.slf4j.simple;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.event.Level;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Acceptance tests for the slf4j-simple SimpleLogger implementation.
*
* <p>This concrete JUnit test class exercises logging at different levels
* (TRACE, DEBUG, INFO, WARN, ERROR), verifies message formatting, and
* checks exception logging behavior. The class contains helper methods to
* create a logger that writes into a supplied {@link ListAppendingOutputStream}
* and to extract message and exception details from produced log lines.</p>
*
* <p>Important: these tests are predicated on the fact that {@code SimpleLogger}
* invokes {@code flush()} on the provided output stream after writing each
* log entry and that each logging event is accumulated into a single entry of
* the backing {@code List<String>} fiels in {@link ListAppendingOutputStream}.
* </p>
*
* <p>Each logging event including events that contain a {@code Throwable}
* and produce stacktrace lines is accumulated into the {@code targetList}
* field of {@link ListAppendingOutputStream} as a single entry representing
* the entire event. Tests expect one list element per logging event.</p>
*
*/
public class SimpleLoggerAcceptanceTest {
/**
* Create a {@link ListAppendingOutputStream} backed by the supplied list.
*
* <p>This helper returns an output stream that accumulates written text
* lines into the provided list. Tests rely on the {@code SimpleLogger}
* implementation to invoke {@code flush()} on the provided stream after
* writing each log entry so that bytes are converted into list entries and
* visible to assertions. </p>
*
* <p>Each logging event (including a {@code Throwable} and its stacktrace)
* is collected by {@code ListAppendingOutputStream} into a single element
* in its {@code targetList} field; tests expect one string element per event.</p>
*
* @param outputList the list which will receive captured log lines
* @return a new ListAppendingOutputStream writing into the supplied list
*/
private ListAppendingOutputStream prepareSink(List<String> outputList) {
return new ListAppendingOutputStream(outputList);
}
/**
* Extracts only the part of the log string that should represent the `message` string.
*
* @param message the full log message
* @return only the supplied message
*/
public String extractMessage(String message) {
// Example log line:
// [main] INFO TestSuiteLogger - An exception occurred: 99
return message
.split("\n")[0]
.split("- ")[1];
}
/**
* Extracts only the part of the log string that should represent the supplied exception message, if any.
*
* @param message the full log message
* @return only the supplied exception message
*/
public String extractExceptionMessage(String message) {
// Example log lines:
// [main] INFO TestSuiteLogger - An exception occurred: 99
// java.lang.IllegalArgumentException: Invalid argument
// at org.slf4j.simple.SimpleLoggerAcceptanceTest.testExceptionParameterFormatting(SimpleLoggerAcceptanceTest.java:274)
String[] logLines = message.split("\n");
if(logLines.length < 2) {
return null;
}
String exceptionLine = logLines[1];
return exceptionLine.split(": ")[1];
}
/**
* Extracts only the part of the log string that should represent the supplied exception type.
*
* @param message the full log message
* @return only the supplied exception type name
*/
public String extractExceptionType(String message) {
String[] logLines = message.split("\n");
if(logLines.length < 2) {
return null;
}
String exceptionLine = logLines[1];
return exceptionLine.split(": ")[0];
}
/**
* Configures the logger for running the tests.
*
* @param outputStream The output stream for logs to be written to
* @param level The expected level the tests will run for this logger
* @return a configured logger able to run the tests
*/
public Logger createLogger(ListAppendingOutputStream outputStream, Level level) {
SimpleLogger.CONFIG_PARAMS.outputChoice = new OutputChoice(new PrintStream(outputStream));
SimpleLogger logger = new SimpleLogger("TestSuiteLogger");
logger.currentLogLevel = SimpleLoggerConfiguration.stringToLevel(level.toString());
return logger;
}
@Test
public void testTrace() {
ArrayList<String> outputList = new ArrayList<>();
Logger configuredLogger = createLogger(prepareSink(outputList), Level.TRACE);
assertTrue("Trace level should be enabled for this test", configuredLogger.isTraceEnabled());
configuredLogger.trace("Simple trace message");
assertEquals("Trace message should've been captured", 1, outputList.size());
assertTrue("Message should be logged in trace level", isTraceMessage(outputList.get(0)));
assertEquals("Supplied trace message wasn't found in the log",
"Simple trace message",
extractMessage(outputList.get(0)));
outputList.clear();
configuredLogger.debug("Simple debug message");
configuredLogger.info("Simple info message");
configuredLogger.warn("Simple warn message");
configuredLogger.error("Simple error message");
assertEquals("The other levels should have been captured", 4, outputList.size());
}
@Test
public void testDebug() {
ArrayList<String> outputList = new ArrayList<>();
Logger configuredLogger = createLogger(prepareSink(outputList), Level.DEBUG);
configuredLogger.trace("Simple trace message");
assertEquals("Lower levels should have been ignored", 0, outputList.size());
assertTrue("Debug level should be enabled for this test", configuredLogger.isDebugEnabled());
configuredLogger.debug("Simple debug message");
assertEquals("Debug message should've been captured", 1, outputList.size());
assertTrue("Message should be logged in debug level", isDebugMessage(outputList.get(0)));
assertEquals("Supplied debug message wasn't found in the log",
"Simple debug message",
extractMessage(outputList.get(0)));
outputList.clear();
configuredLogger.info("Simple info message");
configuredLogger.warn("Simple warn message");
configuredLogger.error("Simple error message");
assertEquals("The other levels should have been captured", 3, outputList.size());
}
@Test
public void testInfo() {
ArrayList<String> outputList = new ArrayList<>();
Logger configuredLogger = createLogger(prepareSink(outputList), Level.INFO);
configuredLogger.trace("Simple trace message");
configuredLogger.debug("Simple debug message");
assertEquals("Lower levels should have been ignored", 0, outputList.size());
assertTrue("Info level should be enabled for this test", configuredLogger.isInfoEnabled());
configuredLogger.info("Simple info message");
assertEquals("Info message should've been captured", 1, outputList.size());
assertTrue("Message should be logged in debug level", isInfoMessage(outputList.get(0)));
assertEquals("Supplied info message wasn't found in the log",
"Simple info message",
extractMessage(outputList.get(0)));
outputList.clear();
configuredLogger.warn("Simple warn message");
configuredLogger.error("Simple error message");
assertEquals("The other levels should have been captured", 2, outputList.size());
}
@Test
public void testWarn() {
ArrayList<String> outputList = new ArrayList<>();
Logger configuredLogger = createLogger(prepareSink(outputList), Level.WARN);
configuredLogger.trace("Simple trace message");
configuredLogger.debug("Simple debug message");
configuredLogger.info("Simple info message");
assertEquals("Lower levels should have been ignored", 0, outputList.size());
assertTrue("Warn level should be enabled for this test", configuredLogger.isWarnEnabled());
configuredLogger.warn("Simple warn message");
assertEquals("Warn message should've been captured", 1, outputList.size());
assertTrue("Message should be logged in warn level", isWarnMessage(outputList.get(0)));
assertEquals("Supplied warn message wasn't found in the log",
"Simple warn message",
extractMessage(outputList.get(0)));
outputList.clear();
configuredLogger.error("Simple error message");
assertEquals("The other levels should have been captured", 1, outputList.size());
}
@Test
public void testError() {
ArrayList<String> outputList = new ArrayList<>();
Logger configuredLogger = createLogger(prepareSink(outputList), Level.ERROR);
configuredLogger.trace("Simple trace message");
configuredLogger.debug("Simple debug message");
configuredLogger.info("Simple info message");
configuredLogger.warn("Simple warn message");
assertEquals("Lower levels should have been ignored", 0, outputList.size());
assertTrue("Error level should be enabled for this test", configuredLogger.isErrorEnabled());
configuredLogger.error("Simple error message");
assertEquals("Error message should've been captured", 1, outputList.size());
assertTrue("Message should be logged in error level", isErrorMessage(outputList.get(0)));
assertEquals("Supplied error message wasn't found in the log",
"Simple error message",
extractMessage(outputList.get(0)));
}
@Test
public void testFormatting() {
ArrayList<String> outputList = new ArrayList<>();
Logger configuredLogger = createLogger(prepareSink(outputList), Level.INFO);
configuredLogger.info("Some {} string", "formatted");
assertEquals("The formatted message should've been captured", 1, outputList.size());
assertEquals("Message should've been formatted", "Some formatted string", extractMessage(outputList.get(0)));
}
@Test
public void testException() {
ArrayList<String> outputList = new ArrayList<>();
Logger configuredLogger = createLogger(prepareSink(outputList), Level.INFO);
Exception exception = new RuntimeException("My error");
configuredLogger.info("Logging with an exception", exception);
assertEquals("The formatted message should've been captured", 1, outputList.size());
assertEquals("Message should've been formatted",
"My error",
extractExceptionMessage(outputList.get(0)));
assertEquals("Message should've been formatted",
"java.lang.RuntimeException",
extractExceptionType(outputList.get(0)));
}
@Test
public void testExceptionParameterFormatting() {
ArrayList<String> outputList = new ArrayList<>();
Logger configuredLogger = createLogger(prepareSink(outputList), Level.INFO);
Exception exception = new IllegalArgumentException("Invalid argument");
configuredLogger.info("An exception occurred: {}", 99, exception);
assertEquals("The formatted message should've been captured", 1, outputList.size());
assertEquals("Message should've been formatted",
"An exception occurred: 99",
extractMessage(outputList.get(0)));
assertEquals("Exception type should've been captured",
"java.lang.IllegalArgumentException",
extractExceptionType(outputList.get(0)));
configuredLogger.info("Another exception occurred: {} {}", exception, 99);
assertEquals("The formatted message should've been captured", 2, outputList.size());
assertEquals("Message should've been formatted",
"Another exception occurred: java.lang.IllegalArgumentException: Invalid argument 99",
extractMessage(outputList.get(1)));
AtomicInteger atomicInteger = new AtomicInteger();
outputList.forEach(s -> System.out.println("x Log line " + (atomicInteger.getAndIncrement()) + ": " + s));
}
/**
* Allows tests to check whether the log message contains a trace message.
* Override if needed.
*
* @param message String containing the full log message
* @return whether it is a trace message or not
*/
protected boolean isTraceMessage(String message) {
return message.toLowerCase().contains("trace");
}
/**
* Allows tests to check whether the log message contains a debug message.
* Override if needed.
*
* @param message String containing the full log message
* @return whether it is a debug message or not
*/
protected boolean isDebugMessage(String message) {
return message.toLowerCase().contains("debug");
}
/**
* Allows tests to check whether the log message contains an info message.
* Override if needed.
*
* @param message String containing the full log message
* @return whether it is an info message or not
*/
protected boolean isInfoMessage(String message) {
return message.toLowerCase().contains("info");
}
/**
* Allows tests to check whether the log message contains a warn message.
* Override if needed.
*
* @param message String containing the full log message
* @return whether it is a warn message or not
*/
protected boolean isWarnMessage(String message) {
return message.toLowerCase().contains("warn");
}
/**
* Allows tests to check whether the log message contains an error message.
* Override if needed.
*
* @param message String containing the full log message
* @return whether it is an error message or not
*/
protected boolean isErrorMessage(String message) {
return message.toLowerCase().contains("error");
}
}

View File

@ -1,21 +0,0 @@
package org.slf4j.simple;
import org.junit.Test;
import org.slf4j.helpers.Slf4jEnvUtil;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class Slf4jVersionTest {
@Test
public void slf4jVersionTest() {
String version = Slf4jEnvUtil.slf4jVersion();
assertNotNull(version);
assertTrue(version.startsWith("3"));
}
}

View File

@ -7,14 +7,14 @@
<parent> <parent>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId> <artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version> <version>2.1.0-alpha0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
<artifactId>slf4j-testing</artifactId> <artifactId>slf4j-testing</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>SLF4J Common Testing</name> <name>SLF4J Common Testing</name>
<description>SLF4J Common testing</description> <description>SLF4J Common testing </description>
<url>http://www.slf4j.org</url> <url>http://www.slf4j.org</url>
<properties> <properties>

View File

@ -1,10 +1,7 @@
package org.slf4j.testing; package org.slf4j.testing;
import org.junit.Test; import static org.junit.Assert.assertTrue;
import org.slf4j.Logger; import static org.junit.Assert.fail;
import org.slf4j.LoggerFactory;
import org.slf4j.event.EventRecordingLogger;
import org.slf4j.helpers.SubstituteLogger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -13,10 +10,14 @@ import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import static org.junit.Assert.fail; import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.EventRecordingLogger;
import org.slf4j.helpers.SubstituteLogger;
abstract public class MultithreadedInitializationTest { abstract public class MultithreadedInitializationTest {
final protected static int THREAD_COUNT = 1;//4 + Runtime.getRuntime().availableProcessors() * 2; final protected static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2;
private final List<Logger> createdLoggers = Collections.synchronizedList(new ArrayList<>()); private final List<Logger> createdLoggers = Collections.synchronizedList(new ArrayList<>());
@ -34,7 +35,7 @@ abstract public class MultithreadedInitializationTest {
assertAllSubstLoggersAreFixed(); assertAllSubstLoggersAreFixed();
long recordedEventCount = getRecordedEventCount(); long recordedEventCount = getRecordedEventCount();
int LENIENCY_COUNT = 30; int LENIENCY_COUNT = 21;
long expectedEventCount = eventCount.get() + extraLogEvents(); long expectedEventCount = eventCount.get() + extraLogEvents();