If I update my project from Log4J 2.24.1 to 2.25.0 (no other changes), I no longer get logging output.
Spring Boot 3.5.1, gradlew :subprojects:app:run
.
Diff: https://github.com/sdkotlin/sd-kotlin-spring-talks/commit/b15de4858a0c10ab9c267489b1b5a98cf1a9e10d.
Log4J 2.24.1 https://github.com/sdkotlin/sd-kotlin-spring-talks/tree/8d40d0c54e700adbc7c7609eb2b04a16223869ab
> Task :subprojects:app:run
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.5.1)
2025-06-19T10:14:37.901-07:00 INFO 65736 --- [ main] o.s.s.SpringBootAppKt : Starting SpringBootAppKt using Java 21.0.7 with PID 65736 (/Users/ianbrandt/Development/SDKotlin/sd-kotlin-spring-talks/subprojects/app/build/classes/kotlin/main started by ianbrandt in /Users/ianbrandt/Development/SDKotlin/sd-kotlin-spring-talks/subprojects/app)
2025-06-19T10:14:37.903-07:00 INFO 65736 --- [ main] o.s.s.SpringBootAppKt : No active profile set, falling back to 1 default profile: "default"
2025-06-19T10:14:38.107-07:00 INFO 65736 --- [ main] k.r.KClass : Config path: /Users/ianbrandt/Development/SDKotlin/sd-kotlin-spring-talks/subprojects/app/config
2025-06-19T10:14:38.107-07:00 INFO 65736 --- [atcher-worker-1] k.r.KClass : The current time is 2025-06-19T17:14:38.107189Z
2025-06-19T10:14:38.107-07:00 INFO 65736 --- [ main] k.r.KClass : Log path: /Users/ianbrandt/Development/SDKotlin/sd-kotlin-spring-talks/subprojects/app/logs
You've been scanned.
2025-06-19T10:14:38.128-07:00 INFO 65736 --- [ main] o.s.s.SpringBootAppKt : Started SpringBootAppKt in 0.395 seconds (process running for 0.625)
2025-06-19T10:14:38.129-07:00 INFO 65736 --- [ main] o.s.s.ResourcePrinter : classpath:/native-resource.txt content:
Testing native resources on MacOS.
2025-06-19T10:14:38.130-07:00 INFO 65736 --- [ main] o.s.s.ResourcePrinter : classpath:/custom-resource.txt content:
Testing custom resources.
BUILD SUCCESSFUL in 9s
Log4J 2.25.0 https://github.com/sdkotlin/sd-kotlin-spring-talks/tree/b15de4858a0c10ab9c267489b1b5a98cf1a9e10d
> Task :subprojects:app:run
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.5.1)
You've been scanned.
BUILD SUCCESSFUL in 1s
That one output "You've been scanned" line is a plain old println()
: https://github.com/sdkotlin/sd-kotlin-spring-talks/blob/b15de4858a0c10ab9c267489b1b5a98cf1a9e10d/subprojects/app/src/main/kotlin/org/sdkotlin/springdemo/SpringBootApp.kt#L45.
Comment From: wilkinsona
Thanks for the report. Given that the only change you've made is to the Log4j2 version, it would suggest that the cause lies in that project. As such, I'm curious why you've opened an issue here rather than there. If you've done some analysis that points to a problem caused by Spring Boot, please share it with us
Comment From: wilkinsona
https://github.com/apache/logging-log4j2/commit/b23e9a56a9cc9eed8c48241555256db8647e917a is a breaking change from Spring Boot's perspective. We call LoggerContext.start(Configuration)
on a LoggerContext
in STARTED
state. This used to result in setConfiguration(Configuration)
being called. Since these changes in Log4j2, that no longer happens so Boot's configuration isn't applied. Perhaps we can do something differently that will work with both 2.25.0 and earlier versions but I think this should be investigated by the Log4j2 team in the first instance. I'll close this one for now, we can re-open it if that investigation identifies a change that could be made in Boot to tolerate the change in Log4j2's behavior.
Comment From: ianbrandt
Thanks for the report. Given that the only change you've made is to the Log4j2 version, it would suggest that the cause lies in that project. As such, I'm curious why you've opened an issue here rather than there.
You know, that's a good question. I'll have to blame it on a moment of absent-mindedness. Sorry about that, and thanks for looking into this. I've filed https://github.com/apache/logging-log4j2/issues/3770.
Comment From: ppkarwasz
Hi @wilkinsona,
We call
LoggerContext.start(Configuration)
on aLoggerContext
inSTARTED
state. This used to result insetConfiguration(Configuration)
being called. Since these changes in Log4j2, that no longer happens so Boot's configuration isn't applied. Perhaps we can do something differently that will work with both 2.25.0 and earlier versions but I think this should be investigated by the Log4j2 team in the first instance.
Thank you for investigating and pinpointing the issue — we’ll restore backward compatibility in Log4j 2.25.1
.
That said, I believe the use of LoggerContext.start(Configuration)
in this scenario may not be the most appropriate approach. In practice, this call is never actually starting the context — the context has already been initialized by the commons-logging
bridge when Spring Boot starts logging. The intent here is to reconfigure an already started context, so I’d suggest replacing it with LoggerContext.reconfigure(Configuration)
.
While I realize this usage of start(Configuration)
dates back to Spring Boot 1.2.0 (and yes, we even copied it to our own Log4j2CloudConfigLoggingSystem
😈), the semantics of start
vs. reconfigure
align more closely with the distinction between Configurator.initialize()
and Configurator.reconfigure()
:
start(Configuration)
replaces the configuration only if the context hasn't already been startedreconfigure(Configuration)
always applies the new configuration
Note: There is one exception where using start
is appropriate: when a Spring Boot application is running inside an application server that shares a global LoggerContext
across multiple deployments. In that case, reconfiguring a shared context is risky — it can lead to classloader leaks, logging interference between applications, and other side effects (as seen in apache/logging-log4j2#1430).
Unfortunately, there’s currently no reliable API for detecting whether a LoggerContext
is shared or isolated per application. So in most cases, using reconfigure(Configuration)
is the safer and more semantically correct choice — especially for standalone Spring Boot apps.
Comment From: wilkinsona
Thank you, @ppkarwasz. Re-opening to consider switching from start
to reconfigure
in Boot 4.0 when Log4j2 2.25 (or later) will become our default version.
Comment From: ppkarwasz
Hi @wilkinsona,
Thank you!
Do you have an estimated timeline for Spring Boot 4.0? We’re currently working on several open issues and planned subprojects that could help improve and decentralize the implementation of LoggingSystem
. Here are a few areas where collaboration might be especially valuable:
-
Configuration File Locations
With the modularization of Log4j Core 3, the current logic in Spring Boot for detecting supported configuration formats won’t be compatible with the 3.x series. We’re exploring the possibility of moving the logic forAbstractLoggingSystem#getStandardConfigLocations
upstream (see apache/logging-log4j2#3775) to better support dynamic discovery. -
Forwarding JUL Log Events
Because thejava.util.logging.manager
system property must be set very early in the JVM lifecycle, Spring Boot currently usesjava.util.logging.Handler
s to forward JUL events to the active backend — which is less efficient. We're working on a universaljava.util.logging.LogManager
implementation (apache/logging-jdk#20) that could work with both Logback and Log4j Core. This may offer a more reliable and efficient bridging mechanism. -
Logging Configuration API
Users frequently want to programmatically adjust logging levels, but the ecosystem currently lacks a unified, backend-agnostic API for this. We're prototyping a small, standalone API to address this. One key challenge is defining an opt-in locking mechanism that prevents conflicts when multiple libraries (e.g., Spring Boot and another dependency) attempt to manipulate log configuration simultaneously (apache/logging-admin#1). Your input here would be particularly appreciated. -
Miscellaneous Improvements
I’ve proposed several enhancements to ourLog4j2SpringBootLoggingSystem
in this thread on thedev@logging.apache.org
mailing list. Some of them may be relevant or beneficial to Spring Boot’s ownLog4j2LoggingSystem
.
Unfortunately, we’re quite short-handed at the moment, so I’m not sure when we’ll be able to fully implement these improvements — most likely not before the end of the year. Still, we’d love to coordinate if any of these align with Spring Boot 4.0’s roadmap.
Comment From: wilkinsona
We'll release Boot 4.0 in November. RC1 (the last chance for significant changes/new features) is due in October. You can find the exact details on the milestone page.