Correctly fixing multiple `StaticLoggerBinder` bindings in Spark - maven

I had a nice little Maven-built CLI application using Java 17 on Windows 10. For logging I went over SLF4J (org.slf4j:slf4j-api:1.7.36) with Logback (ch.qos.logback:logback-classic:jar:1.2.11) as the implementation.
That was fine until I added Spark 3.3.0 into the mix:
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_${scala.version}</artifactId>
<version>${spark.version}</version>
</dependency>
Then when I run my application, I get this:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in […/lib/logback-classic-1.2.11.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in […/lib/log4j-slf4j-impl-2.17.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
When I do a mvn dependency:tree, it looks like Spark is bringing in all this mess:
[INFO] | +- org.slf4j:jul-to-slf4j:jar:1.7.36:compile
[INFO] | +- org.slf4j:jcl-over-slf4j:jar:1.7.36:compile
[INFO] | +- org.apache.logging.log4j:log4j-slf4j-impl:jar:2.17.2:compile
[INFO] | +- org.apache.logging.log4j:log4j-api:jar:2.17.2:compile
[INFO] | +- org.apache.logging.log4j:log4j-core:jar:2.17.2:compile
[INFO] | +- org.apache.logging.log4j:log4j-1.2-api:jar:2.17.2:compile
In particular org.apache.logging.log4j:log4j-slf4j-impl:jar:2.17.2 is the core problem; it's a Log4j 2 SLF4J Binding for an application logging to SLF4J, to use Log4J as the SLF4J implementation. But I'm using Logback as my SLF4J implementation. So I can exclude the Log4J implementation like this:
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_${scala.version}</artifactId>
<version>${spark.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</exclusion>
</exclusions>
</dependency>
Wonderful; now the warning goes away. I've solved the problem.
But here is my concern: you can see above that Spark is also bringing in log4j-api (the Log4J API itself) as well as log4j-1.2-api, which is a Log4j 1.2 Bridge for applications that write to the Log4J 1.x API! Does this mean that Spark is writing to the Log4J 2.x API itself, or even (horrors!) to the Log4J 1.x API? 🤦‍♂️
Do I also need to include a Log4J-to-SLF4J bridge dependency so that whatever code that uses Log4J in some corner of Spark will correctly get its log output routed to SLF4J? Or is all this extra Log4J gunk included because someone setting up the POM didn't quite fully understand what it means to write to the SLF4J API, and just threw the kitchen sink at things?
In other words, am I good with the Log4J 2 implementation exclusion above, or do I also need to add Log4J-to-SLF4j bridges for some piece of Spark that writes directly to the Log4J API rather than through the SLF4J API?

Related

Adding javax.servlet-api dependency throws exception that org.slf4j.impl.StaticLoggerBinder faild to load but i don't use sl4j, i use thymeleaf

Basicaly title. I'm trying to run simple spring5 + thymeleaf project. If i don't add servlet-api i get an error that
cannot access javax.servlet.ServletException
But if i add servlet-api, project starts and works fine , but i get an error on startup:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
But i don't use sl4j, i use thymeleaf. How does servlet exception connected with sl4j and how should i manage it?
UPD
I understand that my question is wrong. But i need help with connected problem:
As someone suggested i added
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
But i still get Failed to load class "org.slf4j.impl.StaticLoggerBinder". exception. Any ideas?
UPD
as someone mentioned here this is a bug of ide
Add slf4j.jar in your dependency or your project. Spring internally use slf4j for its own logging.
I'm using IntelIj idea.
As someone sugested i added log4j and sl4j dependencies becouse servlet-api uses loging by default. And my exception that class is failed to load is just a bug of ide as it was mentioned in another question and everything including logging works fine.

where does the maven version get overridden?

I am building a spring boot starter, following the recommended convention with core / autoconfigure / starter module separation. When I look at the maven dependency-tree, this is what I have :
[INFO] com.myDomain.myProject:myProject-starter:jar:1.0.8-SNAPSHOT
[INFO] +- com.myDomain.myProject:myProject-autoconfigure:jar:1.0.8-SNAPSHOT:compile
[INFO] | \- com.myDomain.myProject:myProject-core:jar:1.0.8-SNAPSHOT:compile
[INFO] | +- io.github.openfeign:feign-gson:jar:9.5.1:compile
[INFO] | | +- io.github.openfeign:feign-core:jar:9.5.1:compile
[INFO] | | \- com.google.code.gson:gson:jar:2.8.5:compile
gson comes in v2.8.5, which is the version I expect - my project works with it
(note : in https://mvnrepository.com/artifact/io.github.openfeign/feign-core/9.5.1 , we see that the expected version for gson is 2.5... so not sure why I get 2.8.5..)
In my root pom.xml, I declare the BOM like this :
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
<version>2.0.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
and in my "core" pom.xml :
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
</dependencies>
Now, in another project, I use the starter. So my pom.xml is very simple :
<dependencies>
<dependency>
<groupId>com.myDomain.myProject</groupId>
<artifactId>myProject-starter</artifactId>
<version>1.0.8-SNAPSHOT</version>
</dependency>
</dependencies>
When I look at the dependency tree in this project, I get this :
[INFO] \- com.myDomain.myProject:myProject-starter:jar:1.0.8-SNAPSHOT:compile
[INFO] +- com.myDomain.myProject:myProject-autoconfigure:jar:1.0.8-SNAPSHOT:compile
[INFO] | \- com.myDomain.myProject:myProject-core:jar:1.0.8-SNAPSHOT:compile
[INFO] | +- io.github.openfeign:feign-gson:jar:9.5.1:compile
[INFO] | | +- io.github.openfeign:feign-core:jar:9.5.1:compile
[INFO] | | \- com.google.code.gson:gson:jar:2.5:compile
gson comes in v2.5, and because of that it doesn't work. If I override it in the pom.xml, by declaring gson 2.8.5 before the starter, then it works..
But there must be something that I am missing in the way Maven works..
I've tried deleting the 1.0.8-snapshot version from my local repo, then rebuild, it, to make sure my second project was not taking an older version, but I keep getting this incorrect version in my build, and I have no clue where it's coming from / what overrides it.
code is available in this branch if you want to give it a try locally : https://github.com/societe-generale/github-crawler/tree/sprinBoot2upgrade
I am really interested in any pointer for investigation, to understand the root cause, because I am quite confused right now..
Thanks !
=========================================
EDIT 1
As mentioned in comments, it's Spring Boot starter that overrides the gson version to 2.8.5 (instead of the 2.5 planned in feign-core).
So now the question becomes : how come that when I use the starter as the single dependency in another project with no parent, that overridden version (2.8.5) disappears and I end up with the initial version (2.5) that is not compatible with spring-boot-autoconfigure 2.0.4.RELEASE ?
EDIT 2
I have created a fresh, more focused question here : Not getting the expected version when using the Spring Boot starter I built
quick summary based on the various hints in the question comments
Verbose mode is discontinued since Maven 3.x, so use mvn dependency:tree -X to get more details on versions used/overridden, etc. Then you get something like that :
[DEBUG] io.github.openfeign:feign-gson:jar:9.5.1:compile
[DEBUG] com.google.code.gson:gson:jar:2.8.5:compile (version managed from 2.5 by org.springframework.boot:spring-boot-dependencies:2.0.4.RELEASE)
-> this points quite clearly to where the version is coming from, ie https://github.com/spring-projects/spring-boot/blob/v2.0.4.RELEASE/spring-boot-project/spring-boot-dependencies/pom.xml#L65

Setting Logger Implementation to Test Scope with Maven for IntelliJ

For automated tests of an API, I need to have an implementation of a logger present. But the logger is supposed to not ship with the API itself. To that end I set up the relevant part of the pom.xml of the API module itself like so:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
When I manually run maven from the command line the test where the logger is relevant passes. But when I run the test file from within Intellij I get the following error:
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.
I have spent several hours now trying to figure out what is wrong and followed multiple tutorials. None actually covered the sort of setup I need though and so I am still stuck with this error.
Do you know what the actual problem is here and how to set this up correctly?

Hibernate (4.3.11-Final) logging not bridging to log4j2?

We are migrating from log4j to log4j2. We use the following libraries and there logging mechanisms:
Tomcat (which uses JULI), Spring 4.2.0 (which uses commons-logging) and Hibernate 4.3.11-Final (which uses jboss-logging).
I have successfully got Spring bridging to log4j2, but Hibernate logging is not working.
According to the Hibernate docs:
To use JBoss Logging with Log4j2, the log4j2 jar would also need to be available on the classpath.
I have the following logging-related jars on my classpath:
commons-logging-1.2.jar
jboss-logging-3.1.3.GA.jar
jboss-logging-annotations-1.2.0.Beta1.jar
log4j-api-2.6.1.jar
log4j-core-2.6.1.jar
log4j-jcl-2.6.1.jar
log4j-slf4j-impl-2.6.1.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
Any ideas why I'm not seeing the results I expect?
The version of jboss-logging included with hibernate-4 is not compatible with log4j2.
I had to import version 3.3.0.Final (should work starting with 3.1.4, according to JBLOGGING-94) for hibernate to work with log4j2.
Here is a shortcut if you use maven :
<dependency> <!-- version working with log4j2 -->
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.3.0.Final</version>
<scope>runtime</scope>
</dependency>

Shiro Plugin conflicting with Quartz framework in Grails

I have been working Quartz framework in my grails project with lib called quartz-all-1.7.3.
Now I need to install the shiro plugin to my project. So, whenever I am installing shiro plugin to my project its getting installed successfully..
But again whenever I am running my project again it's giving compilation error as follows :
[groovyc] org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
[groovyc] Compile error during compilation with javac.
[groovyc] ....scheduler\quartz\framework\CustomJDBCDelegate.java:46: com.securonix.application.scheduler.quartz.framework.CustomJDBCDelegate is not abstract and does not override abstract method updateSchedulerState(java.sql.Connection,java.lang.String,long,java.lang.String) in org.quartz.impl.jdbcjobstore.DriverDelegate
[groovyc] public class CustomJDBCDelegate implements DriverDelegate, StdJDBCConstants {
[groovyc] ^
So after long look on shiro plugin I have found that it has some dependencies with plugins. In that one of the dependency is shiro-quartz-1.0.0-incubating.jar. So, now inside it's pom.xml file I have seen following line code :
<dependency>
<groupId>quartz</groupId>
<artifactId>quartz</artifactId>
</dependency>
As per our line in pom.xml, there is no tag of version with quartz dependency, that means whenever shiro getting installed in my project, simultaneously it's extracting latest library of quartz i.e. 1.8.3 with maven.
And inside that quartz 1.8.3 the method updateSchedulerState of class CustomJDBCDelegate has been changed from version quarts 1.7.3.
So now problem is I cannot change quartz-all-1.7.3 in my existing project, and wanted to use Shiro plugin too in my project.
So there should be some resolution so that shiro should get quartz-1.7.3 version rather than the latest one using maven.
Any help would be highly appreciated...
Thanks...
Maybe I'm getting this wrong, do you mean something like this?:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>1.0.0-incubating</version>
<exclusions>
<exclusion>
<groupId>quartz</groupId>
<artifactId>quartz</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>1.7.3</version>
</dependency>
then $ mvn dependency:tree
[...]
[INFO] +- org.apache.shiro:shiro-quartz:jar:1.0.0-incubating:compile
[INFO] | \- org.apache.shiro:shiro-core:jar:1.0.0-incubating:compile
[INFO] | +- org.slf4j:slf4j-api:jar:1.5.6:compile
[INFO] | \- commons-beanutils:commons-beanutils:jar:1.7.0:compile
[INFO] \- org.quartz-scheduler:quartz:jar:1.7.3:compile
[INFO] \- commons-logging:commons-logging:jar:1.1:compile
[INFO] +- log4j:log4j:jar:1.2.12:compile
[INFO] +- logkit:logkit:jar:1.0.1:compile
[INFO] \- avalon-framework:avalon-framework:jar:4.1.3:compile

Resources