Compare commits

..

65 Commits

Author SHA1 Message Date
ceki 6e66c3f419 SLF4JPlatformLogger.isLoggable should handle Logger.ALL and Logger.OFF in a coherent fashion
relates to https://github.com/qos-ch/slf4j/issues/430

Signed-off-by: ceki <ceki@qos.ch>
2026-08-07 15:17:14 +02:00
ceki 1febf07dc0 update Slf4jVersionTest to expect 3.0
Signed-off-by: ceki <ceki@qos.ch>
2026-08-07 15:15:03 +02:00
ceki ff224725c9 given the bump to JDK 11, bumb the major version to 3 instead of 2
Signed-off-by: ceki <ceki@qos.ch>
2026-08-07 14:59:04 +02:00
arimu1 8068f198ee fix(api): guard addKeyValue value toString from fatal errors
When a key-value value's toString() throws (including StackOverflowError),
mergeKeyValuePairs previously aborted logging. MessageFormatter already
substitutes [FAILED toString()] for message arguments; apply the same
protection when formatting key-value pairs into the merged message.

Fixes #448

Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com>
2026-08-06 08:39:14 +02:00
arimu1 55e67102a8 fix(build): package each module's LICENSE.txt into JAR META-INF
Parent resources previously copied the repo-root MIT LICENSE into every
module JAR. Apache-2.0 modules (jcl-over-slf4j, log4j-over-slf4j) already
have the correct LICENSE.txt at the module root, but it was never packaged.

Use ${project.basedir}/LICENSE.txt so META-INF/LICENSE.txt matches the
module's declared license (Apache-2.0 or MIT).

Fixes #465

Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com>
2026-08-06 08:33:53 +02:00
ceki 0bf9797444 renamed LoggerTestSuite.java as SimpleLoggerAcceptanceTest
Signed-off-by: ceki <ceki@qos.ch>
2025-12-16 21:27:36 +01:00
ceki ffa6367c7a move module-info.java from java9 to java
Signed-off-by: ceki <ceki@qos.ch>
2025-12-16 17:59:30 +01:00
ceki 2af556252c required JDK to 11
Signed-off-by: ceki <ceki@qos.ch>
2025-12-16 17:57:15 +01:00
ceki b4803aaf56 extract first marker when caller locationAwareLogger
Signed-off-by: ceki <ceki@qos.ch>
2025-12-16 16:44:00 +01:00
ceki dd19e9a33b add a trivial test for CONFIG_PARAMS.warnLevelString
Signed-off-by: ceki <ceki@qos.ch>
2025-12-16 16:36:53 +01:00
ceki b5bb565347 CONFIG_PARAMS.warnLevelString should be taken into account
See https://github.com/qos-ch/slf4j/issues/471

Signed-off-by: ceki <ceki@qos.ch>
2025-12-16 16:35:45 +01:00
ceki 05731e8bda minor refactoring, javadoc changes
Signed-off-by: ceki <ceki@qos.ch>
2025-11-24 17:53:05 +01:00
ceki ac947b0104 remove cruft
Signed-off-by: ceki <ceki@qos.ch>
2025-10-01 16:59:04 +02:00
ceki 59da7b69ec security manager is no longer supported in later JDKs
Signed-off-by: ceki <ceki@qos.ch>
2025-10-01 16:58:51 +02:00
ceki 46e23e75d3 remove unneccessary and unused files
Signed-off-by: ceki <ceki@qos.ch>
2025-10-01 16:58:23 +02:00
Ceki Gulcu 40b3e519f2 In SLF4JProviders, move initialization of the markerFactory and
mdcAdapter fields to the constructor.

Added comments regarding LoggerFactory expectation of providers to
initialize their MDCAdapter and markerFactory field as early as
possible, preferably at construction time.

Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2025-02-25 18:43:09 +01:00
Ceki Gulcu 9bd0374b52 In response to issue 450, moved the binding of the MDCAdapter in the
MDC class from the static initializer to the LoggerFactory.bind method.

In case MDC methods are called before LoggerFactory, the various methods
in MDC have been modified to go through the getMDCAdapter method which
checks for this rare case.

https://github.com/qos-ch/slf4j/issues/450

Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2025-02-25 18:41:40 +01:00
Julien HENRY 1a5c37e192 Fix JavaDoc of MDCAmbit.java 2024-12-12 10:01:36 +01:00
Piotr P. Karwasz b69c1b324d Replace license names with SPDX identifiers
As suggested by [Maven documentation](https://maven.apache.org/pom.html#Licenses) the `/project/licenses/licence/name` element in the POM file should contain a SPDX identifier of the license.
The license element is often used by external tools, such as SBOM generators.

This PR:

- Replaces the current content of the `<name>` element with the appropriate SPDX identifier.
- Follows all HTTP 301 redirections of the currently provided license URLs.

Signed-off-by: Piotr P. Karwasz <piotr.github@karwasz.org>
2024-12-10 11:04:38 +01:00
Ceki Gülcü fdc4a8579d Update README.md 2024-10-21 21:00:00 +02:00
Ceki Gülcü b7406c6679 Update README.md 2024-10-21 20:59:51 +02:00
Ceki Gulcu 00e1210276 README updates
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-10-21 20:59:29 +02:00
Ceki Gulcu 2a91eee698 fix incorrect interpretation of Level.OFF and Level.ALL in SLF4JPlatformLogger
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-10-21 20:58:25 +02:00
Ceki Gulcu fa7c18f7e7 fix issues/425
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-10-21 20:56:22 +02:00
Ceki Gulcu 914e8c8f5a cherry pick changes 3ff00870b3 from 2.0, print connected provider only if DEBUG level for internal reporting is enabled
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-08-10 10:25:20 +02:00
Manfred Hanke caeccff0db fix javadoc of Slf4jEnvUtil
resolves #423

Signed-off-by: Manfred Hanke <Manfred.Hanke@tngtech.com>
2024-08-08 22:26:07 +02:00
Ceki Gulcu 0fe25e2eb0 added copyright, @since to Slf4jEnvUtil
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-08-07 22:48:12 +02:00
Ceki Gulcu 19ca97d751 align with version 2.0.14
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-08-07 22:47:51 +02:00
Ceki Gulcu a735039012 fix issues/409 SLF4J-601, wrong classname when using slf4j inside a wrapper
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-04-12 15:48:47 +02:00
Ceki Gulcu a29e4b8629 providers should open their main packages, allow org.slf4j reeflection
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-02-05 22:39:28 +01:00
Ceki Gulcu cd1468685b increase leniency count
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-02-05 22:37:13 +01:00
Ceki Gulcu 7b04a6cda8 revert Util.report methods removed by mistake
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-02-05 22:33:45 +01:00
Ceki Gulcu f1fc5a14a8 more comments
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-01-23 15:52:22 +01:00
Ceki Gulcu 1d7785cec9 acceptance test, disabled for the moment
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-01-08 18:51:20 +01:00
Guillaume Nodet 1915ef81ca Use computeIfAbsent with a protected method, make reset protected
Signed-off-by: Guillaume Nodet <gnodet@gmail.com>
2024-01-08 17:42:21 +01:00
Ceki Gulcu 31a3a8d1f3 javadoc changed for SimpleLogger constructor
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-01-08 15:28:04 +01:00
Ceki Gulcu 42501efe52 change constructor access modifier instead of
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-01-08 15:27:55 +01:00
Ceki Gulcu 85d905cb6e add renderLevel method in SimpleLogger
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-01-08 15:07:10 +01:00
Ceki Gulcu 7aa44f3171 start work on version 2.1.0-alpha2-SNAPSHOT
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-01-02 20:43:20 +01:00
Ceki Gulcu d0fe6310eb prepare release 2.1.0-alpha1
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-01-02 20:20:46 +01:00
Ceki Gulcu 6aa9a6e0ff continued reversion to mixed jdk 8 and 9 requirement
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-01-02 19:53:36 +01:00
Ceki Gulcu c63a840d8d revert to mixed jdk 8 and 9 requirement
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2024-01-02 19:40:21 +01:00
Ceki Gulcu f4adff9ae3 start work on 2.1.0-alpha1-SNAPSHOT
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-29 00:05:12 +01:00
Ceki Gulcu 037b7258c5 do not deploy slf4j-testing
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-28 20:40:02 +01:00
Ceki Gulcu 372e029c34 prepare release 2.1.0-alpha0
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-28 20:22:52 +01:00
Ceki Gulcu 2cec82beec minor edits
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-28 20:19:48 +01:00
Ceki Gulcu aafbd0499f moving the javadoc plugin config from parent/pom.xml to ./pom.xml made a big difference, javadoc edits
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-23 20:55:49 +01:00
Ceki Gulcu 9af7ed283b more tinkering with the javadocs
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-22 22:19:53 +01:00
Ceki Gulcu b56795ba5f add historical notes in the javadocs for LocationAwareLogger
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-22 16:24:08 +01:00
Ceki Gulcu f3fedc2e69 add kv() methods as synonyms for addKeyValue(), add kv() catering for primitives
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-22 16:22:56 +01:00
Ceki Gulcu 8a72658cb8 javadoc changes
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-22 11:06:09 +01:00
Ceki Gulcu 154b4e4afa issues/375 add arg(primitiveType) methods in LoggingEventBuilder interface
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-22 10:52:24 +01:00
Ceki Gulcu 93722a121b add run/call methods in MDCAmbit
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-21 20:27:55 +01:00
Ceki Gulcu e3205a47ce improve javadocs
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-21 19:58:46 +01:00
Ceki Gulcu 30295c847a further JIGSAW/JMPS modularization of slf4j
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-19 20:38:20 +01:00
Ceki Gulcu 8f8691065d migrate to Java 11
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-18 22:54:49 +01:00
Ceki Gulcu c573117a91 bump requirement to Java 11
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-18 14:41:15 +01:00
Ceki Gulcu 50b9f5df11 rename MDCHelper as MDCAmbit, rename removeSet() method as clear()
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-18 14:31:44 +01:00
Ceki Gulcu 98812ca93b start work on 2.1.0-alpha0-SNAPSHOT
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-18 14:22:23 +01:00
Ceki Gulcu 13ea69236d rename MDCHelper as MDCAmbit
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-18 14:20:39 +01:00
Ceki Gulcu ce201ea248 more tests, more javadocs
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-07 13:37:59 +01:00
Ceki Gulcu 0497273648 add more usage examples
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-07 11:59:09 +01:00
Ceki Gulcu 2597366200 make MDCHelper more testing friendly
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-06 22:17:49 +01:00
Ceki Gulcu ff981fd20f add javadoc to MDCHelper
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-06 22:15:34 +01:00
Ceki Gulcu 4909d1d81a move MDCHelper to org.slf4j
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
2023-12-06 21:54:00 +01:00
98 changed files with 2150 additions and 792 deletions

22
AGENTS.md Normal file
View File

@ -0,0 +1,22 @@
# 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

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

View File

@ -61,7 +61,6 @@ public class MultiBindingAssertionTest {
assertMsgContains(list, line++, "Found provider");
assertMsgContains(list, line++, "Found provider");
assertMsgContains(list, line++, "See https://www.slf4j.org/codes.html#multiple_bindings for an explanation.");
//assertMsgContains(list, line++, "SLF4J(D): Connected with provider of type [");
}
void assertMsgContains(List<String> strList, int index, String msg) {

View File

@ -0,0 +1,67 @@
<?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"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jcl-over-slf4j-blackbox</artifactId>
<packaging>jar</packaging>
<name>jcl-over-slf4j blackbox testing</name>
<description>jcl-over-slf4j blackbox testing</description>
<url>http://www.slf4j.org</url>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,7 @@
module org.apache.commons.logging.blackbox {
requires org.slf4j;
requires org.slf4j.jul;
requires org.apache.commons.logging;
requires java.logging;
requires junit;
}

View File

@ -22,7 +22,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.apache.commons.logging.test;
package org.apache.commons.logging.blackbox;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -36,6 +36,7 @@ import org.apache.commons.logging.impl.SLF4JLocationAwareLog;
import org.apache.commons.logging.impl.SLF4JLog;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.jul.JDK14LoggerFactory;
import org.slf4j.spi.LocationAwareLogger;

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@ -14,7 +14,7 @@
<artifactId>jcl-over-slf4j</artifactId>
<packaging>jar</packaging>
<name>JCL 1.2 implemented over SLF4J</name>
<description>JCL 1.2 implemented over SLF4J</description>
<description>Jakarta/Apache commons logging 1.2 implemented over SLF4J</description>
<url>http://www.slf4j.org</url>
<licenses>

View File

@ -0,0 +1,8 @@
/**
* Jakarta/Apache Commons Logging implemented over SLF4J.
*/
module org.apache.commons.logging {
requires org.slf4j;
exports org.apache.commons.logging;
exports org.apache.commons.logging.impl;
}

View File

@ -0,0 +1,151 @@
/**
* <p>Jakarta Commons Logging implemented over SLF4J.</p>
*
*
* <h3>Overview</h3>
*
* <p>This package contains the same public user interface as <a
* href="http://jakarta.apache.org/commons/logging/">Jakarta Commons
* Logging (JCL)</a>. <b>It is intended as a 100% compatible drop-in
* replacement for the original JCL version 1.0.4</b>.
* </p>
*
* <p>As the original JCL version 1.0.4, the present version supports
* various logging APIs. It differs from the original in implementation
* but not the public API. This implementation uses SLF4J under the
* covers. As such, all the logging systems that SLF4J supports,
* e.g. NOP, Simple, logback, java.util.logging, log4j 1.x are supported
* indirectly by this version of JCL via SLF4J.
* </p>
*
* <h3>Quick Start Guide</h3>
*
* <p>For those impatient to just get on with it, the following example
* illustrates the typical declaration and use of a logger that is named (by
* convention) after the calling class:
*
* <pre>
* import org.apache.commons.logging.Log;
* import org.apache.commons.logging.LogFactory;
*
* public class Foo {
*
* static Log log = LogFactory.getLog(Foo.class);
*
* public void foo() {
* ...
* try {
* if (log.isDebugEnabled()) {
* log.debug("About to do something to object " + name);
* }
* name.bar();
* } catch (IllegalStateException e) {
* log.error("Something bad happened to " + name, e);
* }
* ...
* }
* </pre>
*
* <h3>Configuring the Commons Logging Package</h3>
*
* <p>In this version of JCL, the selection of the logging system to use
* is chosen by SLF4J at initialization time. Consequently, all JCL-specific
* configuration parameters are ignored.
* </p>
*
* <h4>Choosing a <code>LogFactory</code> Implementation</h4>
*
* <p>From an application perspective, the first requirement is to
* retrieve an object reference to the <code>LogFactory</code> instance
* that will be used to create <code><a href="Log.html">Log</a></code>
* instances for this application. This is normally accomplished by
* calling the static <code>getFactory()</code> method. This method
* always returns the same factory, i.e. a unique instance of the <a
* href="impl/SLF4FLogFactory.html">SLF4FLogFactory</a> class.
* </p>
*
*
*
* <h4>Configuring the Underlying Logging System</h4>
*
* <p>The basic principle is that the user is totally responsible for the
* configuration of the underlying logging system.
* Commons-logging should not change the existing configuration.</p>
*
* <p>Each individual <a href="Log.html">Log</a> implementation may
* support its own configuration properties. These will be documented in the
* class descriptions for the corresponding implementation class.</p>
*
* <p>Finally, some <code>Log</code> implementations (such logback or log4j)
* require an external configuration file for the entire logging environment.
* This file should be prepared in a manner that is specific to the actual logging
* technology being used.</p>
*
*
* <h3>Using the Logging Package APIs</h3>
*
* <p>Use of the Logging Package APIs, from the perspective of an application
* component, consists of the following steps:</p>
* <ol>
* <li>Acquire a reference to an instance of
* <a href="Log.html">org.apache.commons.logging.Log</a>, by calling the
* factory method
* <a href="LogFactory.html#getInstance(java.lang.String)">
* LogFactory.getInstance(String name)</a>. Your application can contain
* references to multiple loggers that are used for different
* purposes. A typical scenario for a server application is to have each
* major component of the server use its own Log instance.</li>
* <li>Cause messages to be logged (if the corresponding detail level is enabled)
* by calling appropriate methods (<code>trace()</code>, <code>debug()</code>,
* <code>info()</code>, <code>warn()</code>, <code>error</code>, and
* <code>fatal()</code>).</li>
* </ol>
*
* <p>For convenience, <code>LogFactory</code> also offers a static method
* <code>getLog()</code> that combines the typical two-step pattern:</p>
* <pre>
* Log log = LogFactory.getFactory().getInstance(Foo.class);
* </pre>
* <p>into a single method call:</p>
* <pre>
* Log log = LogFactory.getLog(Foo.class);
* </pre>
*
* <p>For example, you might use the following technique to initialize and
* use a <a href="Log.html">Log</a> instance in an application component:</p>
* <pre>
* import org.apache.commons.logging.Log;
* import org.apache.commons.logging.LogFactory;
*
* public class MyComponent {
*
* protected static Log log =
* LogFactory.getLog(MyComponent.class);
*
* // Called once at startup time
* public void start() {
* ...
* log.info("MyComponent started");
* ...
* }
*
* // Called once at shutdown time
* public void stop() {
* ...
* log.info("MyComponent stopped");
* ...
* }
*
* // Called repeatedly to process a particular argument value
* // which you want logged if debugging is enabled
* public void process(String value) {
* ...
* // Do the string concatenation only if logging is enabled
* if (log.isDebugEnabled())
* log.debug("MyComponent processing " + value);
* ...
* }
* }
*
*/
package org.apache.commons.logging;

View File

@ -1,169 +0,0 @@
<!--
Copyright 2001-2004 The Apache Software Foundation.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<body>
<p>Jakarta Commons Logging implemented over SLF4J.</p>
<h3>Overview</h3>
<p>This package contains the same public user interface as <a
href="http://jakarta.apache.org/commons/logging/">Jakarta Commons
Logging (JCL)</a>. It is intended as a 100% compatible drop-in
replacement for the original JCL version 1.0.4.
</p>
<p>As the original JCL version 1.0.4, the present version supports
various logging APIs. It differs from the original in implementation
but not the public API. This implementation uses SLF4J under the
covers. As such, all the logging systems that SLF4J supports,
e.g. NOP, Simple, JDK14, nlog4j are supported by this version of JCL.
</p>
<h3>Quick Start Guide</h3>
<p>For those impatient to just get on with it, the following example
illustrates the typical declaration and use of a logger that is named (by
convention) after the calling class:
<pre>
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Foo {
static Log log = LogFactory.getLog(Foo.class);
public void foo() {
...
try {
if (log.isDebugEnabled()) {
log.debug("About to do something to object " + name);
}
name.bar();
} catch (IllegalStateException e) {
log.error("Something bad happened to " + name, e);
}
...
}
</pre>
<h3>Configuring the Commons Logging Package</h3>
<p>In this version of JCL, the selection of the logging system to use
is chosen by the underlying SLF4J API. Consequently, all JCL-specific
configuration parameters are ignored.
</p>
<h4>Choosing a <code>LogFactory</code> Implementation</h4>
<p>From an application perspective, the first requirement is to
retrieve an object reference to the <code>LogFactory</code> instance
that will be used to create <code><a href="Log.html">Log</a></code>
instances for this application. This is normally accomplished by
calling the static <code>getFactory()</code> method. This method
always returns the same factory, i.e. a unique instance of the <a
href="impl/SLF4FLogFactory.html">SLF4FLogFactory</a> class.
</p>
<h4>Configuring the Underlying Logging System</h4>
<p>The basic principle is that the user is totally responsible for the
configuration of the underlying logging system.
Commons-logging should not change the existing configuration.</p>
<p>Each individual <a href="Log.html">Log</a> implementation may
support its own configuration properties. These will be documented in the
class descriptions for the corresponding implementation class.</p>
<p>Finally, some <code>Log</code> implementations (such as the one for Log4J)
require an external configuration file for the entire logging environment.
This file should be prepared in a manner that is specific to the actual logging
technology being used.</p>
<h3>Using the Logging Package APIs</h3>
<p>Use of the Logging Package APIs, from the perspective of an application
component, consists of the following steps:</p>
<ol>
<li>Acquire a reference to an instance of
<a href="Log.html">org.apache.commons.logging.Log</a>, by calling the
factory method
<a href="LogFactory.html#getInstance(java.lang.String)">
LogFactory.getInstance(String name)</a>. Your application can contain
references to multiple loggers that are used for different
purposes. A typical scenario for a server application is to have each
major component of the server use its own Log instance.</li>
<li>Cause messages to be logged (if the corresponding detail level is enabled)
by calling appropriate methods (<code>trace()</code>, <code>debug()</code>,
<code>info()</code>, <code>warn()</code>, <code>error</code>, and
<code>fatal()</code>).</li>
</ol>
<p>For convenience, <code>LogFactory</code> also offers a static method
<code>getLog()</code> that combines the typical two-step pattern:</p>
<pre>
Log log = LogFactory.getFactory().getInstance(Foo.class);
</pre>
<p>into a single method call:</p>
<pre>
Log log = LogFactory.getLog(Foo.class);
</pre>
<p>For example, you might use the following technique to initialize and
use a <a href="Log.html">Log</a> instance in an application component:</p>
<pre>
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MyComponent {
protected static Log log =
LogFactory.getLog(MyComponent.class);
// Called once at startup time
public void start() {
...
log.info("MyComponent started");
...
}
// Called once at shutdown time
public void stop() {
...
log.info("MyComponent stopped");
...
}
// Called repeatedly to process a particular argument value
// which you want logged if debugging is enabled
public void process(String value) {
...
// Do the string concatenation only if logging is enabled
if (log.isDebugEnabled())
log.debug("MyComponent processing " + value);
...
}
}
</pre>
</body>

View File

@ -1,4 +0,0 @@
module org.apache.commons.logging {
requires org.slf4j;
exports org.apache.commons.logging;
}

View File

@ -0,0 +1,68 @@
<?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"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jul-to-slf4j-blackbox</artifactId>
<packaging>jar</packaging>
<name>jul-to-slf4j blackbox testing</name>
<description>jul-to-slf4j blackbox testing</description>
<url>http://www.slf4j.org</url>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,8 @@
module jul.to.slf4j.blackbox {
requires jul.to.slf4j;
requires ch.qos.reload4j;
requires junit;
requires java.logging;
requires org.slf4j;
}

View File

@ -22,7 +22,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.slf4j.bridge;
package org.slf4j.bridge.blackbox;
import java.util.ArrayList;
import java.util.List;

View File

@ -22,7 +22,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.slf4j.bridge;
package org.slf4j.bridge.blackbox;
import java.util.logging.Handler;
import java.util.logging.LogManager;
@ -31,8 +31,10 @@ import org.apache.log4j.FileAppender;
import org.apache.log4j.PatternLayout;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
public class SLF4JBridgeHandlerPerfTest {

View File

@ -22,7 +22,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.slf4j.bridge;
package org.slf4j.bridge.blackbox;
import static org.junit.Assert.assertEquals;
@ -35,6 +35,7 @@ import org.apache.log4j.spi.LoggingEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.bridge.SLF4JBridgeHandler;
public class SLF4JBridgeHandlerTest {

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@ -24,12 +24,7 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -1,3 +1,6 @@
/**
* Bridge/route all JUL log records to the SLF4J API.
*/
module jul.to.slf4j {
requires org.slf4j;

View File

@ -41,8 +41,8 @@ import org.slf4j.spi.LocationAwareLogger;
/**
* <p>Bridge/route all JUL log records to the SLF4J API.
* <p>Essentially, the idea is to install on the root logger an instance of
* <code>SLF4JBridgeHandler</code> as the sole JUL handler in the system. Subsequently, the
* SLF4JBridgeHandler instance will redirect all JUL log records are redirected
* {@link SLF4JBridgeHandler} as the sole JUL handler in the system. Subsequently, the
* <code>SLF4JBridgeHandler</code> instance will redirect all JUL log records are redirected
* to the SLF4J API based on the following mapping of levels:
*
* <pre>
@ -92,13 +92,10 @@ import org.slf4j.spi.LocationAwareLogger;
*
* <h2>As a Java 9/Jigsaw module</h2>
*
* <p>Given that <b>to</b> is a reserved keyword under Java 9 within module productions,
* the MANIFEST.MF file in <em>jul-to-slf4j.jar</em> declares <b>jul_to_slf4j</b> as
* its Automatic Module Name. Thus, if your application is Jigsaw modularized, the requires
* statement in your <em>module-info.java</em> needs to be <b>jul_to_slf4j</b>
* (note the two underscores).
* <p>As of SLF4J 2.0x, the module name for <em>jul-to-slf4j.jar</em> is
* <b>jul.to.slf4j</b>. In SLF4J 1.7.x it was declared via an Automatic-Module-Name statement
* as <b>jul_to_slf4j</b> (note the two underscores).
*
*
* @author Christian Stein
* @author Joern Huxhorn
* @author Ceki G&uuml;lc&uuml;

View File

@ -0,0 +1,4 @@
/**
* Bridge/route all JUL log records to the SLF4J API.
*/
package org.slf4j.bridge;

View File

@ -1,15 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title></title>
</head>
<body>
<p>Bridge/route all JUL log records to the SLF4J API.</p>
<hr>
</body>
</html>

View File

@ -0,0 +1,67 @@
<?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"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>log4j-over-slf4j-blackbox</artifactId>
<packaging>jar</packaging>
<name>log4j-over-slf4j blackbox testing</name>
<description>log4j-over-slf4j blackbox testing</description>
<url>http://www.slf4j.org</url>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,6 @@
module log4j.over.slf4j.blackbox {
requires log4j.over.slf4j;
requires java.logging;
requires junit;
}

View File

@ -22,7 +22,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.dummy;
package org.apache.log4j.blackbox;
import static org.junit.Assert.assertEquals;

View File

@ -22,7 +22,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.dummy;
package org.apache.log4j.blackbox;
import static org.junit.Assert.assertEquals;

View File

@ -22,7 +22,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.dummy;
package org.apache.log4j.blackbox;
import java.util.ArrayList;
import java.util.List;

View File

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

View File

@ -1,4 +1,4 @@
module log4j {
module log4j.over.slf4j {
requires org.slf4j;
requires java.xml;
exports org.apache.log4j;

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@ -53,11 +53,22 @@
<Bundle-SymbolicName>org.slf4j.osgi-over-slf4j</Bundle-SymbolicName>
<Bundle-Activator>org.slf4j.osgi.logservice.impl.Activator</Bundle-Activator>
<Bundle-Category>osgi</Bundle-Category>
<_exportcontents combine.self="override" />
<_exportcontents combine.self="override"/>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>org.slf4j.osgi.logservice</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-bom</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -18,7 +18,7 @@
<organization>
<name>QOS.ch</name>
<name>QOS.CH Sarl</name>
<url>http://www.qos.ch</url>
</organization>
<inceptionYear>2005</inceptionYear>
@ -26,29 +26,30 @@
<properties>
<!-- yyyy-MM-dd'T'HH:mm:ss'Z' -->
<project.build.outputTimestamp>2026-05-12T18:15:00Z</project.build.outputTimestamp>
<project.build.outputTimestamp>2026-08-07T12:57:07Z</project.build.outputTimestamp>
<latest.1.version>1.7.36</latest.1.version>
<!-- java.util.ServiceLoader requires Java 6 -->
<jdk.version>8</jdk.version>
<jdk.version>11</jdk.version>
<maven.compiler.source>${jdk.version}</maven.compiler.source>
<maven.compiler.target>${jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.resourceEncoding>UTF-8</project.build.resourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- used in integration testing -->
<cal10n.version>0.8.1</cal10n.version>
<reload4j.version>1.2.22</reload4j.version>
<reload4j.version>1.2.25</reload4j.version>
<logback.version>1.2.10</logback.version>
<jcl.version>1.2</jcl.version>
<junit.version>4.13.1</junit.version>
<maven-site-plugin.version>3.7.1</maven-site-plugin.version>
<maven-site-plugin.version>3.12.1</maven-site-plugin.version>
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version>
<maven-javadoc-plugin.version>3.6.3</maven-javadoc-plugin.version>
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<maven-deploy-plugin.version>3.0.0-M1</maven-deploy-plugin.version>
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
<maven-jxr-plugin.version>3.1.1</maven-jxr-plugin.version>
<maven-jxr-plugin.version>3.3.1</maven-jxr-plugin.version>
<maven-bundle-plugin.version>5.1.9</maven-bundle-plugin.version>
</properties>
@ -95,8 +96,10 @@
<filtering>true</filtering>
</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>
<directory>..</directory>
<directory>${project.basedir}</directory>
<targetPath>META-INF</targetPath>
<includes>
<include>LICENSE.txt</include>
@ -142,27 +145,9 @@
<goal>compile</goal>
</goals>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
<release>${jdk.version}</release>
</configuration>
</execution>
<execution>
<id>module-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>9</release>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/main/java9</compileSourceRoot>
</compileSourceRoots>
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
</executions>
</plugin>
@ -252,21 +237,44 @@
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>${maven-site-plugin.version}</version>
</plugin>
<!-- <plugin>-->
<!-- <groupId>org.apache.maven.plugins</groupId>-->
<!-- <artifactId>maven-javadoc-plugin</artifactId>-->
<!-- <version>3.6.3</version>-->
<!-- <executions>-->
<!-- <execution>-->
<!-- <id>default-cli</id>-->
<!-- <goals>-->
<!-- <goal>aggregate</goal>-->
<!-- </goals>-->
<!-- </execution>-->
<!-- </executions>-->
<!-- <configuration>-->
<!-- <verbose>true</verbose>-->
<!-- &lt;!&ndash; <sourceFileExcludes>&ndash;&gt;-->
<!-- &lt;!&ndash; <sourceFileExclude>**/xmodule-info.java</sourceFileExclude>&ndash;&gt;-->
<!-- &lt;!&ndash; </sourceFileExcludes>&ndash;&gt;-->
<!-- <skippedModules>-->
<!-- slf4j-testing,slf4j-ext,log4j-over-slf4j,log4j-over-slf4j-blackbox,jul-to-slf4j-blackbox,slf4j-migrator,osgi-over-slf4j-->
<!-- </skippedModules>-->
<!-- <detectLinks>true</detectLinks>-->
<!-- <doctitle>SLF4J project modules ${project.version}</doctitle>-->
<!-- <windowtitle>SLF4J javadoc</windowtitle>-->
<!-- <linksource>true</linksource>-->
<!-- <additionalOptions>-->
<!-- <additionalOption>-Xdoclint:none</additionalOption>-->
<!-- </additionalOptions>-->
<!-- </configuration>-->
<!-- </plugin>-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</build>
<reporting>
</reporting>
<profiles>
<profile>
<id>skipTests</id>
@ -303,6 +311,8 @@
</build>
</profile>
<profile>
<id>license</id>
<build>
@ -365,32 +375,6 @@
</build>
</profile>
<!--
<profile>
<id>travis</id>
<activation>
<property>
<name>env.TRAVIS</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-toolchains-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>toolchain</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
-->
</profiles>

65
pom.xml
View File

@ -6,11 +6,11 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-bom</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<packaging>pom</packaging>
<url>http://www.slf4j.org</url>
<name>SLF4J BOM</name>
<description>SLF4J project BOM</description>
@ -22,18 +22,18 @@
</license>
</licenses>
<scm>
<url>https://github.com/qos-ch/slf4j</url>
<connection>scm:git:https://github.com/qos-ch/slf4j.git</connection>
</scm>
</scm>
<!-- Inspired by Improving the Maven Bill of Materials (BOM) Pattern -->
<!-- https://www.garretwilson.com/blog/2023/06/14/improve-maven-bom-pattern -->
<modules>
<module>parent</module>
<module>slf4j-api</module>
<module>slf4j-testing</module>
<module>slf4j-simple</module>
<module>slf4j-nop</module>
<module>slf4j-jdk14</module>
@ -42,17 +42,16 @@
<module>slf4j-reload4j</module>
<module>slf4j-ext</module>
<module>jcl-over-slf4j</module>
<module>jcl-over-slf4j-blackbox</module>
<module>log4j-over-slf4j</module>
<module>log4j-over-slf4j-blackbox</module>
<module>jul-to-slf4j</module>
<module>jul-to-slf4j-blackbox</module>
<module>osgi-over-slf4j</module>
<module>integration</module>
<module>slf4j-migrator</module>
</modules>
<properties>
<central-publishing-maven-plugin.version>0.9.0</central-publishing-maven-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
@ -73,7 +72,7 @@
<artifactId>slf4j-nop</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
@ -86,49 +85,49 @@
<artifactId>slf4j-jdk-platform-logging</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-ext</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>osgi-over-slf4j</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -156,13 +155,21 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
<executions>
<execution>
<id>default-cli</id>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
<configuration>
<verbose>true</verbose>
<skippedModules>
slf4j-jdk-platform-logging,slf4j-migrator,osgi-over-slf4j
slf4j-testing,slf4j-jdk-platform-logging,jcl-over-slf4j-blackbox,log4j-over-slf4j-blackbox,jul-to-slf4j-blackbox,slf4j-migrator,osgi-over-slf4j
</skippedModules>
<detectLinks>true</detectLinks>
<doctitle>SLF4J project modules ${project.version}</doctitle>
<doctitle>SLF4J project modules 2.1.0-alpha1</doctitle>
<windowtitle>SLF4J javadoc</windowtitle>
<bottom><![CDATA[Copyright &copy; 2005-{currentYear} QOS.CH Sarl. All rights reserved]]></bottom>
<linksource>true</linksource>
@ -223,23 +230,12 @@
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>${central-publishing-maven-plugin.version}</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<excludeArtifacts>integration</excludeArtifacts>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>sign-artifacts</id>
<build>
@ -261,6 +257,7 @@
</plugins>
</build>
</profile>
</profiles>
</profiles>
</project>

View File

@ -4,11 +4,9 @@
#JDK8 - mvn site:site
#rscpSLF4J apidocs/
# JDK 11+
# adding the following
#mvn -Ddoclint=none -Dadditionalparam=-Xdoclint:none javadoc:aggregate
# mvn -Ddoclint=none -Dmaven.javadoc.skippedModules=slf4j-ext,log4j-over-slf4j,log4j-over-slf4j-blackbox,jul-to-slf4j-blackbox,slf4j-migrator,osgi-over-slf4j javadoc:aggregate
#mvn -Ddoclint=none -DXXadditionalparam=-Xdoclint:none -Dmaven.javadoc.skippedModules=osgi-over-slf4j,slf4j-ext,log4j-over-slf4j-blackbox,log4j-over-slf4j javadoc:aggregate
#mvn versions:set -DgenerateBackupPoms=false -DnewVersion=${VERSION_NUMBER}
MVN='/java/maven-3.5.2//bin/mvn'
@ -46,9 +44,8 @@ echoRunAndCheck "$MVN install"
if [ ! -z "$PASS" ]
then
# WARNING deploying without cleaning may leave stale MANIFEST files
export GPG_TTY=$(tty)
echoRunAndCheck "$MVN deploy -P javadocjar,sign-artifacts"
export GPG_TTY=$(tty)
echoRunAndCheck "$MVN deploy -P javadocjar,sign-artifacts"
fi

View File

@ -1,13 +1,13 @@
<?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"
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>
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@ -59,7 +59,8 @@
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Import-Package>org.slf4j.spi;version="${range;[===,+);${version_cleanup;${project.version}}}"</Import-Package>
<Import-Package>org.slf4j.spi;version="${range;[===,+);${version_cleanup;${project.version}}}"
</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 -->
<_exportcontents><![CDATA[
*,\
@ -75,7 +76,6 @@
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,20 @@
/**
* <p>This module defines the client-facing SLF4J API. </p>
*
* <p>More specifically, the {@link org.slf4j} package contains client-facing classes and interfaces.</p>
*
* <p>The {@link org.slf4j.spi} package contains classes which are intended for logging backends. In particular, </p>
* ogging back-ends must provide a {@link org.slf4j.spi.SLF4JServiceProvider} implementation in order to be picked
* up by SLF4J at initialization time.
* </p>
*
* @moduleGraph
*/
module org.slf4j {
exports org.slf4j;
exports org.slf4j.spi;
exports org.slf4j.event;
exports org.slf4j.helpers;
uses org.slf4j.spi.SLF4JServiceProvider;
requires java.base;
}

View File

@ -116,9 +116,9 @@ public interface Logger {
}
/**
* Make a new {@link LoggingEventBuilder} instance as appropriate for this logger and the
* <p>Make a new {@link LoggingEventBuilder} instance as appropriate for this logger and the
* desired {@link Level} passed as parameter. If this Logger is disabled for the given Level, then
* a {@link NOPLoggingEventBuilder} is returned.
* a {@link NOPLoggingEventBuilder} is returned. This is the main optimization in the fluent API.</p>
*
*
* @param level desired level for the event builder
@ -243,8 +243,11 @@ public interface Logger {
public boolean isTraceEnabled(Marker marker);
/**
* Entry point for fluent-logging for {@link org.slf4j.event.Level#TRACE} level.
*
* Entry point for fluent-logging for {@link org.slf4j.event.Level#TRACE} level.
*
* <p>If this logger is disabled for the TRACE level, then a {@link NOPLoggingEventBuilder} instance is returned.
* As the name indicates, this builder does not perform any operations. This is the main optimization in the fluent API.</p>
*
* @return LoggingEventBuilder instance as appropriate for level TRACE
* @since 2.0
*/
@ -441,7 +444,10 @@ public interface Logger {
/**
* Entry point for fluent-logging for {@link org.slf4j.event.Level#DEBUG} level.
*
*
* <p>If this logger is disabled for the DEBUG level, then a {@link NOPLoggingEventBuilder} instance is returned.
* As the name indicates, this builder does not perform any operations. This is the main optimization in the fluent API.</p>
*
* @return LoggingEventBuilder instance as appropriate for level DEBUG
* @since 2.0
*/
@ -582,7 +588,10 @@ public interface Logger {
/**
* Entry point for fluent-logging for {@link org.slf4j.event.Level#INFO} level.
*
*
* <p>If this logger is disabled for the INFO level, then a {@link NOPLoggingEventBuilder} instance is returned.
* As the name indicates, this builder does not perform any operations. This is the main optimization in the fluent API.</p>
* @return LoggingEventBuilder instance as appropriate for level INFO
* @since 2.0
*/
@ -723,7 +732,10 @@ public interface Logger {
/**
* Entry point for fluent-logging for {@link org.slf4j.event.Level#WARN} level.
*
*
* <p>If this logger is disabled for the WARN level, then a {@link NOPLoggingEventBuilder} instance is returned.
* As the name indicates, this builder does not perform any operations. This is the main optimization in the fluent API.</p>
*
* @return LoggingEventBuilder instance as appropriate for level WARN
* @since 2.0
*/
@ -865,7 +877,10 @@ public interface Logger {
/**
* Entry point for fluent-logging for {@link org.slf4j.event.Level#ERROR} level.
*
*
* <p>If this logger is disabled for the ERROR level, then a {@link NOPLoggingEventBuilder} instance is returned.
* As the name indicates, this builder does not perform any operations.</p>
*
* @return LoggingEventBuilder instance as appropriate for level ERROR
* @since 2.0
*/

View File

@ -0,0 +1,184 @@
/**
* Copyright (c) 2004-2023 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;
import org.slf4j.spi.MDCAdapter;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
/**
* <p>This class assists in the creation and removal (aka closing) of {@link org.slf4j.MDC MDC} entries.</p>
*
* <p>Typical Usage example:</p>
*
* <pre>
* MDCAmbit mdca = new MDCAmbit();
* try {
* mdca.put("k0", "v0");
* doSomething();
* } catch (RuntimeException e) {
* // here MDC.get("k0") would return "v0"
* } finally {
* // MDC remove "k0"
* mdca.clear();
* }
* </pre>
*
* <p>It is also possible to chain {@link #put}, {@link #addKeys(String...)} and {@link #addKey(String)}
* invocations.</p>
*
* <p>For example:</p>
* <pre>
* MDCAmbit mdca = new MDCAmbit();
* try {
* // assume "k0" was added to MDC at an earlier stage
* mdca.addKey("k0").put("k1", "v1").put("k2, "v2");
* doSomething();
* } finally {
* // MDC remove "k0", "k1", "k2", clear the set of tracked keys
* mdca.clear();
* }
* </pre>
*
* <p>The {@link #run(Runnable)} and {@link #call(Callable)} methods invoke the run/callable methods of
* objects passed as parameter in a <code>try/finally</code> block, and afterwards invoking {@link #clear()}
* method from within <code>finally</code>.
*
* </p>
*
* <pre>
* MDCAmbit mdca = new MDCAmbit();
* Runnable runnable = ...;
* mdca.put("k0", "v0").run(runnable);
* </pre>
*
* @since 2.1.0
*/
public class MDCAmbit {
/**
* Set of keys under management of this instance
*/
Set<String> keySet = new HashSet();
MDCAdapter mdcAdapter;
public MDCAmbit() {
mdcAdapter = MDC.getMDCAdapter();
}
MDCAmbit(MDCAdapter mdcAdapter) {
this.mdcAdapter = mdcAdapter;
}
/**
* Put the key/value couple in the MDC and keep track of the key for later
* removal by a call to {@link #clear()} }.
*
* @param key
* @param value
* @return this instance
*/
public MDCAmbit put(String key, String value) {
mdcAdapter.put(key, value);
keySet.add(key);
return this;
}
/**
* Keep track of a key for later removal by a call to {@link #clear()}.
* .
* @param key
* @return this instance
*/
public MDCAmbit addKey(String key) {
keySet.add(key);
return this;
}
/**
* Keep track of several keys for later removal by a call to {@link #clear()} .
* @param keys
* @return this instance
*/
public MDCAmbit addKeys(String... keys) {
if(keys == null)
return this;
for(String k: keys) {
keySet.add(k);
}
return this;
}
/**
* Run the runnable object passed as parameter within a try/finally block.
*
* <p>Afterwards, the {@link #clear()} method will be called within the `finally` block.
* </p>
* @param runnable
*/
public void run(Runnable runnable) {
try {
runnable.run();
} finally {
clear();
}
}
/**
* Invoke the {@link Callable#call()} method of the callable object passed as parameter within a try/finally block.
*
* <p>Afterwards, the {@link #clear()} method will be invoked within the `finally` block.
* </p>
* @param callable
*/
public <T> T call(Callable<? extends T> callable) throws Exception {
try {
return callable.call();
} finally {
clear();
}
}
/**
* Clear tracked keys by calling {@link MDC#remove} on each key.
*
* <p>In addition, the set of tracked keys is cleared.</p>
*
* <p>This method is usually called from within finally statement of a
* try/catch/finally block</p>
*
*/
public void clear() {
for(String key: keySet) {
mdcAdapter.remove(key);
}
keySet.clear();
}
}

View File

@ -2,6 +2,11 @@ package org.slf4j.event;
import org.slf4j.spi.LocationAwareLogger;
/**
* Various constants used by {@link Level} and {@link org.slf4j.Logger}.
*
*
*/
public class EventConstants {
public static final int ERROR_INT = LocationAwareLogger.ERROR_INT;
public static final int WARN_INT = LocationAwareLogger.WARN_INT;

View File

@ -2,6 +2,12 @@ package org.slf4j.event;
import java.util.Objects;
/**
* Instances of this class store the key value pair passed to a {@link org.slf4j.Logger logger} via
* the {@link org.slf4j.spi.LoggingEventBuilder#addKeyValue(String, Object)} method of the fluent API.
*
* @since 2.0.0
*/
public class KeyValuePair {
public final String key;

View File

@ -7,9 +7,8 @@ import static org.slf4j.event.EventConstants.TRACE_INT;
import static org.slf4j.event.EventConstants.WARN_INT;
/**
* SLF4J's internal representation of Level.
*
*
* SLF4J's internal representation of a level.
*
* @author Ceki G&uuml;lc&uuml;
* @since 1.7.15
*/

View File

@ -7,6 +7,13 @@ import java.util.List;
import org.slf4j.Marker;
import org.slf4j.helpers.SubstituteLogger;
/**
* An implementation of {@link LoggingEvent} used to store logging events generated during logging backend
* initialization.
*
* @author Ceki G&uuml;lc&uuml;
* @since 1.7.15
*/
public class SubstituteLoggingEvent implements LoggingEvent {
Level level;

View File

@ -0,0 +1,8 @@
/**
* SLF4J internal representation of a logging event.
*
* <p>>Most notably, the {@link org.slf4j.event.LoggingEvent} interface, a minimal interface sufficient for
* the restitution of data passed by the user to the SLF4J API.
* </p>
*/
package org.slf4j.event;

View File

@ -24,6 +24,9 @@
package org.slf4j.helpers;
import java.lang.module.ModuleDescriptor;
import java.util.Optional;
/**
* Various utility methods
*
@ -39,9 +42,9 @@ public class Slf4jEnvUtil {
* @since 2.0.14
*/
static public String slf4jVersion() {
// String moduleVersion = slf4jVersionByModule();
// if(moduleVersion != null)
// return moduleVersion;
String moduleVersion = slf4jVersionByModule();
if(moduleVersion != null)
return moduleVersion;
Package pkg = Slf4jEnvUtil.class.getPackage();
if(pkg == null) {
@ -58,16 +61,16 @@ public class Slf4jEnvUtil {
* @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);
// }
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

@ -0,0 +1,5 @@
/**
* Various SLF4J <b>internal</b> utility and helper classes.
*
*/
package org.slf4j.helpers;

View File

@ -1,16 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title></title>
</head>
<body>
<p>Helper classes.</p>
<hr/>
</body>
</html>

View File

@ -0,0 +1,6 @@
/**
* Core logging interfaces.
*
* This packages contains the "core", that is client facing, classes and interfaces of the SLF4J API.
*/
package org.slf4j;

View File

@ -1,16 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title></title>
</head>
<body>
<p>Core logging interfaces.</p>
<hr>
</body>
</html>

View File

@ -32,9 +32,14 @@ import org.slf4j.event.DefaultLoggingEvent;
import org.slf4j.event.KeyValuePair;
import org.slf4j.event.Level;
import org.slf4j.event.LoggingEvent;
import org.slf4j.helpers.Reporter;
/**
* Default implementation of {@link LoggingEventBuilder}
* Default implementation of {@link LoggingEventBuilder}.
*
* <p>It is assumed that when </p>
*
* @since 2.0.0
*/
public class DefaultLoggingEventBuilder implements LoggingEventBuilder, CallerBoundaryAware {
@ -76,6 +81,7 @@ public class DefaultLoggingEventBuilder implements LoggingEventBuilder, CallerBo
return this;
}
@Override
public LoggingEventBuilder addArgument(Supplier<?> objectSupplier) {
this.loggingEvent.addArgument(objectSupplier.get());
@ -254,12 +260,33 @@ public class DefaultLoggingEventBuilder implements LoggingEventBuilder, CallerBo
for(KeyValuePair kvp : keyValuePairList) {
sb.append(kvp.key);
sb.append('=');
sb.append(kvp.value);
// 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);

View File

@ -34,6 +34,18 @@ import org.slf4j.Marker;
* which need to provide hints so that the underlying logging system can extract
* the correct location information (method name, line number).
*
* <p></p>
*
* <p>In response to <a href="https://jira.qos.ch/browse/SLF4J-118">SLF4J-118</a>,
* the {@link #log(Marker, String, int, String, Object[], Throwable) log()} method was modified to accept
* an additional <code>Object[]</code> parameter.
* This Object[] represents arguments of the log request. Due to this modification, slf4j-api
* version 1.6.x no longer work with bindings shipping with SLF4J 1.5.x, instead
* bindings shipping with 1.6.x or later are required. See also
* <a href="https://github.com/qos-ch/slf4j/commit/6dd2bd58cff">commit 6dd2</a> dated
* April 9th, 2010.
* </p>
*
* @author Ceki G&uuml;lc&uuml;
* @since 1.3
*/

View File

@ -1,58 +0,0 @@
/**
* Copyright (c) 2004-2011 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.spi;
import org.slf4j.ILoggerFactory;
/**
* An internal interface which helps the static {@link org.slf4j.LoggerFactory}
* class bind with the appropriate {@link ILoggerFactory} instance.
*
* @author Ceki G&uuml;lc&uuml;
* @deprecated
*/
public interface LoggerFactoryBinder {
/**
* Return the instance of {@link ILoggerFactory} that
* {@link org.slf4j.LoggerFactory} class should bind to.
*
* @return the instance of {@link ILoggerFactory} that
* {@link org.slf4j.LoggerFactory} class should bind to.
*/
public ILoggerFactory getLoggerFactory();
/**
* The String form of the {@link ILoggerFactory} object that this
* <code>LoggerFactoryBinder</code> instance is <em>intended</em> to return.
*
* <p>This method allows the developer to interrogate this binder's intention
* which may be different from the {@link ILoggerFactory} instance it is able to
* yield in practice. The discrepancy should only occur in case of errors.
*
* @return the class name of the intended {@link ILoggerFactory} instance
*/
public String getLoggerFactoryClassStr();
}

View File

@ -31,9 +31,10 @@ import org.slf4j.Marker;
import org.slf4j.helpers.CheckReturnValue;
/**
* This is the main interface in slf4j's fluent API for creating
* This is the central interface in slf4j's fluent API for creating
* {@link org.slf4j.event.LoggingEvent logging events}.
*
*
*
* @author Ceki G&uuml;lc&uuml;
* @since 2.0.0
*/
@ -42,7 +43,7 @@ public interface LoggingEventBuilder {
/**
* Set the cause for the logging event being built.
* @param cause a throwable
* @return a LoggingEventBuilder, usually <b>this</b>.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*/
@CheckReturnValue
LoggingEventBuilder setCause(Throwable cause);
@ -51,54 +52,383 @@ public interface LoggingEventBuilder {
* A {@link Marker marker} to the event being built.
*
* @param marker a Marker instance to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*/
@CheckReturnValue
LoggingEventBuilder addMarker(Marker marker);
/**
* Add an argument to the event being built.
* Synonymous with {@link #arg(Object)} method.
*
* @param p an Object to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*/
@CheckReturnValue
LoggingEventBuilder addArgument(Object p);
/**
* Add an argument supplier to the event being built.
* Add an argument to the event being built.
* Synonymous with {@link #addArgument(Object)} method.
*
* @param p an Object to add.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.1.0
*/
@CheckReturnValue
default LoggingEventBuilder arg(Object p) {
return addArgument(p);
}
/**
* <p>Add an argument supplier to the event being built.
* Synonymous with {@link #arg(Supplier)} method.
* </p>
* @param objectSupplier an Object supplier to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*/
@CheckReturnValue
LoggingEventBuilder addArgument(Supplier<?> objectSupplier);
/**
* <p>Add an argument supplier to the event being built.
* Synonymous with {@link #addArgument(Supplier)} method.
* </p>
*
* @param objectSupplier an Object supplier to add.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.1.0
*/
@CheckReturnValue
default LoggingEventBuilder arg(Supplier<?> objectSupplier) {
return addArgument(objectSupplier);
}
/**
* Add a value of type <code>boolean</code> to the event being built.
*
* <p>The default implementation simply casts to <code>Boolean</code>. However, the NOP implementation, i.e.
* {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param b a value of type <code>boolean</code> value to add.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.1.0
*/
default public LoggingEventBuilder arg(boolean b) {
return addArgument((Boolean) b);
}
/**
* Add a value of type <code>char</code> to the event being built.
*
* <p>The default implementation simply casts to <code>Character</code>. However, the NOP implementation, i.e.
* {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param c a value of type <code>char</code> value to add.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.1.0
*/
default public LoggingEventBuilder arg(char c) {
return addArgument((Character) c);
}
/**
* Add a value of type <code>byte</code> to the event being built.
*
* <p>The default implementation simply casts to <code>Byte</code>. However, the NOP implementation, i.e.
* {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param b a value of type <code>byte</code> value to add.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.1.0
*/
default public LoggingEventBuilder arg(byte b) {
return addArgument((Byte) b);
}
/**
* Add a value of type <code>short</code> to the event being built.
*
* <p>The default implementation simply casts to <code>Short</code>. However, the NOP implementation, i.e.
* {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param s a value of type <code>short</code> value to add.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.1.0
*/
default public LoggingEventBuilder arg(short s) {
return addArgument((Short) s);
}
/**
* Add a value of type <code>int</code> to the event being built.
*
* <p>The default implementation simply casts to <code>Integer</code>. However, the NOP implementation, i.e.
* {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param i a value of type <code>int</code> value to add.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.1.0
*/
default public LoggingEventBuilder arg(int i) {
return addArgument((Integer) i);
}
/**
* Add a value of type <code>long</code> to the event being built.
*
* <p>The default implementation simply casts to <code>Long</code>. However, the NOP implementation, i.e.
* {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param l a value of type <code>long</code> value to add.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.1.0
*/
default public LoggingEventBuilder arg(long l) {
return addArgument((Long) l);
}
/**
* Add a value of type <code>float</code> to the event being built.
*
* <p>The default implementation simply casts to <code>Float</code>. However, the NOP implementation, i.e.
* {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param f a value of type <code>float</code> value to add.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.1.0
*/
default public LoggingEventBuilder arg(float f) {
return addArgument((Float) f);
}
/**
* Add a value of type <code>double</code> to the event being built.
*
* <p>The default implementation simply casts to <code>Double</code>. However, the NOP implementation skips the cast.</p>
*
* @param d a value of type <code>double</code> value to add.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.1.0
*/
default LoggingEventBuilder arg(double d) {
return arg((Double) d);
}
/**
* Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built.
*
* @param key the key of the key value pair.
* @param value the value of the key value pair.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*/
@CheckReturnValue
LoggingEventBuilder addKeyValue(String key, Object value);
/**
* Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built.
* Synonymous with {@link #addKeyValue(String, Object)} method.
*
* @param key the key of the key value pair.
* @param value the value of the key value pair.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*
* @since 2.1.0
*/
@CheckReturnValue
default LoggingEventBuilder kv(String key, Object value) {
return addKeyValue(key,value);
}
/**
* Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built.
*
* @param key the key of the key value pair.
* @param valueSupplier a supplier of a value for the key value pair.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*/
@CheckReturnValue
LoggingEventBuilder addKeyValue(String key, Supplier<Object> valueSupplier);
/**
* Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built.
* Synonymous with {@link #addKeyValue(String, Supplier)} method.
*
* @param key the key of the key value pair.
* @param valueSupplier a supplier of a value for the key value pair.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*
* @since 2.1.0
*/
@CheckReturnValue
default LoggingEventBuilder kv(String key, Supplier<Object> valueSupplier) {
return addKeyValue(key, valueSupplier);
}
/**
* <p>Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built, with the value part being
* of type <code>boolean</code>.
* </p>
* <p></p>
* <p>The default implementation simply casts to value part to <code>Boolean</code> before calling
* {@link #addKeyValue(String, Object)}. However, the
* NOP implementation, i.e {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param key the key of the key value pair.
* @param b the value of type <code>boolean</code> of the key value pair.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*
* @since 2.1.0
*/
default public LoggingEventBuilder kv(String key, boolean b) {
return addKeyValue(key, (Boolean) b);
}
/**
* <p>Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built, with the value part being
* of type <code>char</code>.
* </p>
* <p></p>
* <p>The default implementation simply casts to value part to <code>Character</code> before calling
* {@link #addKeyValue(String, Object)}. However, the
* NOP implementation, i.e {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param key the key of the key value pair.
* @param c the value of type <code>char</code> of the key value pair.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*
* @since 2.1.0
*/
default public LoggingEventBuilder kv(String key, char c) {
return addKeyValue(key, (Character) c);
}
/**
* <p>Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built, with the value part being
* of type <code>byte</code>.
* </p>
* <p></p>
* <p>The default implementation simply casts to value part to <code>Byte</code> before calling
* {@link #addKeyValue(String, Object)}. However, the
* NOP implementation, i.e {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param key the key of the key value pair.
* @param b the value of type <code>byte</code> of the key value pair.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*
* @since 2.1.0
*/
default public LoggingEventBuilder kv(String key, byte b) {
return addKeyValue(key, (Byte) b);
}
/**
* <p>Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built, with the value part being
* of type <code>short</code>.
* </p>
* <p></p>
* <p>The default implementation simply casts to value part to <code>Short</code> before calling
* {@link #addKeyValue(String, Object)}. However, the
* NOP implementation, i.e {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param key the key of the key value pair.
* @param s the value of type <code>short</code> of the key value pair.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*
* @since 2.1.0
*/
default public LoggingEventBuilder kv(String key, short s) {
return addKeyValue(key, (Short) s);
}
/**
* <p>Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built, with the value part being
* of type <code>int</code>.
* </p>
* <p></p>
* <p>The default implementation simply casts to value part to <code>Integer</code> before calling
* {@link #addKeyValue(String, Object)}. However, the
* NOP implementation, i.e {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param key the key of the key value pair.
* @param i the value of type <code>int</code> of the key value pair.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*
* @since 2.1.0
*/
default public LoggingEventBuilder kv(String key, int i) {
return addKeyValue(key, (Integer) i);
}
/**
* <p>Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built, with the value part being
* of type <code>long</code>.
* </p>
* <p></p>
* <p>The default implementation simply casts to value part to <code>Integer</code> before calling
* {@link #addKeyValue(String, Object)}. However, the
* NOP implementation, i.e {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param key the key of the key value pair.
* @param l the value of type <code>long</code> of the key value pair.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*
* @since 2.1.0
*/
default public LoggingEventBuilder kv(String key, long l) {
return addKeyValue(key, (Long) l);
}
/**
* <p>Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built, with the value part being
* of type <code>float</code>.
* </p>
* <p></p>
* <p>The default implementation simply casts to value part to <code>Float</code> before calling
* {@link #addKeyValue(String, Object)}. However, the
* NOP implementation, i.e {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param key the key of the key value pair.
* @param f the value of type <code>float</code> of the key value pair.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*
* @since 2.1.0
*/
default public LoggingEventBuilder kv(String key, float f) {
return addKeyValue(key, (Float) f);
}
/**
* <p>Add a {@link org.slf4j.event.KeyValuePair key value pair} to the event being built, with the value part being
* of type <code>double</code>.
* </p>
* <p></p>
* <p>The default implementation simply casts to value part to <code>Double</code> before calling
* {@link #addKeyValue(String, Object)}. However, the
* NOP implementation, i.e {@link NOPLoggingEventBuilder}, skips the cast.</p>
*
* @param key the key of the key value pair.
* @param f the value of type <code>double</code> of the key value pair.
* @return a LoggingEventBuilder instance, usually <b>this</b>.
*
* @since 2.1.0
*/
default public LoggingEventBuilder kv(String key, double f) {
return addKeyValue(key, (Double) f);
}
/**
* Sets the message of the logging event.
*
* @since 2.0.0-beta0
* @param message the message of the event
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.0.0
*/
@CheckReturnValue
LoggingEventBuilder setMessage(String message);
@ -107,6 +437,7 @@ public interface LoggingEventBuilder {
* Sets the message of the event via a message supplier.
*
* @param messageSupplier supplies a String to be used as the message for the event
* @return a LoggingEventBuilder instance, usually <b>this</b>.
* @since 2.0.0-beta0
*/
@CheckReturnValue

View File

@ -1,58 +0,0 @@
/**
* Copyright (c) 2004-2011 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.spi;
import org.slf4j.IMarkerFactory;
/**
* An internal interface which helps the static {@link org.slf4j.MarkerFactory}
* class bind with the appropriate {@link IMarkerFactory} instance.
*
* @author Ceki G&uuml;lc&uuml;
* @deprecated
*/
public interface MarkerFactoryBinder {
/**
* Return the instance of {@link IMarkerFactory} that
* {@link org.slf4j.MarkerFactory} class should bind to.
*
* @return the instance of {@link IMarkerFactory} that
* {@link org.slf4j.MarkerFactory} class should bind to.
*/
public IMarkerFactory getMarkerFactory();
/**
* The String form of the {@link IMarkerFactory} object that this
* <code>MarkerFactoryBinder</code> instance is <em>intended</em> to return.
*
* <p>This method allows the developer to interrogate this binder's intention
* which may be different from the {@link IMarkerFactory} instance it is able to
* return. Such a discrepancy should only occur in case of errors.
*
* @return the class name of the intended {@link IMarkerFactory} instance
*/
public String getMarkerFactoryClassStr();
}

View File

@ -2,15 +2,20 @@ package org.slf4j.spi;
import java.util.function.Supplier;
import org.slf4j.Logger;
import org.slf4j.Marker;
import org.slf4j.event.Level;
/**
* <p>A no-operation implementation of {@link LoggingEventBuilder}.</p>
*
* <p>As the name indicates, the method in this class do nothing, except when a return value is expected
* in which case a singleton, i.e. the unique instance of this class is returned.
* </p
* <p></p>
* <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.
* </p>
* <p></p>
* <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}
* when the relevant level is disabled for current logger. This is the core optimization in the SLF4J fluent API.</p>
*
* @author Ceki G&uuml;lc&uuml;
* @since 2.0.0
@ -33,68 +38,379 @@ public class NOPLoggingEventBuilder implements LoggingEventBuilder {
return SINGLETON;
}
/**
* <p>NOP implementation that does nothing.</p>
*
* @param marker a Marker instance to add.
* @return
*/
@Override
public LoggingEventBuilder addMarker(Marker marker) {
return singleton();
return this;
}
/**
* <p>NOP implementation that does nothing.</p>
*
* @param p
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
@Override
public LoggingEventBuilder addArgument(Object p) {
return singleton();
return this;
}
/**
* <p>NOP implementation that does nothing and thus skips calling get() call on the object supplier.</p>
*
* @param objectSupplier
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
@Override
public LoggingEventBuilder addArgument(Supplier<?> objectSupplier) {
return singleton();
return this;
}
/**
* <p>NOP implementation that does nothing and thus skips calling get() call on the object supplier.</p>
*
* @param objectSupplier
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
@Override
public LoggingEventBuilder arg(Supplier<?> objectSupplier) {
return this;
}
/**
* <p>NOP implementation that does nothing and thus skips the type cast.</p>
*
* @param b a value of type <code>boolean</code> value to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
public LoggingEventBuilder arg(boolean b) {
return this;
}
/**
* <p>NOP implementation that does nothing and thus skips the type cast.</p>
*
* @param c a value of type <code>char</code> value to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
@Override
public LoggingEventBuilder arg(char c) {
return this;
}
/**
* <p>NOP implementation that does nothing and thus skips the type cast.</p>
*
* @param b a value of type <code>byte</code> value to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
@Override
public LoggingEventBuilder arg(byte b) {
return this;
}
/**
* <p>NOP implementation that does nothing and thus skips the type cast.</p>
*
* @param s a value of type <code>short</code> value to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
public LoggingEventBuilder arg(short s) {
return this;
}
/**
* <p>NOP implementation that does nothing and thus skips the type cast.</p>
*
* @param i a value of type <code>int</code> value to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
@Override
public LoggingEventBuilder arg(int i) {
return this;
}
/**
* <p>NOP implementation that does nothing and thus skips the type cast.</p>
*
* @param l a value of type <code>long</code> value to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
@Override
public LoggingEventBuilder arg(long l) {
return this;
}
/**
* <p>NOP implementation that does nothing and thus skips the type cast.</p>
*
* @param f a value of type <code>float</code> value to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
@Override
public LoggingEventBuilder arg(float f) {
return this;
}
/**
* <p>NOP implementation that does nothing and thus skips the type cast.</p>
*
* @param d a value of type <code>float</code> value to add.
* @return a LoggingEventBuilder, usually <b>this</b>.
* @since 2.1.0
*/
@Override
public LoggingEventBuilder arg(double d) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param key the key of the key value pair.
* @param value the value of the key value pair.
* @return a LoggingEventBuilder, usually <b>this</b>.
*/
@Override
public LoggingEventBuilder addKeyValue(String key, Object value) {
return singleton();
return this;
}
/**
* NOP implementation that doesnothing.
*
* @param key the key of the key value pair.
* @param value the value of the key value pair.
* @return a LoggingEventBuilder, usually <b>this</b>.
*/
@Override
public LoggingEventBuilder kv(String key, Object value) {
return this;
}
/**
* NOP implementation that doesnothing.
*
* @param key the key of the key value pair.
* @param value a supplier of a value for the key value pair.
* @return a LoggingEventBuilder, usually <b>this</b>.
*/
@Override
public LoggingEventBuilder addKeyValue(String key, Supplier<Object> value) {
return singleton();
return this;
}
/**
* NOP implementation that doesnothing.
*
* @param key the key of the key value pair.
* @param value a supplier of a value for the key value pair.
* @return a LoggingEventBuilder, usually <b>this</b>.
*/
@Override
public LoggingEventBuilder kv(String key, Supplier<Object> value) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param key the key of the key value pair.
* @param b the value of type <code>boolean</code> of the key value pair.
* @return a LoggingEventBuilder, usually <b>this</b>.
*/
@Override
public LoggingEventBuilder kv(String key, boolean b) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param key the key of the key value pair.
* @param c the value of type <code>char</code> of the key value pair.
* @return
*/
@Override
public LoggingEventBuilder kv(String key, char c) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param key the key of the key value pair.
* @param b the value of type <code>byte</code> of the key value pair.
* @return
*/
@Override
public LoggingEventBuilder kv(String key, byte b) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param key the key of the key value pair.
* @param s the value of type <code>short</code> of the key value pair.
* @return
*/
@Override
public LoggingEventBuilder kv(String key, short s) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param key the key of the key value pair.
* @param i the value of type <code>int</code> of the key value pair.
* @return
*/
@Override
public LoggingEventBuilder kv(String key, int i) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param key the key of the key value pair.
* @param l the value of type <code>long</code> of the key value pair.
* @return
*/
@Override
public LoggingEventBuilder kv(String key, long l) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param key the key of the key value pair.
* @param f the value of type <code>float</code> of the key value pair.
* @return
*/
@Override
public LoggingEventBuilder kv(String key, float f) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param key the key of the key value pair.
* @param d the value of type <code>double</code> of the key value pair.
* @return
*/
@Override
public LoggingEventBuilder kv(String key, double d) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param cause a throwable
* @return
*/
@Override
public LoggingEventBuilder setCause(Throwable cause) {
return singleton();
return this;
}
/**
*
*/
@Override
public void log() {
}
/**
* NOP implementation that does nothing.
*
* @param message the message of the event
* @return
*/
@Override
public LoggingEventBuilder setMessage(String message) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param messageSupplier supplies a String to be used as the message for the event
* @return
*/
@Override
public LoggingEventBuilder setMessage(Supplier<String> messageSupplier) {
return this;
}
/**
* NOP implementation that does nothing.
*
* @param message the message to log
*/
@Override
public void log(String message) {
}
/**
* NOP implementation that does nothing.
*
* @param messageSupplier a Supplier returning a message of type String
*/
@Override
public void log(Supplier<String> messageSupplier) {
}
/**
* NOP implementation that does nothing.
*
* @param message the message to log
* @param arg an argument to be used with the message to log
*/
@Override
public void log(String message, Object arg) {
}
/**
* NOP implementation that does nothing.
*
* @param message the message to log
* @param arg0 first argument to be used with the message to log
* @param arg1 second argument to be used with the message to log
*/
@Override
public void log(String message, Object arg0, Object arg1) {
}
/**
* NOP implementation that does nothing.
*
* @param message the message to log
* @param args a list (actually an array) of arguments to be used with the message to log
*/
@Override
public void log(String message, Object... args) {
}
}

View File

@ -0,0 +1,10 @@
/**
* Contains classes and interfaces which are intended for logging backends.
*
* <p>
* Logging back-ends wishing to interact with SLF4J must provide a {@link org.slf4j.spi.SLF4JServiceProvider}
* implementation in order to be picked up by SLF4J at initialization time.
* </p>
*
*/
package org.slf4j.spi;

View File

@ -1,8 +0,0 @@
<body>
Classes and interfaces which are internal to SLF4J. Under most
circumstances SLF4J users should be oblivious even to the existence of
this package.
</body>

View File

@ -1,8 +0,0 @@
module org.slf4j {
exports org.slf4j;
exports org.slf4j.spi;
exports org.slf4j.event;
exports org.slf4j.helpers;
uses org.slf4j.spi.SLF4JServiceProvider;
requires java.base;
}

View File

@ -0,0 +1,115 @@
/**
* Copyright (c) 2004-2023 QOS.ch
* All rights reserved.
* <p>
* 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:
* <p>
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* <p>
* 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;
import org.junit.Test;
import org.slf4j.helpers.BasicMDCAdapter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class MDCAmbitTest {
BasicMDCAdapter mdcAdapter = new BasicMDCAdapter();
MDCAmbit mdca = new MDCAmbit(mdcAdapter);
String k0 = "k0";
String v0 = "v0";
String k1 = "k1";
String v1 = "v0";
String k2 = "k2";
String v2 = "v2";
String kUnused = "kUnused";
void throwRuntimeException() {
throw new RuntimeException();
}
@Test
public void smoke() {
try {
mdca.put(k0, v0);
assertEquals(v0, mdcAdapter.get(k0));
assertNull(mdcAdapter.get(kUnused));
throwRuntimeException();
} catch (RuntimeException e) {
assertEquals(v0, mdcAdapter.get(k0));
} finally {
mdca.clear();
}
assertNull(mdcAdapter.get(k0));
}
@Test
public void empty() {
try {
assertNull(mdcAdapter.get(kUnused));
} finally {
mdca.clear();
}
assertNull(mdcAdapter.get(k0));
}
@Test
public void addKeyTest() {
mdcAdapter.put(k0, v0);
try {
mdca.addKey(k0);
assertEquals(v0, mdcAdapter.get(k0));
assertNull(mdcAdapter.get(kUnused));
throwRuntimeException();
} catch (RuntimeException e) {
assertEquals(v0, mdcAdapter.get(k0));
} finally {
mdca.clear();
}
assertNull(mdcAdapter.get(k0));
}
@Test
public void combinedPut_addKeyTest() {
mdcAdapter.put(k0, v0);
try {
mdca.addKey(k0).put(k1, v1).put(k2, v2);
assertEquals(v0, mdcAdapter.get(k0));
assertEquals(v1, mdcAdapter.get(k1));
assertEquals(v2, mdcAdapter.get(k2));
assertNull(mdcAdapter.get(kUnused));
throwRuntimeException();
} catch (RuntimeException e) {
assertEquals(v0, mdcAdapter.get(k0));
assertEquals(v1, mdcAdapter.get(k1));
assertEquals(v2, mdcAdapter.get(k2));
} finally {
mdca.clear();
}
assertNull(mdcAdapter.get(k0));
assertNull(mdcAdapter.get(k1));
assertNull(mdcAdapter.get(k2));
}
}

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@ -67,6 +67,7 @@
<configuration>
<archive>
<manifestEntries>
<!-- <Automatic-Module-Name>org.slf4j.ext</Automatic-Module-Name>-->
<Premain-Class>org.slf4j.agent.AgentPremain</Premain-Class>
<!-- 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>

View File

@ -8,7 +8,7 @@
<parent>
<artifactId>slf4j-parent</artifactId>
<groupId>org.slf4j</groupId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@ -19,6 +19,9 @@
<url>https://www.slf4j.org</url>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
@ -35,37 +38,6 @@
<build>
<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>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>

View File

@ -22,7 +22,13 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
/**
* Implementation of {@link System.Logger} interface relaying events to SLF4J.
*
* @since 2.0.0
*/
module org.slf4j.jdk.platform.logging {
requires org.slf4j;
exports org.slf4j.jdk.platform.logging;
provides java.lang.System.LoggerFinder with org.slf4j.jdk.platform.logging.SLF4JSystemLoggerFinder;
}
}

View File

@ -1,7 +1,7 @@
/**
* Copyright (c) 2004-2021 QOS.ch
* All rights reserved.
*
* <p>
* 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
@ -9,10 +9,10 @@
* 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:
*
* <p>
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* <p>
* 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
@ -36,13 +36,14 @@ import org.slf4j.spi.CallerBoundaryAware;
import org.slf4j.spi.LoggingEventBuilder;
/**
* Adapts {@link Logger} to {@link System.Logger}.
* Implements {@link System.Logger} by forwarding logging events to the appropriate {@link org.slf4j.Logger} instance.
*
* @since 2.0.0
*/
class SLF4JPlatformLogger implements System.Logger {
static private final String PRESUMED_CALLER_BOUNDARY = System.Logger.class.getName();
private final Logger slf4jLogger;
public SLF4JPlatformLogger(Logger logger) {
@ -59,12 +60,12 @@ class SLF4JPlatformLogger implements System.Logger {
@Override
public boolean isLoggable(Level jplLevel) {
if (jplLevel == Level.ALL)
return true;
if (jplLevel == Level.OFF)
return true;
// If called via log method, fixExtremeLevels has been called. System.Logger.Level.ALL and Level.OFF have
// been respectively mapped to Level.TRACE and Level.ERROR.
// However, if isLoggable is called directly, we must fix the extreme levels here as well.
final Level jplLevelReduced = fixExtremeLevels(jplLevel);
org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevel);
org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevelReduced);
return slf4jLogger.isEnabledForLevel(slf4jLevel);
}
@ -72,27 +73,27 @@ class SLF4JPlatformLogger implements System.Logger {
/**
* Transform a {@link Level} to {@link org.slf4j.event.Level}.
*
*
* This method assumes that Level.ALL or Level.OFF never reach this method.
*
*
* @param jplLevel
* @return
*/
private org.slf4j.event.Level jplLevelToSLF4JLevel(Level jplLevel) {
switch (jplLevel) {
case TRACE:
return org.slf4j.event.Level.TRACE;
case DEBUG:
return org.slf4j.event.Level.DEBUG;
case INFO:
return org.slf4j.event.Level.INFO;
case WARNING:
return org.slf4j.event.Level.WARN;
case ERROR:
return org.slf4j.event.Level.ERROR;
default:
reportUnknownLevel(jplLevel);
return null;
switch(jplLevel) {
case TRACE:
return org.slf4j.event.Level.TRACE;
case DEBUG:
return org.slf4j.event.Level.DEBUG;
case INFO:
return org.slf4j.event.Level.INFO;
case WARNING:
return org.slf4j.event.Level.WARN;
case ERROR:
return org.slf4j.event.Level.ERROR;
default:
reportUnknownLevel(jplLevel);
return null;
}
}
@ -108,8 +109,8 @@ class SLF4JPlatformLogger implements System.Logger {
/**
* Single point of processing taking all possible parameters.
*
* @param jplLevel
*
* @param jplLevel
* @param bundle
* @param msg
* @param thrown
@ -122,7 +123,7 @@ class SLF4JPlatformLogger implements System.Logger {
org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevelReduced);
boolean isEnabled = slf4jLogger.isEnabledForLevel(slf4jLevel);
if (isEnabled) {
if(isEnabled) {
performLog(slf4jLevel, bundle, msg, thrown, params);
}
}
@ -139,10 +140,10 @@ class SLF4JPlatformLogger implements System.Logger {
* @return
*/
private Level fixExtremeLevels(Level jplLevel) {
if (jplLevel == Level.OFF)
return Level.ERROR;
if(jplLevel == Level.OFF)
return Level.ERROR;
if (jplLevel == Level.ALL)
if(jplLevel == Level.ALL)
return Level.TRACE;
return jplLevel;
@ -151,18 +152,18 @@ class SLF4JPlatformLogger implements System.Logger {
private void performLog(org.slf4j.event.Level slf4jLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params) {
String message = getResourceStringOrMessage(bundle, msg);
LoggingEventBuilder leb = slf4jLogger.makeLoggingEventBuilder(slf4jLevel);
if (thrown != null) {
if(thrown != null) {
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
for (Object p : params) {
for(Object p : params) {
leb = leb.addArgument(p);
}
// The JDK uses a different formatting convention. We must invoke it now.
message = MessageFormat.format(message, params);
}
if (leb instanceof CallerBoundaryAware) {
if(leb instanceof CallerBoundaryAware) {
CallerBoundaryAware cba = (CallerBoundaryAware) leb;
cba.setCallerBoundary(PRESUMED_CALLER_BOUNDARY);
}
@ -176,7 +177,7 @@ class SLF4JPlatformLogger implements System.Logger {
}
private static String getResourceStringOrMessage(ResourceBundle bundle, String msg) {
if (bundle == null || msg == null)
if(bundle == null || msg == null)
return msg;
// ResourceBundle::getString throws:
//

View File

@ -0,0 +1,5 @@
/**
* JDK platform logging
*
*/
package org.slf4j.jdk.platform.logging;

View File

@ -24,9 +24,6 @@
*/
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.PrintStream;
import java.lang.System.Logger;
@ -41,6 +38,8 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.LoggerFactory;
import static org.junit.Assert.*;
/**
* The present test is fragile in the sense that it sets up SimpleLogger
* with a StringPrintStream and reverts to the old stream when done.
@ -106,8 +105,9 @@ public class SLF4JPlatformLoggingTest {
systemLogger.log(Level.INFO, "we have a problem", new Exception());
List<String> results = SPS.stringList;
//INFO throwTest - a problem
//java.lang.Exception
// SLF4J(I): Actual provider is of type [org.slf4j.simple.SimpleServiceProvider@67c27493]
// INFO throwTest - a problem
// java.lang.Exception
// at org.slf4j.jdk.platform.logging/org.slf4j.jdk.platform.logging.SLF4JPlatformLoggingTest.throwTest(SLF4JPlatformLoggingTest.java:92)
int line = 0;
@ -129,7 +129,19 @@ public class SLF4JPlatformLoggingTest {
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>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@ -31,11 +31,16 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<type>test-jar</type>
<artifactId>slf4j-testing</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
</plugins>
</build>
</project>

View File

@ -1,9 +1,13 @@
module org.slf4j.jul {
/**
* This module implements an SLF4J adapter for the java.logging package.
*/
module org.slf4j.jul {
requires org.slf4j;
requires java.logging;
provides org.slf4j.spi.SLF4JServiceProvider with org.slf4j.jul.JULServiceProvider;
exports org.slf4j.jul;
opens org.slf4j.jul to org.slf4j;
}

View File

@ -18,6 +18,7 @@ import org.slf4j.event.EventConstants;
import org.slf4j.event.SubstituteLoggingEvent;
import org.slf4j.helpers.SubstituteLogger;
import org.slf4j.helpers.SubstituteServiceProvider;
import org.slf4j.jul.JDK14LoggerAdapter;
import org.slf4j.jul.ListHandler;
import org.slf4j.spi.CallerBoundaryAware;
import org.slf4j.spi.LoggingEventBuilder;
@ -121,6 +122,7 @@ public class CallerInfoTest {
substituteLogger.debug("jello");
Logger logger = LoggerFactory.getLogger(loggerName);
assertTrue(logger instanceof JDK14LoggerAdapter);
substituteLogger.setDelegate(logger);
final LinkedBlockingQueue<SubstituteLoggingEvent> queue = substituteServiceProvider.getSubstituteLoggerFactory().getEventQueue();

View File

@ -130,6 +130,35 @@ 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) {
LogRecord logRecord = listHandler.recordList.get(index);
Assert.assertNotNull(logRecord);

View File

@ -30,7 +30,7 @@ import java.util.logging.Handler;
import org.junit.After;
import org.junit.Before;
import org.slf4j.testHarness.MultithreadedInitializationTest;
import org.slf4j.testing.MultithreadedInitializationTest;
public class JDK14MultithreadedInitializationTest extends MultithreadedInitializationTest {

View File

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

View File

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

View File

@ -0,0 +1,3 @@
module slf4j.migrator {
requires java.desktop;
}

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@ -32,11 +32,14 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<type>test-jar</type>
<artifactId>slf4j-testing</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
</plugins>
</build>
</project>

View File

@ -1,7 +1,9 @@
module org.slf4j.nop {
/**
* A no-operation logging provider, aka back-end, that drops all events.
*/
module org.slf4j.nop {
requires org.slf4j;
provides org.slf4j.spi.SLF4JServiceProvider with org.slf4j.nop.NOPServiceProvider;
exports org.slf4j.nop;
opens org.slf4j.nop to org.slf4j;
provides org.slf4j.spi.SLF4JServiceProvider with org.slf4j.nop.NOPServiceProvider;
}

View File

@ -8,6 +8,11 @@ import org.slf4j.helpers.NOPMDCAdapter;
import org.slf4j.spi.MDCAdapter;
import org.slf4j.spi.SLF4JServiceProvider;
/**
* As the name indicates, this {#link SLF4JServiceProvider} implementation git sdiscards all events.
*
* @author Ceki G&uuml;lc&uuml;
*/
public class NOPServiceProvider implements SLF4JServiceProvider {
/**

View File

@ -0,0 +1,4 @@
/**
* NOP implementation
*/
package org.slf4j.nop;

View File

@ -29,9 +29,10 @@ import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.LoggerFactoryFriend;
import org.slf4j.helpers.StringPrintStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
@ -42,7 +43,6 @@ import static org.slf4j.helpers.Reporter.SLF4J_INTERNAL_VERBOSITY_KEY;
public class MultithreadedInitializationTest {
static int NUM_LINES_IN_SLF4J_CONNECTED_WITH_PROVIDER_INFO = 1;
final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2;
private static final AtomicLong EVENT_COUNT = new AtomicLong(0);
@ -52,7 +52,7 @@ public class MultithreadedInitializationTest {
int diff = new Random().nextInt(10000);
String loggerName = "org.slf4j.impl.MultithreadedInitializationTest";
private final PrintStream oldErr = System.err;
StringPrintStream sps = new StringPrintStream(oldErr, false);
StringPrintStream sps = new StringPrintStream(oldErr);
@Before
public void setup() {
@ -82,7 +82,8 @@ public class MultithreadedInitializationTest {
logger.info("hello");
EVENT_COUNT.getAndIncrement();
assertEquals(NUM_LINES_IN_SLF4J_CONNECTED_WITH_PROVIDER_INFO, sps.stringList.size());
// SLF4J(I): Actual provider is of type [org.slf4j.nop.NOPServiceProvider@21b3698b]
assertEquals(1, sps.stringList.size());
}
private static LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException {
@ -124,31 +125,31 @@ public class MultithreadedInitializationTest {
;
// public static class StringPrintStream extends PrintStream {
//
// public static final String LINE_SEP = System.getProperty("line.separator");
// PrintStream other;
// List<String> stringList = new ArrayList<>();
//
// public StringPrintStream(PrintStream ps) {
// super(ps);
// other = ps;
// }
//
// public void print(String s) {
// other.print(s);
// stringList.add(s);
// }
//
// public void println(String s) {
// other.println(s);
// stringList.add(s);
// }
//
// public void println(Object o) {
// other.println(o);
// stringList.add(o.toString());
// }
// };
public static class StringPrintStream extends PrintStream {
public static final String LINE_SEP = System.getProperty("line.separator");
PrintStream other;
List<String> stringList = new ArrayList<>();
public StringPrintStream(PrintStream ps) {
super(ps);
other = ps;
}
public void print(String s) {
other.print(s);
stringList.add(s);
}
public void println(String s) {
other.println(s);
stringList.add(s);
}
public void println(Object o) {
other.println(o);
stringList.add(o.toString());
}
};
}

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@ -37,11 +37,11 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<type>test-jar</type>
<artifactId>slf4j-testing</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
@ -52,18 +52,53 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<reportFormat>plain</reportFormat>
<trimStackTrace>false</trimStackTrace>
<excludes>
<exclude>**/AllTest.java</exclude>
<exclude>**/PackageTest.java</exclude>
</excludes>
<!--<argLine>-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8001</argLine> -->
<!--<argLine>XXadd-opens log4j/org.apache.log4j=org.slf4j.log4j12</argLine>-->
<!--
java.lang.IllegalAccessException: class org.apache.log4j.helpers.OptionConverter
(in module ch.qos.reload4j) cannot access class org.slf4j.reload4j.testHarness.RecursiveAppender
(in module org.slf4j.reload4j) because module org.slf4j.reload4j does not export org.slf4j.reload4j.testHarness
to module ch.qos.reload4j
-->
<argLine>
--add-opens org.slf4j.reload4j/org.slf4j.reload4j.testHarness=ch.qos.reload4j
</argLine>
</configuration>
</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>
</build>

View File

@ -0,0 +1,11 @@
/**
* slf4j reload4j module
*
*
*/
module org.slf4j.reload4j {
requires org.slf4j;
requires ch.qos.reload4j;
exports org.slf4j.reload4j;
provides org.slf4j.spi.SLF4JServiceProvider with org.slf4j.reload4j.Reload4jServiceProvider;
}

View File

@ -0,0 +1,5 @@
/**
* slf4j reload4j
*
*/
package org.slf4j.reload4j;

View File

@ -1,7 +1,7 @@
package org.slf4j.reload4j;
import org.junit.Test;
import org.slf4j.helpers.MDCAdapterTestBase;
import org.slf4j.testing.MDCAdapterTestBase;
import org.slf4j.spi.MDCAdapter;
import java.util.HashMap;

View File

@ -34,7 +34,7 @@ import org.junit.After;
import org.junit.Before;
import org.slf4j.reload4j.testHarness.RecursiveAppender;
public class Reload4jMultithreadedInitializationTest extends org.slf4j.testHarness.MultithreadedInitializationTest {
public class Reload4jMultithreadedInitializationTest extends org.slf4j.testing.MultithreadedInitializationTest {
static int NUM_LINES_BY_RECURSIVE_APPENDER = 3;
// value of LogManager.DEFAULT_CONFIGURATION_KEY;

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>2.0.18</version>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@ -19,6 +19,7 @@
<properties>
<module-name>org.slf4j.simple</module-name>
<slf4j.provider.implementation>org.slf4j.simple.SimpleServiceProvider</slf4j.provider.implementation>
<slf4j.provider.type>simple</slf4j.provider.type>
</properties>
@ -31,11 +32,17 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<type>test-jar</type>
<artifactId>slf4j-testing</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
</plugins>
</build>
</project>

View File

@ -1,6 +1,12 @@
/**
* The simple logger, a bare-bones implementation of logging backend.
*
*
*/
module org.slf4j.simple {
requires org.slf4j;
provides org.slf4j.spi.SLF4JServiceProvider with org.slf4j.simple.SimpleServiceProvider;
// exporting ?
exports org.slf4j.simple;
provides org.slf4j.spi.SLF4JServiceProvider with org.slf4j.simple.SimpleServiceProvider;
opens org.slf4j.simple to org.slf4j;
}

View File

@ -65,9 +65,9 @@ public class SimpleLoggerFactory implements ILoggerFactory {
/**
* Clear the internal logger cache.
*
* This method is intended to be called by classes (in the same package or
* subclasses) for testing purposes. This method is internal. It can be
* modified, renamed or removed at any time without notice.
* This method is intended to be called by classes (in the same package) for
* testing purposes. This method is internal. It can be modified, renamed or
* removed at any time without notice.
*
* You are strongly discouraged from calling this method in production code.
*/

View File

@ -0,0 +1,6 @@
/**
* Contains slf4j simple package.
*
*
*/
package org.slf4j.simple;

View File

@ -1,50 +0,0 @@
package org.slf4j.simple;
import org.junit.Ignore;
import org.slf4j.Logger;
import org.slf4j.event.Level;
import java.io.PrintStream;
@Ignore
public class AcceptanceTest extends LoggerTestSuite {
@Override
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;
}
@Override
public String extractMessage(String message) {
return message
.split("\n")[0]
.split("- ")[1];
}
@Override
public String extractExceptionMessage(String message) {
String[] logLines = message.split("\n");
if (logLines.length < 2) {
return null;
}
String exceptionLine = logLines[1];
return exceptionLine.split(": ")[1];
}
@Override
public String extractExceptionType(String message) {
String[] logLines = message.split("\n");
if (logLines.length < 2) {
return null;
}
String exceptionLine = logLines[1];
return exceptionLine.split(": ")[0];
}
}

View File

@ -5,19 +5,124 @@ 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;
public abstract class LoggerTestSuite {
/**
* 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<>();
@ -168,9 +273,38 @@ public abstract class LoggerTestSuite {
}
@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
*/
@ -181,6 +315,7 @@ public abstract class LoggerTestSuite {
/**
* 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
*/
@ -191,6 +326,7 @@ public abstract class LoggerTestSuite {
/**
* 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
*/
@ -201,6 +337,7 @@ public abstract class LoggerTestSuite {
/**
* 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
*/
@ -211,6 +348,7 @@ public abstract class LoggerTestSuite {
/**
* 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
*/
@ -218,33 +356,4 @@ public abstract class LoggerTestSuite {
return message.toLowerCase().contains("error");
}
/**
* 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 abstract String extractMessage(String message);
/**
* 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 abstract String extractExceptionMessage(String message);
/**
* 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 abstract String extractExceptionType(String message);
/**
* 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 abstract Logger createLogger(ListAppendingOutputStream outputStream, Level level);
}
}

View File

@ -29,8 +29,7 @@ import java.io.PrintStream;
import org.junit.After;
import org.junit.Before;
import org.slf4j.LoggerFactoryFriend;
import org.slf4j.helpers.StringPrintStream;
import org.slf4j.testHarness.MultithreadedInitializationTest;
import org.slf4j.testing.MultithreadedInitializationTest;
public class SimpleLoggerMultithreadedInitializationTest extends MultithreadedInitializationTest {
// final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2;
@ -41,8 +40,6 @@ public class SimpleLoggerMultithreadedInitializationTest extends MultithreadedIn
//
// final int diff = new Random().nextInt(10000);
static int NUM_LINES_IN_SLF4J_REPLAY_WARNING = 3;
static int NUM_LINES_IN_SLF4J_CONNECTED_WITH_PROVIDER_INFO = 1;
private final PrintStream oldErr = System.err;
final String loggerName = this.getClass().getName();
StringPrintStream sps = new StringPrintStream(oldErr, false);
@ -69,7 +66,7 @@ public class SimpleLoggerMultithreadedInitializationTest extends MultithreadedIn
@Override
protected int extraLogEvents() {
return NUM_LINES_IN_SLF4J_REPLAY_WARNING + NUM_LINES_IN_SLF4J_CONNECTED_WITH_PROVIDER_INFO;
return NUM_LINES_IN_SLF4J_REPLAY_WARNING;
}
}

View File

@ -14,7 +14,7 @@ public class Slf4jVersionTest {
String version = Slf4jEnvUtil.slf4jVersion();
assertNotNull(version);
assertTrue(version.startsWith("2"));
assertTrue(version.startsWith("3"));
}

View File

@ -22,7 +22,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.slf4j.helpers;
package org.slf4j.simple;
import java.io.PrintStream;
import java.util.ArrayList;

View File

@ -30,7 +30,8 @@ import java.util.regex.Pattern;
public class StateCheckingPrintStream extends PrintStream {
static String PACKAGE_NAME = "org.slf4j.simple.multiThreadedExecution";
static String MODULE_NAME = "org.slf4j.simple";
enum State {
INITIAL, UNKNOWN, HELLO, THROWABLE, AT1, AT2, OTHER;
@ -48,7 +49,7 @@ public class StateCheckingPrintStream extends PrintStream {
}
public void println(String s) {
//System.out.println(s);
State next = computeState(s);
//System.out.println(next + " " + s);
switch (currentState) {
@ -108,7 +109,7 @@ public class StateCheckingPrintStream extends PrintStream {
String OTHER_PATTERN_STR = ".*Other \\d{1,5}";
String HELLO_PATTERN_STR = ".*Hello \\d{1,5}";
String THROWABLE_PATTERN_STR = "java.lang.Throwable: i=\\d{1,5}";
String AT1_PATTERN_STR = "\\s*at " + PACKAGE_NAME + ".*";
String AT1_PATTERN_STR = "\\s*at " + "("+ MODULE_NAME+"@.*/)?" + PACKAGE_NAME + ".*";
String AT2_PATTERN_STR = "\\s*at " + ".*Thread.java.*";
Pattern PATTERN_OTHER = Pattern.compile(OTHER_PATTERN_STR);

49
slf4j-testing/pom.xml Normal file
View File

@ -0,0 +1,49 @@
<?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"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>3.0.0-alpha0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<artifactId>slf4j-testing</artifactId>
<packaging>jar</packaging>
<name>SLF4J Common Testing</name>
<description>SLF4J Common testing</description>
<url>http://www.slf4j.org</url>
<properties>
<module-name>org.slf4j.testing</module-name>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,5 @@
module org.slf4j.testing {
requires org.slf4j;
requires junit;
exports org.slf4j.testing;
}

View File

@ -22,7 +22,10 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.slf4j;
package org.slf4j.testing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.CyclicBarrier;

View File

@ -22,7 +22,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.slf4j.helpers;
package org.slf4j.testing;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -34,6 +34,7 @@ import java.util.Map;
import org.junit.After;
import org.junit.Test;
import org.slf4j.helpers.BasicMDCAdapter;
import org.slf4j.spi.MDCAdapter;
/**

View File

@ -1,7 +1,10 @@
package org.slf4j.testHarness;
package org.slf4j.testing;
import static org.junit.Assert.assertTrue;
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;
import java.util.ArrayList;
import java.util.Collections;
@ -10,15 +13,10 @@ import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerAccessingThread;
import org.slf4j.LoggerFactory;
import org.slf4j.event.EventRecordingLogger;
import org.slf4j.helpers.SubstituteLogger;
import static org.junit.Assert.fail;
abstract public class MultithreadedInitializationTest {
final protected static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2;
final protected static int THREAD_COUNT = 1;//4 + Runtime.getRuntime().availableProcessors() * 2;
private final List<Logger> createdLoggers = Collections.synchronizedList(new ArrayList<>());
@ -40,11 +38,12 @@ abstract public class MultithreadedInitializationTest {
long expectedEventCount = eventCount.get() + extraLogEvents();
assertTrue("unmet condition: " + expectedEventCount + " >= " + recordedEventCount, expectedEventCount >= recordedEventCount);
assertTrue("unmet condition: " + expectedEventCount + " < " + recordedEventCount + "+" + LENIENCY_COUNT, expectedEventCount < (recordedEventCount + LENIENCY_COUNT)); }
//assertTrue(expectedEventCount + " >= " + recordedEventCount, expectedEventCount >= recordedEventCount);
//assertTrue(expectedEventCount + " < " + recordedEventCount + "+" + LENIENCY_COUNT, expectedEventCount < recordedEventCount + LENIENCY_COUNT);
}
abstract protected long getRecordedEventCount();
protected int extraLogEvents() {
return 0;
}

View File

@ -22,12 +22,12 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.slf4j.basicTests;
package org.slf4j.testing;
import org.junit.After;
import org.junit.Before;
import org.slf4j.LoggerFactoryFriend;
import org.slf4j.testHarness.MultithreadedInitializationTest;
import org.slf4j.testing.MultithreadedInitializationTest;
/**
* Checks that when no binding is present, proper clean up is performed by LoggerFactory.

View File

@ -1,4 +1,4 @@
package org.slf4j.helpers;
package org.slf4j.testing;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;

View File

@ -0,0 +1,7 @@
<html>
<body>
<p>Here are the javadocs for the modules produced by the SLF4J project.</p>
</body>
</html>