qos-ch / slf4j Goto Github PK
View Code? Open in Web Editor NEWSimple Logging Facade for Java
Home Page: http://www.slf4j.org
License: MIT License
Simple Logging Facade for Java
Home Page: http://www.slf4j.org
License: MIT License
MDC is a useful way to inject pertinent context into log messages. But the current design makes it challenging to work with intra-service propagation solutions, like OpenTelemetry's Context mechanism. Typically these mechanisms are basically a Map
from aString
-shaped key to an Object
. MDC
provides a clear API for what we would want to propagate, which would be MDC.getCopyOfContextMap
, but when we switch threads, we would have access to that context again, but we wouldn't have a way to use that context. We would need to write code to call MDC.setContextMap
, and consistently do that every time we switch threads. Instead, it would be much easier if we could have SLF4J (or its implementations) call directly into the context propagation mechanism and read the context from there. In practice, they are often doing the same thing under the hood as a logging implementation with ThreadLocal, but they also have a mechanism for propagating the context across threads (for example with OTel, they have an auto-instrumentation java agent that can add java byte code to move the context automatically across when you fork, or schedule new work).
With the current API, folks go to extreme lengths to work around the current limitations of the SLF4J API.
Add a public API for overriding the MDCAdapter. Today, there's no way to wrap-and-modify or replace the MDCAdapter that's provided by a logging implementation. This means that if you want to change it, you need to take your logging implementation, rip out the suggested SLF4JServiceProvider implementation, and provide your own. Or else override MDC#mdcAdapter
. However, there is currently a scary message that this is not the only place where you must override MDC.mdcAdapter. Instead, it would be great for MDC to have an MDC.overrideMDCAdapter(MDCAdapter)
method that would also be compatible with the SLF4JServiceProvider implementations, perhaps adding a SLF4JServiceProvider#overrideMDCAdapter(MDCAdapter) method.
This has the advantage that it provides maximum flexibility. However, it may end up being a bit of a footgun if it provides too much flexibility and eventually becomes something that customers misuse.
Provide a way to register an additional way to fetch MDC Context. This could be an MDCExtension interface that exposes a method MDCExtension#getContext()
and MDCExtension#get(key)
. This would let customers provide extra info when it’s time to read MDCContext. To implement this, we could add a method to MDCAdapter to take into account this extra MDCExtension.
SLF4J users who do intra-service context propagation wouldn’t need to jump through hoops to integrate with MDC.
I'm happy to implement this feature once we've come to a consensus on what it should look like.
Right now, I'm working on the Apache Pulsar project, and migrating the slf4j to 2.0.12 from 1.7.36, but it always prints the following log:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
please see apache/pulsar#22391, the GHA env is Ubuntu, we are using the testcontainers to run the integration test, and the test image is based on the alpine 3.9:
I'm not sure where the problem is, thanks for your time!
docker run -it nodece/java-test-image bin/pulsar proxy
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
2024-04-07T14:35:25,623Z [jdk.internal.loader.ClassLoaders$AppClassLoader@63c12fb0] error Uncaught exception in thread main: java.lang.IllegalArgumentException: metadataStoreUrl must be provided
org.apache.pulsar.broker.PulsarServerException: java.lang.IllegalArgumentException: metadataStoreUrl must be provided
at org.apache.pulsar.proxy.server.ProxyServiceStarter.<init>(ProxyServiceStarter.java:205)
at org.apache.pulsar.proxy.server.ProxyServiceStarter.main(ProxyServiceStarter.java:215)
Caused by: java.lang.IllegalArgumentException: metadataStoreUrl must be provided
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:143)
at org.apache.pulsar.proxy.server.ProxyServiceStarter.<init>(ProxyServiceStarter.java:193)
... 1 more
2024-04-07T14:46:00,668+0000 [main] ERROR org.apache.pulsar.proxy.server.ProxyServiceStarter - Failed to start pulsar proxy service. error msg metadataStoreUrl must be provided
java.lang.IllegalArgumentException: metadataStoreUrl must be provided
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:143) ~[com.google.guava-guava-32.1.2-jre.jar:?]
at org.apache.pulsar.proxy.server.ProxyServiceStarter.<init>(ProxyServiceStarter.java:193) [org.apache.pulsar-pulsar-proxy-3.3.0-SNAPSHOT.jar:3.3.0-SNAPSHOT]
at org.apache.pulsar.proxy.server.ProxyServiceStarter.main(ProxyServiceStarter.java:215) [org.apache.pulsar-pulsar-proxy-3.3.0-SNAPSHOT.jar:3.3.0-SNAPSHOT]
2024-04-07T14:46:00,699Z [jdk.internal.loader.ClassLoaders$AppClassLoader@63c12fb0] error Uncaught exception in thread main: java.lang.IllegalArgumentException: metadataStoreUrl must be provided
org.apache.pulsar.broker.PulsarServerException: java.lang.IllegalArgumentException: metadataStoreUrl must be provided
at org.apache.pulsar.proxy.server.ProxyServiceStarter.<init>(ProxyServiceStarter.java:205)
at org.apache.pulsar.proxy.server.ProxyServiceStarter.main(ProxyServiceStarter.java:215)
Caused by: java.lang.IllegalArgumentException: metadataStoreUrl must be provided
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:143)
at org.apache.pulsar.proxy.server.ProxyServiceStarter.<init>(ProxyServiceStarter.java:193)
... 1 more
We are using a custom class loader for loading our application classes, but delegate loading SLF4j to standard classloaders.
Because of this SLF4J cannot load our custom ServiceProvider.
A simple fix for such situations is to perform a fallback search for service providers using context class loader.
The solution provided here would fix the issue.
I could provide an implementation if necessary.
slf4j-api-2.0.11
throws java.lang.NullPointerException
during Android build. But works perfect in versions 2.0.9
and below.
Our IDS detected an attempted remote code execution using a vulnerability exploiting CVE-2021-44228 and CVE-2021-45046, which Apache fixed by log4j 2.17.1. Are these vulnerabilities present in log4j-over-slf4j? Apache log4j 1.x was EOL in 2015 and won't receive any security patches, though those CVEs were only known to affect certain versions of log4j 2.x
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.13</version>
</dependency>
log4j2.xml
<Properties>
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %highlight{%-5level} [%t] %highlight{%c{1.}.%M(%L)}: %msg%n" />
<property name="FILE_PATH" value="${sys:LogHomeRoot}" />
</Properties>
...
public static void main(String[] args){
String runLogDir = STR."\{System.getProperty("user.dir")}\{File.separator}log";
System.setProperty("LogHomeRoot", runLogDir);
....
}
In the scenario described, I attempted to dynamically specify the log path at runtime. Since the project ultimately needs to be packaged using jlink/jpackage, I added a module-info.class for SLF4J. However, an exception was still thrown at runtime. Eventually, I had to add the Java option --add-reads org.slf4j=org.apache.logging.log4j.slf4j.impl to start the application,
this is quite troublesome... Can this issue be resolved in a future version?
I added the module-info file to the JAR using the following commands:
jdeps --ignore-missing-deps --generate-module-info . slf4j-api-1.7.36.jar
javac --patch-module org.slf4j=slf4j-api-1.7.36.jar org.slf4j/module-info.java
jar uf slf4j-api-1.7.36.jar -C org.slf4j module-info.class
stackTrace
Caused by: java.lang.IllegalAccessError: class org.slf4j.LoggerFactory (in module org.slf4j) cannot access class org.slf4j.impl.StaticLoggerBinder (in module org.apache.logging.log4j.slf4j.impl) because module org.slf4j does not read module org.apache.logging.log4j.slf4j.impl
at org.slf4j/org.slf4j.LoggerFactory.bind(LoggerFactory.java:150)
at org.slf4j/org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:124)
at org.slf4j/org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:417)
at org.slf4j/org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:362)
at org.slf4j/org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:388)
at my_driver/com.tom.controller.MyDriverPaneController.(MyDriverPaneController.java:16)
at my_driver/com.tom.FXMLVersionApp.start(FXMLVersionApp.java:23)
at javafx.graphics@22/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:839)
at javafx.graphics@22/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:483)
at javafx.graphics@22/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:456)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at javafx.graphics@22/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:455)
at javafx.graphics@22/com.sun.glass.ui.InvokeLaterDispatcher$Future.run$$$capture(InvokeLaterDispatcher.java:95)
Since Commons Logging 1.3.0 natively supports SLF4J as a backend (cf. apache/commons-logging#177), the jcl-over-slf4j
artifact became redundant.
The artifact uses the org.apache.commons.logging
namespace, which can cause problems in a JPMS environment.
cc/ @garydgregory
I am using the kotlin-logging library which is basically a wrapper around slf4j tailored for kotlin. (Original issue kotlin-logging-416).
When logging using the LoggingEventBuilder and setting the CallerBoundary accordingly it prints the wrong classname.
package my.pkg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.spi.CallerBoundaryAware;
public class Example {
private static final LoggingWrapper wrapper = new LoggingWrapper();
public static void main(String[] args) {
wrapper.logWithEvent("hello");
}
}
class LoggingWrapper {
private Logger underlyingLogger = LoggerFactory.getLogger("anything");
public void logWithEvent(String msg) {
var builder = underlyingLogger.atInfo();
// setting the caller boundary to LoggingWrapper
if(builder instanceof CallerBoundaryAware)
((CallerBoundaryAware) builder).setCallerBoundary(LoggingWrapper.class.getName());
builder.log(msg);
}
}
Running the given example I expect the following output:
Apr. 06, 2024 6:28:12 AM my.pkg.Example main
INFORMATION: hello
However following is printed:
Apr. 06, 2024 6:28:12 AM my.pkg.LoggingWrapper logWithEvent
INFORMATION: hello
Checkout the example: example.zip
XFrog triggers an alert XRAY-589059 on packages:
Looks like groupId domain org.slf4j can be claimed by malicious user.
Hi @ceki
Please, what's the log4j version used when I've org.slf4j:log4j-over-slf4j:jar:1.7.10:compile
as dependency?
Or at least, what's the log4j version that org.slf4j:log4j-over-slf4j:jar:1.7.10:compile
is trying to mock?
Is there any page that I can use use as reference to get this information?
My question is mainly to figure out what are the Log4j features that I'm able to use based on its version.
When using LoggingEventBuilder to addArgument
or addKeyValue
the only parameter options are Object or Supplier. If I use any primitive type (boolean, char, byte, short, int, long, float, double) then the compiler autoboxes them, even when the specified log level is not enabled and the Nop builder then discards them. This can generate a lot of eden garbage. This is an issue for me as I am working on a high throughput, garbage free, app which deals primarily in primitive types.
Adding these variants as additional methods eg addKeyValue("Foo", 1.23d)
etc would delay the auto boxing until when, and only when, the logging is going to output something.
Currently the only surefire way to avoid this is to wrap such logging within an is<Level>Enabled
block.
I thought it should be pronounced as "self-for-J",
but some people say "S-L-F-for-J", and I'm curious about how everyone pronounces it.
This is the default behavior since the very beginning of slf4j
, including the latest slf4j-api:2.0.9
:
When there's no provider available, slf4j prints an error message to stderr when the library is used for the first time and swallows all logging messages.
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
Can we just log to stdout instead of swallowing the messages?
I know there's a slf4j-simple
but it would be much easier to "combine" slf4j-api
and slf4j-simple
, or just log to stdout/stderr.
The graal native-image
gives us an opportunity to build fast command line tools, which will use some existing java libraries. Since slf4j
is widely used, a lot of libraries uses slf4j as their logging dependency.
However this requires us to include slf4j-simple
for the projects which depend on these libraries.
This is ok for projects running on the server side since it would always need a logging impl anyway, but it's quite redundant for the command-line tools, and it would require extra configurations when building the native-image (we must ensure slf4j-simple
accessible and can be used via reflection when building).
So can we consider to simply log to stdout when there is no provider available?
Hey Guys,
The module definition for the jcl-over-slf4j unfortunately does not specify the service loader for org.apache.commons.logging.LogFactory
When executing applications in a built JRE (Using JLink or JPackage), the services are loaded from their module definitions, and the functionality is not loaded.
Could you please possible update the module definition -
module org.apache.commons.logging {
requires org.slf4j;
exports org.apache.commons.logging;
provides org.apache.commons.logging.LogFactory with org.apache.commons.logging.impl.SLF4JLogFactory;
}
Much appreciated
Feature request
I am requesting a feature where the logger interface is extended to have an error
method that accepts varargs along with a Throwable
.
Motivation
Currently, the error
method accepts either a message with varargs or a message with a Throwable
. There isn't a method that accepts both combined. This leads to a situation where developers are forced to combine messages and/or params with error objects manually, which can lead to loss of stack trace information or awkward workarounds.
Suggested Solution
Add the following method to the Logger
interface:
void error(Throwable t,String format, Object... arguments);
Usage Example
This allows the user to log an error with formatting options as well as attaching an exception stack trace like so:
logger.error(throwable, "Something went wrong with the value: {} {}", value1, value2);
I believe this enhancement will make the API more flexible and user-friendly when dealing with common logging scenarios that involve both parameters and exceptions.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>3.0.0-alpha1</version>
</dependency>
DefaultLoggingEventBuilder addArgument with supplier should be executed an after calling log() not directly during "addArgument" calling, else it is same as constant value.
@Override
public LoggingEventBuilder addArgument(Supplier<?> objectSupplier) {
loggingEvent.addArgument(objectSupplier.get());
return this;
}
should be
@Override
public LoggingEventBuilder addArgument(Supplier<?> objectSupplier) {
loggingEvent.addArgument(objectSupplier);
return this;
}
Same behaviour is in "Log4jEventBuilder"
Are there any compatibility issues when we need to upgrade slf4j from 1.7.36 to 2.x?
Besides ordinary/journal logging there are other logging needs like audit, trace, and metrics logging. Those other types of logging have all in common that the log message shall be published independently of a logging level.
Log4J2
supports such use cases by invoking org.apache.logging.log4j.spi.ExtendedLogger#logIfEnabled
with level
set to org.apache.logging.log4j.Level#OFF
.
How would SLF4J
support such use cases? It would be nice to have a method like org.slf4j.Logger#atOff#log(org.slf4j.Marker, java.lang.String)
or org.slf4j.Logger#log(org.slf4j.Marker, java.lang.String)
with a corresponding binding to Log4J2
that always publishes a log message independently of the log level.
Without such, the above mentioned use cases cannot elegantly implemented using this facade.
It would be extremely useful to bundle the slf4j-simple
logging implementation as a separate artifact (e.g. slf4j-simple-impl
) so that it can be used without exposing it as an automatically detected service provider. (P.S. I didn't realize how cool the name slf4j-simple-impl
is until I just wrote that.) This would involve simply splitting out the implementation code (and perhaps the actual SimpleServiceProvider
class as well, without exposing it as a service) into a separate subproject—little if any actual code changes would be needed.
You can see how I've done something similar with Clogr's https://github.com/globalmentor/clogr/tree/main/clogr-logback and https://github.com/globalmentor/clogr/tree/main/clogr-logback-provider .
This would bring a couple of big wins, notably solving SLF4J-592
: Mechanism for indicating provider to use for unit tests. Let me lay out the use cases:
Splitting out the slf4j-simple
implementation would allow others to create specialized versions. Without the separate artifact, a specialized version has to duplicate the slf4j-simple
code, because otherwise simply referring to that dependency would expose a provider that would be detected by SLF4J, resulting in "dueling providers".
This is not a theoretical need. Read Solving the Java Aws Lambda logging problem, in which Frank Afriat (@fafriat) investigates how to create a logging implementation that is simple but plays well with AWS Lambda. In theory you would just write to stdout
/stderr
, but there are a couple of gotchas Frank had to work around. He had to fork slf4j-simple
and make a customized version. I believe (although I haven't asked him) that had slf4j-simple-impl
existed, he could have simply used that dependency, added a few tweaks, and then exposed his own provider rather than copying all the code as he has done.
If slf4j-simple-impl
existed, I could include the dependency but not expose SimpleServiceProvider
via the Java service provider mechanism, so that it wouldn't be detected by SLF4J automatically, requiring me to manually "enable it".
In SLF4J-592
: Mechanism for indicating provider to use for unit tests (see also my Maven exclude/remove test dependency defined in parent POM and someone else's Is there any simple pattern of slf4j usage in unit tests?) I pondered how I want logging to work in unit tests. After months of thinking, I finally know:
stderr
during the build, just by setting some flag.I both cases, I don't want to affect the logging provider used by the artifacts actually being built.
With slf4j-simple-impl
(assuming you put SimpleServiceProvider
inside slf4j-simple-impl
as well, but don't expose it as a Java service provider), I could simply include slf4j-simple-impl
in test
scope in my parent POM. All my tests would automatically get the slf4j-simple-impl
logging implementation, but it wouldn't be used—it would lurking, ready to be enabled.
In my build I would set slf4j.provider
to ….NOP_FallbackServiceProvider
during unit/integration tests. This would address 1) above—all logging in unit tests would be suppressed. This would not conflict with or affect in any way the logging providers of the actual artifacts build for the various libraries and applications.
In my build I would add a Maven debug
profile that I could invoke with -P debug
. This would override slf4j.provider
with ….SimpleServiceProvider
for the unit/integration tests. Suddenly all my unit tests would start logging to stdout
/stderr
(whichever I have configured), helping me to track down problems in the build. This addresses 2) above.
I believe this would be a complete, comprehensive solution to the build unit/integration test logging question. And pulling it off would be so simple. (The only remaining question would be whether to include SimpleServiceProvider
in slf4j-simple-impl
but not expose it as a service; or leave it in slf4j-simple
, requiring consumers to create their own provider wrapper class.)
Note that if you decide not to split out slf4j-simple-impl
, I can easily write my own simple logging implementation—it would just be a shame to reinvent the wheel.
If you think this is a great idea, just let me know and I could probably file a pull request for it.
Hello,
Currently i'm using Slf4j version 2.0.11 and Logback version 1.4.14
I'm working on an old products with a lot of code and using a lot of thread, so I need to have MDC properties thread inheritance. So I force the usage of a BasicMDCAdapter by setting the MDC.mdcAdapter to new BasicMDCAdapter() when my program starts.
The problem is that, using Slf4j version 2.0.11 and Logback version 1.4.14 this doesn't work anymore.
I don't have any MDC info in my logs.
Could you please tell me what is the correct way to use your BasicMDCAdapter ? or tell me another way to have MDC properties thread inheritance ?
Many thanks
it looks like it is trying to create e new instance based on this property. I guess it would be better to loop over the providers and check if there is a matching instance.
SLF4J(I): Attempting to load provider "org.slf4j.simple.SimpleServiceProvider" specified via "slf4j.provider" system property
SLF4J(E): Failed to instantiate the specified SLF4JServiceProvider (org.slf4j.simple.SimpleServiceProvider)
SLF4J(E): Reported exception:
java.lang.IllegalAccessException: class org.slf4j.LoggerFactory (in module org.slf4j) cannot access class org.slf4j.simple.SimpleServiceProvider (in module org.slf4j.simple) because module org.slf4j.simple does not export org.slf4j.simple to module org.slf4j
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:394)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:714)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:495)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
at [email protected]/org.slf4j.LoggerFactory.loadExplicitlySpecified(LoggerFactory.java:225)
Our team wrote some code that broadly looked like this:
MDC.put("color", "red");
try(ignored = MDC.putCloseable("color", "green")) {
...
}
assertTrue(MDC.get("color", "green")) // fails, the key is deleted
It should be an easy patch to allow callers to nest putCloseable calls and get expected results; in fact, I'll go try to write one now.
Thank you very much, by the way, for SLF4j -- it's a wonderful tool. Cheers
Failed to load slf4j-api in the OSIG environment.
ERROR log :
Unresolved requirement: Import-Package: org.slf4j
-> Export-Package: org.slf4j; bundle-symbolic-name="slf4j.api"; bundle-version="2.0.12"; version="1.7.36"
slf4j.api [9]
Unresolved requirement: Require-Capability: osgi.extender; filter:="(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))"
Unresolved requirement: Import-Package: org.slf4j.helpers
-> Export-Package: org.slf4j.helpers; bundle-symbolic-name="slf4j.api"; bundle-version="2.0.12"; version="1.7.36"
in parent pom.xml slf4j-master/slf4j-master/parent/pom.xml
<latest.1.version>1.7.36</latest.1.version>
in slf4j-api pom.xml
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<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[
*,\
**org.slf4j;version="${latest.1.version}",\
org.slf4j.helpers;version="${latest.1.version}"**
]]></_exportcontents>
<Require-Capability><![CDATA[
**osgi.extender;filter:="(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))",**
osgi.serviceloader;filter:="(osgi.serviceloader=org.slf4j.spi.SLF4JServiceProvider)";osgi.serviceloader="org.slf4j.spi.SLF4JServiceProvider"
]]></Require-Capability>
</instructions>
</configuration>
</plugin>
Please help to check the verification logic of the version number and filter.
Thanks
I want to use 'org.slf4j:slf4j-simple' on 'Android Studio Flamingo | 2022.2.1'.
in file 'app/build.gradle' / block 'dependencies', only add
implementation 'org.slf4j:slf4j-simple:2.0.13'
build error
> Task :app:mergeExtDexDebug FAILED
AGPBI: {"kind":"error","text":"java.lang.NullPointerException","sources":[{"file":"C:\\Users\\wanko\\.gradle\\caches\\modules-2\\files-2.1\\org.slf4j\\slf4j-simple\\2.0.13\\be11a3f05f7cf546524b07ad252719d840f4daed\\slf4j-simple-2.0.13.jar"}],"tool":"D8"}
AGPBI: {"kind":"error","text":"java.lang.NullPointerException","sources":[{"file":"C:\\Users\\wanko\\.gradle\\caches\\modules-2\\files-2.1\\org.slf4j\\slf4j-api\\2.0.13\\80229737f704b121a318bba5d5deacbcf395bc77\\slf4j-api-2.0.13.jar"}],"tool":"D8"}
> Task :app:processDebugManifestForPackage
> Task :app:mergeLibDexDebug
> Task :app:mergeDebugResources
> Task :app:mergeDebugJavaResource
> Task :app:processDebugResources
> Task :app:compileDebugJavaWithJavac
> Task :app:dexBuilderDebug
> Task :app:mergeProjectDexDebug
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:mergeExtDexDebug'.
> Could not resolve all files for configuration ':app:debugRuntimeClasspath'.
> Failed to transform slf4j-simple-2.0.13.jar (org.slf4j:slf4j-simple:2.0.13) to match attributes {artifactType=android-dex, asm-transformed-variant=NONE, dexing-enable-desugaring=true, dexing-enable-jacoco-instrumentation=false, dexing-is-debuggable=true, dexing-min-sdk=21, org.gradle.category=library, org.gradle.libraryelements=jar, org.gradle.status=release, org.gradle.usage=java-runtime}.
> Execution failed for DexingWithClasspathTransform: C:\Users\wanko\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-simple\2.0.13\be11a3f05f7cf546524b07ad252719d840f4daed\slf4j-simple-2.0.13.jar.
> Error while dexing.
> Failed to transform slf4j-api-2.0.13.jar (org.slf4j:slf4j-api:2.0.13) to match attributes {artifactType=android-dex, asm-transformed-variant=NONE, dexing-enable-desugaring=true, dexing-enable-jacoco-instrumentation=false, dexing-is-debuggable=true, dexing-min-sdk=21, org.gradle.category=library, org.gradle.libraryelements=jar, org.gradle.status=release, org.gradle.usage=java-runtime}.
> Execution failed for DexingWithClasspathTransform: C:\Users\wanko\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-api\2.0.13\80229737f704b121a318bba5d5deacbcf395bc77\slf4j-api-2.0.13.jar.
> Error while dexing.
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 8s
30 actionable tasks: 30 executed
OK
implementation 'org.slf4j:slf4j-simple:2.0.9'
NG
implementation 'org.slf4j:slf4j-simple:2.0.10'
implementation 'org.slf4j:slf4j-simple:2.0.12'
implementation 'org.slf4j:slf4j-simple:2.0.13'
While evaluating the License Maven Plugin to manage/download dependency licenses, I noticed that it does not download the 'correct' license for SLF4J. It does download a copy of the MIT license but the downloaded copy includes a generic copyright notice compared to a specific SLF4J copyright notice:
- Copyright <YEAR> <COPYRIGHT HOLDER>
+ Copyright (c) 2004-2023 QOS.ch
The plugin downloads the license referenced in <license><url>
in the project's main POM. In this case, the specified URL points to the generic copy of the MIT license hosted at opensource.org: http://www.opensource.org/licenses/mit-license.php. Project Lombok, for example, points to its custom copy of the MIT license (which also includes the license of each dependency), instead:
<license>
<name>The MIT License</name>
<url>https://projectlombok.org/LICENSE</url>
<distribution>repo</distribution>
</license>
Now I am wondering if it is an oversight to not point to SLF4J's specific copy of the MIT license?
Please notice, I deliberately ignore the discussion, if the MIT license actually requires projects depending on an MIT licensed dependency to bundle a copy of that license: Including a copy of the license does not break the license while not including it may.
Thanks for considering and please feel free to simply close this ticket, if you do not consider this an issue as grabbing a copy of the license and manually bundling it with our project(s) is simple.
Also, I've noticed that some of the sub modules in this project include license files with different a copyright notice. For example the copyright notice of the jul-to-slf4j
sub module reads Copyright (c) 2004-2022 QOS.ch Sarl (Switzerland)
, which would require that sub module's POM to override <license><url>
to point to its own license file, if the above is considered an issue.
While reading slf4j2 code to figure out how bindingsproviders work, I came across a line that confused me: catch(NoSuchFieldError)
in LoggerFactory
slf4j/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java
Lines 364 to 388 in 216459e
I was wondering why the comment references REQUESTED_API_VERSION
, while there's no such thing in the try
.
I found the change that invalidated that catch
, and I'm still baffled as to why Java does not complain about a checked exception being not used I see why javac didn't alert: it's an Error
, not checked!.
If no SLF4J providers are found, SLF4J defaults to no-op logger, which results in all logs, including errors and exceptions being hidden.
IMO this is not a sane default, a better default would be logging exceptions, errors and warning to stdout
. stdout
is perfectly fine for development and became a common practice for Docker containers in production.
The codebase already has SimpleLogger
that does this, but when I tried to reference it in slf4j.LoggerFactory
it introduced a circular dependency. Maybe it makes sense to copy SimpleLogger
to base package, remove all extra code for configurability/etc, call it FallbackStdoutLogger
and use it by default?
I was using log4j version 2.23.1 which comes with slf4j-api version 2.0.9. Below are the dependencies:
<log4j2.version>2.23.1</log4j2.version>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>${log4j2.version}</version>
</dependency>
And I was using maven-assembly-plugin to build a single jar with all dependencies
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.7.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>assemble-all</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Included the following imports:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Using slf4j logger
Logger log = LoggerFactory.getLogger(Main.class);
When I run the standalone main application (fat jar including all the dependencies), I see the below log in the console
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
When I run same standalone main application (without fat jar) and added the above log4j and slf4j dependencies to classpath, I don't see any issue
Good work @KengoTODA on SLF4J-450. Unfortunately the PROVIDER_PROPERTY_KEY
constant is not public in LoggerFactory
:
static final public String PROVIDER_PROPERTY_KEY = "slf4j.provider";
This is part of the official, documented API, so it's appropriate that it should be public. After all I might want to programmatically set the system property like this (see #361), for example in JUnit tests:
@BeforeAll
static void disableLogging() {
System.setProperty("slf4j.provider", NOP_FallbackServiceProvider.class.getName());
}
If nobody has any objections, I can file a pull request for this.
When logging with either the System.Logger or the JUL the expectation of passing Level.OFF
(which does not have an SLF4J analog) is inconsistent when they should be same. Ideally they should both NOOP.
That is when passing making a logging request with Level.OFF it should be off.
This can be clearly seen in java.util.logging.Handler.isLoggable(LogRecord)
public boolean isLoggable(LogRecord record) {
final int levelValue = getLevel().intValue();
if (record == null) return false;
if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
return false;
}
final Filter filter = getFilter();
if (filter == null) {
return true;
}
return filter.isLoggable(record);
}
N.B. the levelValue == offValue
. All JUL handlers inherit isLoggable
including the SLF4J bridge.
However here it is turned into ERROR
here:
Worse is in the System.Logger it is reported as an error:
It clearly was the intention of the System.Logger to follow JUL behavior as it is documented:
/**
* A marker to indicate that all levels are disabled.
* This level {@linkplain #getSeverity() severity} is
* {@link Integer#MAX_VALUE}.
*/
OFF(Integer.MAX_VALUE); // typically mapped to/from j.u.l.Level.OFF
Links from chapter "Where can I get a particular SLF4J provider/binding?" of FAQ (https://www.slf4j.org/faq.html) don't work.
Quote:
SLF4J providers for SimpleLogger, NOPLogger, Log4jLoggerAdapter and JDK14LoggerAdapter are contained within the files slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, and slf4j-jdk14.jar.
I really often hit issue with slf4j interpreting my messages not the way I'd like it to.
I don't think its reasonable to have two following lines result in different behaviour.
Throwable ex = ...
Item item = ...
log.warn("Processing issue; ex={}, item={}", ex, item); // this works fine
log.warn("Processing issue; item={}, ex={}", item, ex); // and this produces "... issue=Issue(123), ex={}" followed by stacktrace
I think the MessageFormatter
should take into account number of placeholders, and try to use last argument as throwable candidate only if not bound.
FAQ says:
If the exception is not the last argument, it will be treated as a plain object and its stack trace will NOT be printed. However, such situations should not occur in practice.
For me this is not true. I quite often want to see just ex.toString
, specially where exception is part of business logic. I just want to log its name, description, details - I don't care about stack trace. So it's common to treat exception just as any other part of message.
SLF4J, in accordance with the programmer's most probable intention, will interpret NumberFormatException instance as a throwable instead of an unused Object parameter
And this one actually suggests what should be done. It says about choice between exception and unused object parameter. And code actually does not check if parameter is used - it just picks last argument, resulting in message with last '{}' not filled in, and with unwanted stacktrace appended.
I didn't realize SLF4J-450 was already implemented, so I was excited to look into this. Thanks for the work on this, @ceki and @KengoTODA.
In the source code I see:
static SLF4JServiceProvider loadExplicitlySpecified(ClassLoader classLoader) {
String explicitlySpecified = System.getProperty(PROVIDER_PROPERTY_KEY);
if (null == explicitlySpecified || explicitlySpecified.isEmpty()) {
return null;
}
try {
String message = String.format("Attempting to load provider \"%s\" specified via \"%s\" system property", explicitlySpecified, PROVIDER_PROPERTY_KEY);
Util.report(message);
…
Unfortunately this logs a message to stderr
every time we use the slf4j.provider
property. I don't quite understand the point of that. Logging something to stderr
outside of the normal SLF4J logging system should only be done as a last resort, if there is some unexpected error. For example, if no logger implementation is present, SLF4J indicates, "No SLF4J providers were found."
. The point here is that the user should be warned if they inadvertently don't include a logging implementation. (I'm not sure I fully agree with that decision, but I certain understand the motivation.)
But there is nothing inadvertent about the slf4j.provider
. If you include it, you know you're specifically requesting a logging provider. You don't need SLF4J to remind you of that. If SLF4J uses a provider it finds on the classpath, SLF4J doesn't send a message to stderr
notifying the user of which provider they chose. I don't see the difference here—if any thing, there is less of a reason to log information, because nothing happened "by default"—there was an explicit configuration.
Let's say that I want all my unit tests to ignore all logging output of the libraries they use, so that I won't have to have a logging implementation in test
scope at all. (See SLF4J-592.) By default SLF4J does a a NOP, so I could just leave it at that, except that all my unit tests will have this:
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
SLF4J-450 should fix that! Now I can do this in JUnit:
@BeforeAll
static void disableLogging() {
System.setProperty("slf4j.provider", NOP_FallbackServiceProvider.class.getName());
}
Now I get the following, which defeats the purpose of what I was trying to do. 🤦♂️
SLF4J: Attempting to load provider "org.slf4j.helpers.NOP_FallbackServiceProvider" specified via "slf4j.provider" system property
I can do an ugly hack to get rid of the message:
@BeforeAll
static void disableLogging() {
System.setProperty("slf4j.provider", NOP_FallbackServiceProvider.class.getName());
final PrintStream originalSystemErr = System.err;
try {
System.setErr(new PrintStream(OutputStream.nullOutputStream()));
LoggerFactory.getILoggerFactory();
} finally {
System.setErr(originalSystemErr);
}
}
That suppresses the message. But if I'm going to do that, there's no point in using slf4j.provider
at all, because SLF4J would default to the NOP provider anyway.
Please remove messages to stderr
when slf4j.provider
is used. Or just let me know that you're OK with this change, and I can file a pull request.
In the documentation it is written:
SINCE 2.0.8 You can specify the provider class explicitly via the "slf4j.binding" system property. This bypasses the service loader mechanism for finding providers and may shorten SLF4J initialization.
But looking at the code (here), it is not slf4j.binding
but slf4j.provider
.
Can you update the documentation ?
When I execute mvn test in the source directory, I report the following error:
----------------< org.slf4j:slf4j-jdk-platform-logging >----------------
[INFO] Building SLF4J JDK Platform Logging Integration 2.0.10 [7/16]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ slf4j-jdk-platform-logging ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 1 resource to META-INF
[INFO]
[INFO] --- maven-compiler-plugin:3.10.1:compile (default-compile) @ slf4j-jdk-platform-logging ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-compiler-plugin:3.10.1:compile (module-compile) @ slf4j-jdk-platform-logging ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-bundle-plugin:5.1.9:manifest (bundle-manifest) @ slf4j-jdk-platform-logging ---
[INFO] Stale files detected, re-generating manifest.
[INFO] Writing manifest: /home/stage/root/spack-stage-slf4j-2.0.10-d3eqrim3igcnehqt456nzz2wvlafq2sh/spack-src/slf4j-jdk-platform-logging/target/classes/META-INF/MANIFEST.MF
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ slf4j-jdk-platform-logging ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/stage/root/spack-stage-slf4j-2.0.10-d3eqrim3igcnehqt456nzz2wvlafq2sh/spack-src/slf4j-jdk-platform-logging/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.10.1:testCompile (default-testCompile) @ slf4j-jdk-platform-logging ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to /home/stage/root/spack-stage-slf4j-2.0.10-d3eqrim3igcnehqt456nzz2wvlafq2sh/spack-src/slf4j-jdk-platform-logging/target/test-classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] module not found: org.slf4j
[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for SLF4J BOM 2.0.10:
[INFO]
[INFO] SLF4J BOM .......................................... SUCCESS [ 0.006 s]
[INFO] SLF4J Parent POM ................................... SUCCESS [ 0.848 s]
[INFO] SLF4J API Module ................................... SUCCESS [ 4.847 s]
[INFO] SLF4J Simple Provider .............................. SUCCESS [ 3.226 s]
[INFO] SLF4J NOP Provider ................................. SUCCESS [ 1.080 s]
[INFO] SLF4J JDK14 Provider ............................... SUCCESS [ 2.813 s]
[INFO] SLF4J JDK Platform Logging Integration ............. FAILURE [ 0.600 s]
[INFO] SLF4J LOG4J-12 Binding relocated ................... SKIPPED
[INFO] SLF4J Reload4j Provider ............................ SKIPPED
[INFO] SLF4J Extensions Module ............................ SKIPPED
[INFO] JCL 1.2 implemented over SLF4J ..................... SKIPPED
[INFO] Log4j Implemented Over SLF4J ....................... SKIPPED
[INFO] JUL to SLF4J bridge ................................ SKIPPED
[INFO] OSGi LogService implemented over SLF4J ............. SKIPPED
[INFO] SLF4J Integration tests ............................ SKIPPED
[INFO] SLF4J Migrator ..................................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.908 s
[INFO] Finished at: 2024-01-05T15:20:30+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:testCompile (default-testCompile) on project slf4j-jdk-platform-logging: Compilation failure
[ERROR] module not found: org.slf4j
[ERROR]
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR] mvn <args> -rf :slf4j-jdk-platform-logging
[root@simon28li spack-src]#
[root@simon28li spack-src]# pwd
/home/stage/root/spack-stage-slf4j-2.0.10-d3eqrim3igcnehqt456nzz2wvlafq2sh/spack-src
But when I went to the subdirectory where the test error was reported to test, I didn't report an error. What caused this?
[root@simon28li spack-src]# cd slf4j-jdk-platform-logging
[root@simon28li slf4j-jdk-platform-logging]# mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< org.slf4j:slf4j-jdk-platform-logging >----------------
[INFO] Building SLF4J JDK Platform Logging Integration 2.0.10
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ slf4j-jdk-platform-logging ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 1 resource to META-INF
[INFO]
[INFO] --- maven-compiler-plugin:3.10.1:compile (default-compile) @ slf4j-jdk-platform-logging ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-compiler-plugin:3.10.1:compile (module-compile) @ slf4j-jdk-platform-logging ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-bundle-plugin:5.1.9:manifest (bundle-manifest) @ slf4j-jdk-platform-logging ---
[INFO] Stale files detected, re-generating manifest.
[INFO] Writing manifest: /home/stage/root/spack-stage-slf4j-2.0.10-d3eqrim3igcnehqt456nzz2wvlafq2sh/spack-src/slf4j-jdk-platform-logging/target/classes/META-INF/MANIFEST.MF
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ slf4j-jdk-platform-logging ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/stage/root/spack-stage-slf4j-2.0.10-d3eqrim3igcnehqt456nzz2wvlafq2sh/spack-src/slf4j-jdk-platform-logging/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.10.1:testCompile (default-testCompile) @ slf4j-jdk-platform-logging ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to /home/stage/root/spack-stage-slf4j-2.0.10-d3eqrim3igcnehqt456nzz2wvlafq2sh/spack-src/slf4j-jdk-platform-logging/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:3.0.0-M7:test (default-test) @ slf4j-jdk-platform-logging ---
[INFO] Using auto detected provider org.apache.maven.surefire.junit4.JUnit4Provider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.slf4j.jdk.platform.logging.test.SLF4JPlatformLoggingTest
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.114 s - in org.slf4j.jdk.platform.logging.test.SLF4JPlatformLoggingTest
[INFO] org.slf4j.jdk.platform.logging.test.SLF4JPlatformLoggingTest.throwTest Time elapsed: 0.034 s
[INFO] org.slf4j.jdk.platform.logging.test.SLF4JPlatformLoggingTest.smoke Time elapsed: 0 s
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.298 s
[INFO] Finished at: 2024-01-05T15:25:11+08:00
[INFO] ------------------------------------------------------------------------
[root@simon28li slf4j-jdk-platform-logging]#
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.