spring-boot
spring-boot copied to clipboard
Upgrade to SLF4J 2.0 and Logback 1.4
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.
Logback 1.3 is still in alpha so I think we should push this back to Spring Boot 2.2
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?
@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.
@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.
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.
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!
@jhigueras as we've already mentioned, this is a false positive in the security check unless you happen to use slf4j-ext
directly.
@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.
Thanks, we will add the exception to the false-positives list so.
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?
We cannot schedule this feature as SLF4J 1.8 and Logback 1.3 have not yet been released.
You have a couple options:
- 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.
- Try using Log4j2 instead of Logback.
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.
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.
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?
@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.
@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?
@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.
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.).
I can not even disable LogbackLoggingSystem
Disabling or changing the LoggingSystem
that Spring Boot uses is possible and documented in the reference guide.
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.
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
.
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.
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.
Logback 1.3 has removed InPlayListener
which is used by our SpringProfileAction
.
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.
@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?
@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.
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.
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.