When upgrading to Spring Boot 3.4.2 our logging stopped completely working.
After narrowing down I figured the problem happens with Spring Boot 3.4.2 when using Log4j2 together with BlockHound.
Here is a minimum reproducer repo: https://github.com/micopiira/spring-boot-log4j2-issue
Spring Boot 3.4.1 with exact same Log4j2 version and BlockHound version works.
Spring Boot 3.4.1:
Spring Boot 3.4.2:
Comment From: wilkinsona
Thanks for the report and for the minimal sample. I assume that something has changed in Spring Boot 3.4.2 that is causing BlockHound to break Log4j2 in some way. Unfortunately, given that this works fine without BlockHound and the way in which BlockHound works, I don't think there's anything we can do about this in Spring Boot. Please raise a BlockHound issue so that they can investigate further.
Comment From: wilkinsona
Re-opening. Thanks to @violetagg's analysis, this has been tracked down to an assumption in StatusConsoleListener#closeNonSystemStream that is faulty when BlockHound is involved. It's only started causing a problem due to https://github.com/spring-projects/spring-boot/issues/43578.
Comment From: nosan
Thanks for the sample, @micopiira.
StandardOutputIntegration.applyTo(...) replaces the standard OUT and ERR streams with PrintStreamDelegate. During initialization, Log4J2LoggingSystem attempts to reset the StatusLogger.FallbackListener stream (which was previously replaced by BlockHound). This results in PrintStreamDelegate being closed, which in turn delegates the close call to the standard OUT and ERR streams.
One of the options is to revert https://github.com/spring-projects/spring-boot/commit/b6b9237f2c0f8b3767c04d017bfd0a5e5778d18d and fix SampleLog4j2StructuredLoggingApplicationTests.
https://github.com/spring-projects/spring-boot/compare/main...nosan:spring-boot:43963
Meanwhile, you can use this solution https://github.com/reactor/BlockHound/issues/469#issuecomment-2621801396
Comment From: violetagg
Thanks for the sample, @micopiira.
StandardOutputIntegration.applyTo(...)replaces the standard OUT and ERR streams withPrintStreamDelegate. During initialization,Log4J2LoggingSystemattempts to reset theStatusLogger.FallbackListenerstream (which was previously replaced by BlockHound). This results inPrintStreamDelegatebeing closed, which in turn delegates the close call to the standard OUT and ERR streams.
@nosan Please check the screenshot below -> it is not the delegator that closes but the real system stream
One of the options is to revert b6b9237 and fix
SampleLog4j2StructuredLoggingApplicationTests. main...nosan:spring-boot:43963Meanwhile, you can use this solution reactor/BlockHound#469 (comment)
Comment From: nosan
@violetagg
Oh, you're right, my mistake.
// stream = original System.out
// System.out = BlockHound.PrintStreamDelegate
private static void closeNonSystemStream(final OutputStream stream) {
// Close only non-system streams
if (stream != System.out && stream != System.err) {
try {
stream.close();
} catch (IOException error) {
// We are at the lowest level of the system.
// Hence, there is nothing better we can do but dumping the failure.
error.printStackTrace(System.err);
}
}
}
so Log42J closes the original stream.
Comment From: eichingertim
I noticed a similar problem in IntelliJ:
When I upgraded to 3.4.2 and executed a SpringBootTest with OutputCaptureExtension (Log Framework Log4J) the test is marked as "Not started" after some time and produces no log output. However when the tests are run via maven it works fine.
When I downgraded again to 3.4.1 the behavior is back to normal. Can anybody else validate this?
Comment From: nosan
@eichingertim
I've tried the following test with IntelliJ IDEA and 3.4.2:
@SpringBootTest
@ExtendWith(OutputCaptureExtension.class)
class SpringBootLog4j2DemoApplicationTests {
@Test
void contextLoads(CapturedOutput output) {
Assertions.assertThat(output).isNotEmpty();
}
}
And indeed it does not work for me as well.
This fix https://github.com/spring-projects/spring-boot/compare/main...nosan:spring-boot:gh-43963 resolves both issues.