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鈥檚 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鈥檚 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:
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鈥檚 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鈥檚 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.
Most helpful comment
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?