With thanks to @rwinch, I've just learned that Boot doesn't work with Logback 1.3 (still in alpha). It fails on launch with the following exception:

java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder
    at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLoggerContext(LogbackLoggingSystem.java:273)
    at org.springframework.boot.logging.logback.LogbackLoggingSystem.beforeInitialize(LogbackLoggingSystem.java:99)
    at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationStartingEvent(LoggingApplicationListener.java:191)
    at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:170)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
    at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:68)
    at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:48)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:313)

StaticLoggerBinder was removed in this commit which appears to be part of a broader effort to provide Jigsaw modules for SLF4J and Logback.

Comment From: philwebb

Logback 1.3 is still in alpha so I think we should push this back to Spring Boot 2.2

Comment From: aprantl

Apparently the extension module of SLF4J prior to 1.8.0-beta2 contains a security vulnerability (see https://nvd.nist.gov/vuln/detail/CVE-2018-8088#VulnChangeHistorySection). As such, I wouldn't consider this ticket just an enhancement anymore. What do you think?

Comment From: snicoll

@aprantl slf4j-ext and slf4j-api are separate modules and Spring Boot itself does not depend on the module that holds the vulnerability. An application that only depends on slf4j-api is not at risk.

Comment From: aprantl

@snicoll Thanks for the quick reply. What would you recommend if an application based on Spring Boot relies on the extension module in its custom code? I guess the ext-module cannot be updated to 1.8.0-beta2 without dependency-managing the entire SLF4J and logback framework. Which again would not be possible considering the issue above.

Comment From: wilkinsona

If you're not using EventData then my understanding is that you're not vulnerable even if you have slf4j-ext on the classpath. You should confirm that with the SLF4J team though.

Comment From: jhigueras

It would be great if you can solve this issue. We use dependency-check in our security pipelines and today all of them stopped due to this high severity vulnerability.

Thanks!

Comment From: snicoll

@jhigueras as we've already mentioned, this is a false positive in the security check unless you happen to use slf4j-ext directly.

Comment From: wilkinsona

@jhigueras There’s nothing for us to solve at this time.

If you are only using slf4j-api you are not at risk. If your dependency check is still reporting an issue then it’s there that a possible solution lies as it should not be doing so.

If you are using slf4j-ext then that is out of our control but you still have a few options. You may want to check that you are not using EventData and verify that you are therefore not at risk, explore removing the dependency from your application, or upgrade to an SLF4J 1.8 beta. We cannot do the upgrade at this time as we do not want to force everyone to use a beta version of a dependency.

Comment From: jhigueras

Thanks, we will add the exception to the false-positives list so.

Comment From: cowwoc

We're making a final push for Java 9+ support and this issue is blocking us. Are there any workarounds until this is fixed?

Baring that, is this feature scheduled?

Comment From: wilkinsona

We cannot schedule this feature as SLF4J 1.8 and Logback 1.3 have not yet been released.

You have a couple options:

  1. Do not use the module path. It provides minimal, if any, benefits to a typical Spring Boot application. You are probably better off avoiding it until the broader ecosystem has caught up.
  2. Try using Log4j2 instead of Logback.

Comment From: cowwoc

Sadly, part of the reason that "the broader ecosystem has [not] caught up" is that frameworks like spring boot have not expended the necessary effort to add support themselves. Everyone is waiting for everyone else to move forward.

I've personally contributed a lot of my time getting the Maven ecosystem up-to-speed and now it finally seems that Java Modules are well supported there. But the rest of the ecosystem needs to do the same.

As an aside, I've been using slf4j 1.8 and logback 1.3 for month now without any problems so I urge you to add support without waiting for a final release. As far as I can tell, the releases are solid.

Comment From: wilkinsona

I suggested above that you consider using Log4j2 but you chose to ignore that constructive suggestion and called into question our efforts instead. We have expended a considerable amount of effort supporting Java 9, 10, 11 and, most recently 12. We have also fixed issues caused by the module path. Unfortunately we can only do so much and cannot justify spending time and introducing complexity to support something that is still in alpha.

If you cannot or do not want to try Log4j2, you also have the option of disabling Boot’s logging system and using Logback 1.3 alphas.

Comment From: cowwoc

Unfortunately we can only do so much and cannot justify spending time and introducing complexity to support something that is still in alpha.

Understood.

If you cannot or do not want to try Log4j2, you also have the option of disabling Boot’s logging system and using Logback 1.3 alphas.

Interesting. Can you please clarify how this would work? If I disable Boot's logging system, where will the logs go? Certainly I can use Logback for my own code but is there a way to direct Boot's logging to use Logback?

Alternatively, I'm thinking I should keep Boot's logging enabled, force it to use JUL and use jul-to-slf4j to redirect to logback. What do you think?

Comment From: philwebb

@cowwoc If you set a system property with org.springframework.boot.logging.LoggingSystem=NONE then Spring Boot's deeper logging integration will be disabled. This means you won't be able to do things like set logging levels in application.properties.

Setting that property will not disable the actual logging that spring boot does itself. Those are performed via Apache Commons Logging (usually Spring's own fork) and will ultimately end up being routed to Log4J, SLF4J, or JUL depending on what's on the classpath. You'll need to actually configure your logging system yourself (for example with logback.xml) and define the loggers you want. If you want to replicate the config we provide out the box, take a look at the XML here.

Comment From: cowwoc

@philwebb It would work. Is there any harm in forcing JUL support and redirecting that to slf4j? Isn't that better since then application.properties integration would still work?

Comment From: philwebb

@cowwoc That's certainly an option, but I'm not sure how well it work as I've never tested that scenario. Specifically, I'm not sure if calling Logger.getLogger(loggerName).setLevel(...) will propagate to the underlying Logback logger.

Comment From: hohwille

I am facing the same problem in my OSS project that I migrated to JPMS entirely. The problem ist that there seems no way to make it work with spring-boot currently. I can not even disable LogbackLoggingSystem and make spring-boot log to jul instead. It seems to be hardwired inside spring-boot that if logback is found on the classpath that StaticLoggerBinder is loaded what has been removed from logback. I can imagine that it is really tricky to support all this messy variants with Junit4 vs. 5, classpath vs. modulepath, etc. Some OSS projects IMHO seem to tend making breaking changes without considering impact vs. benefit (e.g. junit, spring-data, etc.).

Comment From: snicoll

I can not even disable LogbackLoggingSystem

Disabling or changing the LoggingSystem that Spring Boot uses is possible and documented in the reference guide.

Comment From: hohwille

Disabling or changing the LoggingSystem that Spring Boot uses is possible and documented in the reference guide.

Thanks for the hint. Indeed it works when I launch my test with

-Dorg.springframework.boot.logging.LoggingSystem=none

and I still get the log output.

However, I need the test to be portable, run by anybody in maven, any IDE, etc. I tried this:

@SpringBootTest(classes = TestApp.class, properties = "org.springframework.boot.logging.LoggingSystem=none", webEnvironment = WebEnvironment.RANDOM_PORT)

But it has to be set as a system property in the boostrapping.

Comment From: wilkinsona

If you know that users of your project will never want to use Spring Boot's logging system, you can use an ApplicationListener, registered in spring.factories and with higher precedence than org.springframework.boot.context.logging.LoggingApplicationListener, to set the system property in response to an ApplicationStartingEvent.

Comment From: skjolber

As a side note: The SLF4J 1.8 beta seems to work with Logback 1.2.3, if you return StaticLoggerBinder.getSingleton().getLoggerFactory() in your custom SLF4JServiceProvider getLoggerFactory(..) method.

Comment From: wilkinsona

This has become more important for Spring Boot 3.0 and applications using an SMTP appender. In Logback 1.2, the SMTP appender uses javax.mail classes from Java EE 8. The Logback 1.3 alphas have moved to the jakarta.mail classes that are compatible with Jakarta EE 9.

Comment From: wilkinsona

Logback 1.3 has removed InPlayListener which is used by our SpringProfileAction.

Comment From: candrews

This has become more important for Spring Boot 3.0

Another example is ch.qos.logback.classic.helpers.MDCInsertingServletFilter. In logback version 1.2.10, included in Spring Boot 3.0.0-M1, that class references javax.servlet.Filter which isn't available.

Comment From: wilkinsona

Thanks, @candrews.

Logback moved to jakarta.servlet in 1.3.0-alpha11.

Comment From: wilkinsona

@ceki We have an InPlayListener implementation in Spring Boot. If you have the time, could you please advise on how we would implement it on top of Logback 1.3?

Comment From: ceki

@wilkinsona Logback 1.3 aims for 1) less confusing configuration code 2) allow for other ways to process configuration. Consequently, the XML processing now creates a model of the configuration which is XML agnostic. Once created, the model is processed to configure logback.

Having said this, logback 1.3 does not currently support conditionals. For example. IfAction/ThenAction/ElseAction no longer exist. SpringProfileAction is rather similar to IfAction/ThenAction.

To cut a long story short, logback 1.3 needs to add support for conditional processing. I have created https://jira.qos.ch/browse/LOGBACK-1625 for this.

Comment From: wilkinsona

Thanks, @ceki. I'll keep an eye on that issue. I'd be happy to try to reimplement our SpringProfileAction based on a snapshot when the time comes.

Comment From: ruslangm

Hey, sorry to bother you but 1.3.0-alpha version of logback is getting more and more new feature and we are a bit in trouble right now because of the following issue: https://jira.qos.ch/browse/LOGBACK-1421 We really want this performance improvement in production because it greatly affects our performance right now (confirmed by thread dumps) but just can't do it because we're kinda heavily dependent on spring-logback things and just cannot simply add new property to the JAVA_OPTS and get rid of all the features that spring provides for logging. Otherwise it would be cool for us if logback-team (@ceki) will be able to copy some important features implementation (related to security / performance) to 1.2.X branch as well till the moment it'll be possible to simply update spring boot version. Thanks.

Comment From: snicoll

@ruslangm there's nothing we can do here about this.

Comment From: ceki

I am happy to report that if/then/else support has been restored on the main logback branch (1.3). The changes are mentioned in LOGBACK-1625.

While there are many internal changes in 1.3, they are transparent for "regular" users who usually do not extend Joran.

In your case, there is some work to do.

In order to support logback 1.3, you would need to split SpringProfileAction into three parts, a SpringProfileAction , a SpringProfileModel and a SpringProfileModelHandler.

In SpringBootJoranConfigurator you would need to specify that "springProfile" is a transparent ElementPart so that it does not interfere with elements within <springProfile> during XML to Model transformation.

To enable processing of embedded models within <springProfile> is very easy. If the profile is inactive, then SpringProfileModelHandler will invoke markAsSkipped() on the relevant SpringProfileModel instance. If the profile is active, the embedded sub-models will be processed as usual.

Comment From: wilkinsona

Thanks very much, @ceki. Are Logback 1.3 snapshots published to a Maven repository? I tried https://oss.sonatype.org/content/repositories/snapshots/ch/qos/logback/ but didn't see them there.

Comment From: ceki

@wilkinsona We don't publish snapshots for logback as the need never seemed arise previously. Anyway, this may be a good a time to cut a release and the question will become moot.

update: Release 1.3.0-alpha15 is available on Maven central.

Comment From: wilkinsona

Thanks, @ceki. We'll give alpha 15 a try.

Comment From: ceki

In alpha16-SNAPHOT, some Joran methods were renamed to make their intention clearer.

More importantly, the phase filter configuration step has been greatly simplified. In 16-SNAPSHOT, only ModelHandler instances that need to be differed to the second stage need to use PhaseIndicator annotation (new in 16). The vast majority (95%) of ModelHandler classes do not have to do anything. In version 15, you needed to add them to the DefaultProcessor firstPhaseFilter. (I forgot to mention this step in my earlier comment.)

If you can manage to have things work in 15, adapting to 16 should be very easy.

Let me know if you get stuck.

Comment From: wilkinsona

Thanks again, @ceki.

I think I'm getting close using alpha-15 with the changes in this branch. Our Logback-related tests, including SpringBootJoranConfiguratorTests, are passing at least.

I didn't do anything with firstPhaseFilter so I may have missed something. I also wasn't sure about the serialisation requirements, need for getters and setters, etc on the model classes. Is there something I can look at to learn more, or a particular kind of test that we should add to exercise these areas?

Comment From: ceki

The fact that SpringBootJoranConfiguratorTests are passing is good news.

This can be explained by the fact that in the second and last phase of processing there exists a "catch all" fallback which will handle all models which were not previously handled. This includes SpringProfileModel and sub-models of SpringProfileModel, i.e models contained within SpringProfileModel.

In version 16, SpringProfileModel will be processed in the first phase. This should be transparent with the aforementioned tests passing as is.

Otherwise, the code looks really good. The only change I would suggest would be to validate inputs by overriding the validPreconditions() method in your Action classes.

Comment From: candrews

Since it's been a while and we're getting close to that Spring Boot 3.0 release... what's the latest news on this issue?

Comment From: wilkinsona

There's nothing to share beyond what you can read above. Logback 1.3 and SLF4J 2.0 are still in alpha so we have no firm plans to support them at this time.

Comment From: candrews

Logback 1.3 and SLF4J 2.0 are still in alpha so we have no firm plans to support them at this time.

Don't you have to support them for Spring Boot 3.0 due to the jakarta namespace change?

Comment From: wilkinsona

We don't think so, no. We can't force everyone to use an alpha and supporting Logback 1.2 and 1.3 in parallel isn't an attractive option in terms of the additional complexity and maintenance overhead. Given a choice of depending on an alpha versus losing some non-standard functionality (not being able to use an SMTP appender or the MDC filter, for example), we'd choose to lose some functionality. Users who need things like an SMTP appender can switch to Log4j2 which is Jakarta EE 9 compatible in its recent stable releases.

Comment From: lynch19

@wilkinsona slf4j 2 isn't alpha. Two beta versions have already been released, and the work on the snapshot version has been started.

Comment From: vpavic

Note that those beta releases happened about a week or so ago (meaning, around the same time @wilkinsona posted his comment), and they don't really change any of the things Andy explained as they're still not GA releases.

I looked around the QOS Jira and GitHub org the other day and wasn't able to find any roadmaps so it's probably the best if @ceki could clarify whether there are some plans when Logback 1.3 could hit GA.

Comment From: ceki

@vpavic Yes, the beta releases are indeed quite recent. Both SLF4J 2.0.0-GA and logback 1.3.0-GA are planned for before the end of this month. As of a few days ago, the download pages for both SLF4J and logback also mention the most recent beta versions as stable.

Comment From: tokuhirom

Note: slf4j 2.0.0 was released today. https://www.slf4j.org/news.html?s=31

Maybe there will be a dependency hell like this:

flowchart LR
    project --> boot2
    boot2 --> slf4j1
    project --> library
    library --> slf4j2

Then, the user potentially get an error message like this:

    SLF4J: No SLF4J providers were found.
    SLF4J: Defaulting to no-operation (NOP) logger implementation
    SLF4J: See http://www.slf4j.org/codes.html#noProviders for further details.
    SLF4J: Class path contains SLF4J bindings targeting slf4j-api versions prior to 1.8.
    SLF4J: Ignoring binding found at [jar:file:/Users/tokuhirom/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.2.11/4741689214e9d1e8408b206506cbe76d1c6a7d60/logback-classic-1.2.11.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#ignoredBindings for an explanation.

Comment From: ceki

You can freely mix libraries compiled against any version of SLF4J API. The only restriction is that if one of the libraries you depend on uses the optional fluent API (new in SLF4J 2.0). In that case, your project will also need to use SLF4J API version 2.0.x instead of 1.7.x.

As for the error message(s) you mention, the issue stems from changes in the way SLF4J API links with or finds the logging back-end. Placing any provider shipping with SLF4J 2.0 such as {slf4j-reload4j-2.0.0, slf4j-jdk14-2.0.0, slf4j-simple-2.0.0 } or logback-1.3.0 on your classpath will solve the matter for good.

See also the FAQ entry What has changed in SLF4J version 2.0.0?

Comment From: code-magician323

@ceki @wilkinsona the status of this issue is unclear. Is it currently possible for one to use the new fluent API with Spring Boot 2.7.3 & SLF4J 2.0.0?

Comment From: candrews

Since logback 1.4.0 has been released, can Spring Boot 3.0 now be updated to use logback 1.4.0 and slf4j 2.0.0?

It appears that the work has been done in https://github.com/wilkinsona/spring-boot/tree/gh-12649

Thank you everyone, I'm really looking forward to Spring Boot 3.0 :smile:

Comment From: mrmeyers99

Logback 1.4.0 requires Java 11, whereas Logback 1.3.0 still supports JDK 8. Will spring boot 2.x be upgraded to 1.3.0?

Comment From: bclozel

@mrmeyers99 no it shouldn't, as upgrading a minor version in a maintenance release is against our policy.

Comment From: mrmeyers99

Does that mean since slf4j is a major version upgrade that spring boot will only upgrade to that version with a major upgrade? Or that you are no longer making any minor/major dependency upgrades to 2.x?

Comment From: philwebb

@mrmeyers99 We're not currently planning to release any more versions from the 2.x line. Having said that, plans could change if we deem it necessary.

Comment From: mrmeyers99

The reason I'd like this upgrade is that there is a performance change in logback 1.3.0 that I'd like to be able to use, but we're not quite ready to upgrade JDK version. The change was to use java.time.format.DateTimeFormatter which is thread safe instead of SimpleDateFormat, which was not. I guess there's a chance they could backport that fix to 1.2.x though.

Comment From: wilkinsona

After a few further updates, things seem to work nicely with Logback 1.4 and SLF4J 2.0 but we hit some problems with Log4j 2.18 (using log4j2-slf4j18-impl) and SLFJ 2.0. Specifically, the following is logged to standard error:

Unexpected problem occured during version sanity check
Reported exception:
java.lang.AbstractMethodError: Receiver class org.apache.logging.slf4j.SLF4JServiceProvider does not define or inherit an implementation of the resolved method 'abstract java.lang.String getRequestedApiVersion()' of interface org.slf4j.spi.SLF4JServiceProvider.
    at org.slf4j.LoggerFactory.versionSanityCheck(LoggerFactory.java:297)
    at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:141)
    at org.slf4j.LoggerFactory.getProvider(LoggerFactory.java:421)
    at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:407)
    at io.micrometer.common.util.internal.logging.Slf4JLoggerFactory.<init>(Slf4JLoggerFactory.java:49)
    at io.micrometer.common.util.internal.logging.Slf4JLoggerFactory.<clinit>(Slf4JLoggerFactory.java:46)
    at io.micrometer.common.util.internal.logging.InternalLoggerFactory.newDefaultFactory(InternalLoggerFactory.java:58)
    at io.micrometer.common.util.internal.logging.InternalLoggerFactory.getDefaultFactory(InternalLoggerFactory.java:74)
    at io.micrometer.common.util.internal.logging.InternalLoggerFactory.getInstance(InternalLoggerFactory.java:103)
    at io.micrometer.common.util.internal.logging.InternalLoggerFactory.getInstance(InternalLoggerFactory.java:94)
    at io.micrometer.core.instrument.binder.jvm.JvmGcMetrics.<clinit>(JvmGcMetrics.java:63)
    at org.springframework.boot.actuate.autoconfigure.metrics.JvmMetricsAutoConfiguration.jvmGcMetrics(JvmMetricsAutoConfiguration.java:50)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:130)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:629)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:469)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1324)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1161)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1598)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1555)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1401)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1333)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.resolveStream(DefaultListableBeanFactory.java:2101)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.orderedStream(DefaultListableBeanFactory.java:2095)
    at org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryConfigurer.addBinders(MeterRegistryConfigurer.java:86)
    at org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryConfigurer.configure(MeterRegistryConfigurer.java:68)
    at org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryPostProcessor.postProcessAfterInitialization(MeterRegistryPostProcessor.java:64)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:435)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1757)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1375)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1295)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:861)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:765)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:524)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1324)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1161)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205)
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:210)
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:201)
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:96)
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:85)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:261)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:235)
    at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:52)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5168)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1396)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1386)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:919)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:886)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1396)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1386)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:919)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:263)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:432)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.startup.Tomcat.start(Tomcat.java:486)
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:123)
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:104)
    at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:486)
    at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:210)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:183)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:161)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:430)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292)
    at smoketest.actuator.log4j2.SampleActuatorLog4J2Application.main(SampleActuatorLog4J2Application.java:26)

@ceki, could a change be made to org.slf4j.LoggerFactory.versionSanityCheck() so that it ignores an AbstractMethodError in the same way that NoSuchFieldError is ignored at the moment?

Two alternatives to that are for Log4j2 users to downgrade back to SLF4J 1.x or for Log4j2 to introduce a log4j2-slf4j20-impl. I'd prefer to avoid the first as it's inconveniencing users who choose to use Log4j2 for no benefit to them. The second was proposed in https://issues.apache.org/jira/browse/LOG4J2-2942 but was closed as, at that time, things seemed to work fine with log4j2-slf4j18-impl (/cc @rgoers).

Comment From: rgoers

@wilkinsona I would recommend against hiding that error. It indicates the implementation being used isn't fully compatible with the API. Due to a GA version of SLF4J being released less than two weeks ago It should be understandable that no releases of Log4j 2 support it yet. That said, support for it has already been added to the Log4j code base and will be included in the next release. In addition, since there never was a GA release of SLF4J 1.8 we will be dropping the log4j-slf4j18-impl. See https://github.com/apache/logging-log4j2/pull/1023 and https://issues.apache.org/jira/browse/LOG4J2-3370.

Comment From: wilkinsona

Thanks, @rgoers.

Due to a GA version of SLF4J being released less than two weeks ago It should be understandable that no releases of Log4j 2 support it yet.

Absolutely. Sorry if I unintentionally implied otherwise.

That said, support for it has already been added to the Log4j code base and will be included in the next release

That's great news. Thank you. Does the Log4j2 team have a date in mind at this stage for the 2.19 release? It would be useful for our planning to know if it'll be available before Spring Boot 3.0 reaches RC in October.

Comment From: rgoers

Historically, I have performed almost all of the releases so generally it fits around my schedule. There is a decent chance I might start work on it this weekend. For me, the release process can take up to a week as I usually take a few days to look for easy or critical fixes before starting, and then ASF release votes usually are open for 72 hours. So it should be available.

Comment From: ceki

@wilkinsona If really necessary java.lang.AbstractMethodError can be caught within org.slf4j.LoggerFactory.versionSanityCheck(). However, given the comments above that does not seem to be the case for the moment. How about giving it 10 days or so and revisit the issue?

Comment From: r6q

@ceki @wilkinsona the status of this issue is unclear. Is it currently possible for one to use the new fluent API with Spring Boot 2.7.3 & SLF4J 2.0.0?

No, at the moment it's not really possible (maybe only with some serious hacks) to have Spring Boot 2.7.3 + slf4j 2.0.0, as slf4j needs SLF4JServiceProvider implementation, but logback-classic 1.2.11 does not provide an implementation for it. However updating logback to version 1.3 or 1.4 (which is requirement for slf4j 2) to include the mentioned service provider, no longer has org.slf4j.impl.StaticLoggerBinder which is required by spring boot logging configuration.

Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder
    at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLoggerContext(LogbackLoggingSystem.java:293)
    at org.springframework.boot.logging.logback.LogbackLoggingSystem.beforeInitialize(LogbackLoggingSystem.java:118)

Comment From: rgoers

Note that the release vote for Log4J 2.19.0, which supports SLF4J 2.0, is in progress so it will be able to be used as well.

Comment From: candrews

Spring Boot 3.0.0-M5 is due on September 22: https://github.com/spring-projects/spring-boot/milestone/245

Will Log4J 2.19.0 be released by then?

Could Spring Boot 3.0.0-M5 include slf4j2 2.0.0 + Log4J 2.19.0 + Logback 1.4.0 for a fully working logging configuration?

Comment From: wilkinsona

I doubt that we'll upgrade in Spring Boot 3.0.0-M5 as, even if the Log4j2 release is available in time, Spring Framework 6.0.0-M6 is going to be released tomorrow using SLF4J 1.7. RC1 of Spring Boot 3 and Framework 6 is a more realistic target now.

Comment From: rgoers

@wilkinsona Log4j 2.19.0 has been released. In addition, I have created https://github.com/spring-projects/spring-boot/pull/32425 to move the Log4j 2 Spring Boot support into Spring Boot itself.

Comment From: cmuchinsky

@ceki @wilkinsona the status of this issue is unclear. Is it currently possible for one to use the new fluent API with Spring Boot 2.7.3 & SLF4J 2.0.0?

No, at the moment it's not really possible (maybe only with some serious hacks) to have Spring Boot 2.7.3 + slf4j 2.0.0, as slf4j needs SLF4JServiceProvider implementation, but logback-classic 1.2.11 does not provide an implementation for it. However updating logback to version 1.3 or 1.4 (which is requirement for slf4j 2) to include the mentioned service provider, no longer has org.slf4j.impl.StaticLoggerBinder which is required by spring boot logging configuration.

Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLoggerContext(LogbackLoggingSystem.java:293) at org.springframework.boot.logging.logback.LogbackLoggingSystem.beforeInitialize(LogbackLoggingSystem.java:118)

For spring-boot 2.7, would it be possible to update LogbackLoggingSystem to detect logback 1.3 vs 1.2 (perhaps via reflection) and have it work with both versions? Unless I'm mistaken, the only thing blocking spring-boot 2.7 users from upgrading to logback 1.3 / log4j 2.19 / slf4j 2.0 is the logback initialization logic in that class.

Comment From: wilkinsona

I think that's quite unlikely. The changes required to support Logback 1.4 are too broad to allow us to support 1.2 and 1.3/1.4 in parallel via reflection.

Comment From: code-magician323

@wilkinsona Will this get merged until Spring Boot 3.0.0?

Comment From: wilkinsona

@code-magician323 As I said above, the current target is 3.0.0-RC1.

Comment From: zyxist

It's possible to make Spring Boot 2.x work with Slf4j 2.0 simply by disabling the custom logging facade used by Spring Boot. To do so, one needs to set org.springframework.boot.logging.LoggingSystem system property to none (and also making sure that all dependencies to logback/slf4j on classpath have been updated in Maven/Gradle). I managed to run my project in this way.

As I looked at the code, it should be possible to write a custom LoggingSystemFactory for Spring Boot that delegates stuff to Slf4j, rather than talking to Logback directly. The public API of Slf4j 2.0.x is backward compatible with 1.x. In fact, I wished if things were done in this way from the beginning.

Comment From: prbbj

set org.springframework.boot.logging.LoggingSystem system property to none

How to do this in Intellij?

Comment From: h2nguyen

set org.springframework.boot.logging.LoggingSystem system property to none How to do this in Intellij?

this can be done within the pom.xml file, just look for the maven-surefire-plugin e.g.:

...
<plugins>
   ...
   <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
                <configuration>
                    ...
                    <systemPropertyVariables>
                        <org.springframework.boot.logging.LoggingSystem>none</org.springframework.boot.logging.LoggingSystem>
                    </systemPropertyVariables>
                    ...
                </configuration>
            </plugin>
   ...
</plugins>
...

Comment From: zhaolj214

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.5</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>${logback.version}</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.3.7</version>
</dependency>

after reading the source code, add the following code to the startup class, then launch without exception.

@SpringBootApplication
public class Spring5Application {
    public static void main(String[] args) {
        System.setProperty("org.springframework.boot.logging.LoggingSystem", "none");
        SpringApplication.run(Spring5Application.class, args);
    }
}

Comment From: adamk33n3r

after reading the source code, add the following code to the startup class, then launch without exception.

@SpringBootApplication public class Spring5Application { public static void main(String[] args) { System.setProperty("org.springframework.boot.logging.LoggingSystem", "none"); SpringApplication.run(Spring5Application.class, args); } }

this does let me boot, but wow the output log is insanely verbose now. and colorless.

Comment From: wilkinsona

That's Logback's default configuration. You can customize it, perhaps using Boot's configuration as a starting point. Note that the file must be logback.xml and not logback-spring.xml when you've set the logging system to none.