Mukit09
Mukit09

Reputation: 3409

log4j2 spring boot lookup can't read property from application.properties

I want log4j2-spring.xml to read a property from the application.properties file. But seems log4j2-spring.xml is unable to read this. I have read https://logging.apache.org/log4j/2.x/manual/lookups.html#SpringLookup to implement this.

I have seen this answer on this site. Tried like this as well. But it didn't help me.

My build.gradle is like this:

plugins {
    id 'org.springframework.boot' version '2.5.0-SNAPSHOT'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
    maven { url 'https://repo.spring.io/milestone' }
    maven { url 'https://repo.spring.io/snapshot' }
}

ext {
    log4j2version = '2.14.1'
}

dependencies {

    compileOnly 'org.projectlombok:lombok:1.18.18'
    annotationProcessor 'org.projectlombok:lombok:1.18.18'

    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-log4j2'

    implementation "org.apache.logging.log4j:log4j-spring-cloud-config-client:${log4j2version}"
    implementation "org.apache.logging.log4j:log4j-api:${log4j2version}"
    implementation "org.apache.logging.log4j:log4j-core:${log4j2version}"
}

configurations {
    all {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
        exclude group: "ch.qos.logback", module: "logback-classic"
        exclude group: "org.springframework.cloud", module: "spring-cloud-bus"
    }
}

application.properties file is:

commission.base.path1=C:/Users/user1/Downloads/demo1
logging.config=classpath:log4j2-spring.xml

spring.cloud.config.enabled=false

log4j2-spring.xml is like this:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss:SSS} [%thread] %-5level %logger{2}:%L - %msg%n"/>
        </Console>

        <RollingFile name="CATALINA-FILE" fileName="$${spring:commission.base.path1}/logs/catalina.log"
                     filePattern="$${spring:commission.base.path1}/logs/archived/catalina_%d{yyyy-MM-dd}.log.gz">
            <PatternLayout>
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{20}:%L - %msg%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="1 GB" />
            </Policies>
        </RollingFile>
    </Appenders>

    <Loggers>
        <root level="debug">
            <appender-ref ref="CATALINA-FILE"/>
            <appender-ref ref="console"/>
        </root>
    </Loggers>
</configuration>

But everytime I run the code, I am getting this exception:

2021-05-21 21:28:38,409 main ERROR Unable to create file ${spring:commission.base.path1}/logs/catalina.log java.io.IOException: The filename, directory name, or volume label syntax is incorrect
    at java.io.WinNTFileSystem.canonicalize0(Native Method)
    at java.io.WinNTFileSystem.canonicalize(WinNTFileSystem.java:428)
    at java.io.File.getCanonicalPath(File.java:618)
    at java.io.File.getCanonicalFile(File.java:643)
    at org.apache.logging.log4j.core.util.FileUtils.makeParentDirs(FileUtils.java:135)
    at org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory.createManager(RollingFileManager.java:720)
    at org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory.createManager(RollingFileManager.java:704)
    at org.apache.logging.log4j.core.appender.AbstractManager.getManager(AbstractManager.java:113)
    at org.apache.logging.log4j.core.appender.OutputStreamManager.getManager(OutputStreamManager.java:100)
    at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.getFileManager(RollingFileManager.java:217)
    at org.apache.logging.log4j.core.appender.RollingFileAppender$Builder.build(RollingFileAppender.java:146)
    at org.apache.logging.log4j.core.appender.RollingFileAppender$Builder.build(RollingFileAppender.java:62)
    at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:122)
    at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1000)
    at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:940)
    at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:932)
    at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:551)
    at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:241)
    at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:287)
    at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:627)
    at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:304)
    at org.apache.logging.log4j.spring.boot.Log4j2CloudConfigLoggingSystem.loadConfiguration(Log4j2CloudConfigLoggingSystem.java:123)
    at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.loadConfiguration(Log4J2LoggingSystem.java:181)
    at org.springframework.boot.logging.AbstractLoggingSystem.initializeWithConventions(AbstractLoggingSystem.java:80)
    at org.springframework.boot.logging.AbstractLoggingSystem.initialize(AbstractLoggingSystem.java:60)
    at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.initialize(Log4J2LoggingSystem.java:163)
    at org.apache.logging.log4j.spring.boot.Log4j2CloudConfigLoggingSystem.initialize(Log4j2CloudConfigLoggingSystem.java:80)
    at org.springframework.boot.context.logging.LoggingApplicationListener.initializeSystem(LoggingApplicationListener.java:312)
    at org.springframework.boot.context.logging.LoggingApplicationListener.initialize(LoggingApplicationListener.java:281)
    at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEnvironmentPreparedEvent(LoggingApplicationListener.java:239)
    at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:216)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
    at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:82)
    at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:63)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:117)
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:111)
    at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:62)
    at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:373)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:331)
    at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:144)
    at org.springframework.cloud.bootstrap.BootstrapApplicationListener.bootstrapServiceContext(BootstrapApplicationListener.java:212)
    at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:117)
    at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:74)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
    at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:82)
    at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:63)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:117)
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:111)
    at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:62)
    at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:373)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:331)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1336)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1325)
    at com.example.demo1.Demo1Application.main(Demo1Application.java:12)

How to solve this? Thanks in advance.

Upvotes: 3

Views: 4160

Answers (3)

Mukit09
Mukit09

Reputation: 3409

I just added

implementation "org.apache.logging.log4j:log4j-spring-boot"

in build.gradle and it is working now.

Implementation of

implementation 'org.springframework.boot:spring-boot-starter-log4j2'

is enough for using log4j2 version 2.14.1 as spring boot version is 2.5.0-SNAPSHOT. No need to add dependencies of org.apache.logging.log4j explicitly for this.

So my final build.gradle is:

plugins {
    id 'org.springframework.boot' version '2.5.0-SNAPSHOT'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
    maven { url 'https://repo.spring.io/milestone' }
    maven { url 'https://repo.spring.io/snapshot' }
}

dependencies {

    compileOnly 'org.projectlombok:lombok:1.18.18'
    annotationProcessor 'org.projectlombok:lombok:1.18.18'

    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-log4j2'

    implementation "org.apache.logging.log4j:log4j-spring-boot"
}

configurations {
    all {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
    }
}

And no need to keep this in application.properties:

spring.cloud.config.enabled=false

And yes, Official Documentation of log4j should add that log4j-spring-boot dependency is enough to implement spring lookup.

Upvotes: 3

Vivek Semwal
Vivek Semwal

Reputation: 19

try this single $ istead of $$

fileName="${spring:commission.base.path1}/logs/catalina.log" filePattern="${spring:commission.base.path1}/logs/archived/catalina_%d{yyyy-MM-dd}.log.gz">

Upvotes: 0

RenatoIvancic
RenatoIvancic

Reputation: 2092

The question is do you need Log4j configuration over Spring Cloud?

Problem

If not, I would say org.apache.logging.log4j:2.14.1 dependency is an overkill. It brings Spring Cloud dependencies that you won't need. In a way that I still didn't figure out, it also interfeeres with spring-boot-starter-log4j2 causing initialization of logging context multiple times and then as a sideffect you have this excpetion at the startup as property from Spring is not resolved.

Solution

Mind you don't need whole log4j-spring-cloud-config-client and even spring-boot-starter-log4j2.

Following dependencies will set up your logging context:

  • log4j
  • log4j-slf4j-impl
  • log4j-spring-boot

I have put an example program in GitHub repository. Variable names are slightly changed and there are comments explaining what each dependency is for.

Excerpt of Gradle build file

dependencies {

  compileOnly 'org.projectlombok:lombok:1.18.18'
  annotationProcessor 'org.projectlombok:lombok:1.18.18'

  // Spring Boot dependency
  implementation 'org.springframework.boot:spring-boot-starter'
  testImplementation 'org.springframework.boot:spring-boot-starter-test'

  // Logging dependencies

  // Base Log4j 2
  implementation "org.apache.logging.log4j:log4j-api:${log4j2version}"

  // Will resolve spring properties
  implementation "org.apache.logging.log4j:log4j-spring-boot:${log4j2version}"

  // Log4j 2 to Slf4j binder
  implementation "org.apache.logging.log4j:log4j-slf4j-impl:${log4j2version}"
}

Official documentation should say that log4j-spring-boot dependency is enough to resolve lookup variables from Spring configuration files.

But in case you really need to configure Log4J over cloud configurations then again you have to carefully look on how the dependencies are resolved and which ones do you really need.

Upvotes: 2

Related Questions