Issue
When using Spring Boot Lookup for Log4j2, java.lang.IllegalStateException: Unable to obtain Spring Environment from LoggerContext get thrown a few times per property per unit test. This is the case not only for tests as well as the web-app.
As I'm using Maven to build the web-app, each maven build contains multiple stacktraces for tests until org.springframework.boot.logging.log4j2.SpringEnvironmentLookup#environment is initialised. Hence, this exception pollutes the app/build logs.
Suggestion
The assertion in SpringEnvironmentLookup#lookup should ideally be a warning log.
Usage
pom.xml
<properties>
<java.version>21</java.version>
<kotlin.version>2.0.0</kotlin.version> <!-- My app is in Kotlin but the issue is present for java too -->
<kotlin.compiler.jvmTarget>${java.version}</kotlin.compiler.jvmTarget>
</properties>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.6</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>3.2.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.2.6</version>
<scope>test</scope>
</dependency>
<!-- Log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api-kotlin</artifactId>
<version>1.4.0</version>
</dependency>
<!-- Even added this as per the suggestion on https://logging.apache.org/log4j/2.x/manual/lookups.html#spring-boot-lookup -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-spring-cloud-config-client</artifactId>
<version>2.23.1</version>
<scope>runtime</scope>
</dependency>
log4j2.yml
---
Configuration:
monitorInterval: 60
Properties:
Property:
- name: appName
value: "$${spring:spring.application.name:-}" # From application.yml
- name: myProp
value: "$${spring:application.my.property:-}" # From application.yml
Appenders:
Console:
name: CONSOLE
target: SYSTEM_OUT
PatternLayout:
pattern: "[app=${appName}][myProp=${myProp}] %d{ISO8601} [%-5p] [%t] [%c]%notEmpty{[%marker]} - %m%n"
Loggers:
Logger:
- name: org.springframework
level: INFO
additivity: false
AppenderRef:
ref: CONSOLE
Root:
level: INFO
AppenderRef:
ref: CONSOLE
Exception
2024-09-17T10:29:21.475587700Z main ERROR Resolver failed to lookup spring:spring.application.name java.lang.IllegalStateException: Unable to obtain Spring Environment from LoggerContext
at org.springframework.util.Assert.state(Assert.java:76)
at org.springframework.boot.logging.log4j2.SpringEnvironmentLookup.lookup(SpringEnvironmentLookup.java:46)
at org.apache.logging.log4j.core.lookup.StrLookup.evaluate(StrLookup.java:108)
at org.apache.logging.log4j.core.lookup.Interpolator.evaluate(Interpolator.java:197)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.resolveVariable(StrSubstitutor.java:1227)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.substitute(StrSubstitutor.java:1138)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.substitute(StrSubstitutor.java:1149)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.substitute(StrSubstitutor.java:999)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.replace(StrSubstitutor.java:513)
at org.apache.logging.log4j.core.config.plugins.visitors.PluginBuilderAttributeVisitor.visit(PluginBuilderAttributeVisitor.java:46)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.injectFields(PluginBuilder.java:195)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:123)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1164)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1085)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1077)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1077)
at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:681)
at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:264)
at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:313)
at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:631)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:713)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:735)
at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:260)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:154)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:46)
at org.apache.logging.log4j.LogManager.getContext(LogManager.java:197)
at org.apache.commons.logging.LogAdapter$Log4jLog.<clinit>(LogAdapter.java:146)
at org.apache.commons.logging.LogAdapter$Log4jAdapter.createLog(LogAdapter.java:113)
at org.apache.commons.logging.LogAdapter.createLog(LogAdapter.java:95)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:67)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:59)
at org.springframework.test.context.TestContextManager.<clinit>(TestContextManager.java:93)
2024-09-17T10:29:21.480587600Z main ERROR Resolver failed to lookup spring:application.my.property java.lang.IllegalStateException: Unable to obtain Spring Environment from LoggerContext
at org.springframework.util.Assert.state(Assert.java:76)
at org.springframework.boot.logging.log4j2.SpringEnvironmentLookup.lookup(SpringEnvironmentLookup.java:46)
at org.apache.logging.log4j.core.lookup.StrLookup.evaluate(StrLookup.java:108)
at org.apache.logging.log4j.core.lookup.Interpolator.evaluate(Interpolator.java:197)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.resolveVariable(StrSubstitutor.java:1227)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.substitute(StrSubstitutor.java:1138)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.substitute(StrSubstitutor.java:1149)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.substitute(StrSubstitutor.java:999)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.replace(StrSubstitutor.java:513)
at org.apache.logging.log4j.core.config.plugins.visitors.PluginBuilderAttributeVisitor.visit(PluginBuilderAttributeVisitor.java:46)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.injectFields(PluginBuilder.java:195)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:123)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1164)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1085)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1077)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1077)
at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:681)
at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:264)
at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:313)
at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:631)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:713)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:735)
at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:260)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:154)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:46)
at org.apache.logging.log4j.LogManager.getContext(LogManager.java:197)
at org.apache.commons.logging.LogAdapter$Log4jLog.<clinit>(LogAdapter.java:146)
at org.apache.commons.logging.LogAdapter$Log4jAdapter.createLog(LogAdapter.java:113)
at org.apache.commons.logging.LogAdapter.createLog(LogAdapter.java:95)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:67)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:59)
at org.springframework.test.context.TestContextManager.<clinit>(TestContextManager.java:93)
Comment From: wilkinsona
As noted in the documentation, Spring Boot's Log4j extensions should only be used in a log4j2-spring.xml file. Doing so prevents Log4j from trying to access the Spring environment before it's available.
Can you please try renaming log4j2.xml to log4j2-spring.xml?
Comment From: RGB314
I'm using YML and it worked after adding logging.config: classpath:log4j2-spring.yml in application.yml. Thanks!
Comment From: wilkinsona
Thanks for letting us know.