Search code examples
spring-bootlogbackgraalvm-native-image

Spring Boot native does not override Logback logging.config property


There is minimal SpringBoot + Gradle application

plugins {
    java
    id("org.springframework.boot") version "3.1.5"
    id("io.spring.dependency-management") version "1.1.3"
    id("org.graalvm.buildtools.native") version "0.9.27"
}

group = "com.example"
version = "0.0.7"

java {
    sourceCompatibility = JavaVersion.VERSION_17
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter")
}

tasks {
    bootBuildImage {
        builder.set("paketobuildpacks/builder-jammy-tiny:latest")
    }
}

application.properties looks like

logging.config=classpath:logback-aaa.xml

and single java file

package com.example.springlogbacknative;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringLogbackNativeApplication {
    public static Logger log = LoggerFactory.getLogger(SpringLogbackNativeApplication.class);

    public static void main(String[] args) {
        System.out.println("System.getenv(\"LOGGING_CONFIG\") = " + System.getenv("LOGGING_CONFIG"));
        System.out.println("System.getenv(\"logging.config\") = " + System.getenv("logging.config"));

        SpringApplication.run(SpringLogbackNativeApplication.class, args);
    }
}

After building this project with command ./gradlew bootBuildImage and running with following docker compose file

services:
  sln:
    image: spring-logback-native:0.0.7
    environment:
      LOGGING_CONFIG: "classpath:logback-replace.xml"
      logging.config: "classpath:logback-replace.xml"

No replacement happens.

System.getenv("LOGGING_CONFIG") = classpath:logback-replace.xml
System.getenv("logging.config") = classpath:logback-replace.xml
14:21:46,499 |-INFO in ch.qos.logback.classic.LoggerContext[default] - This is logback-classic version 1.4.11
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab - Here is a list of configurators discovered as a service, by rank: 
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab -   org.springframework.boot.logging.logback.RootLogLevelConfigurator
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab - They will be invoked in order until ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY is returned.
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab - Constructed configurator of type class org.springframework.boot.logging.logback.RootLogLevelConfigurator
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab - org.springframework.boot.logging.logback.RootLogLevelConfigurator.configure() call lasted 0 milliseconds. ExecutionStatus=INVOKE_NEXT_IF_ANY
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab - Trying to configure with ch.qos.logback.classic.joran.SerializedModelConfigurator
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab - Instantiation failure: java.lang.ClassNotFoundException: ch.qos.logback.classic.joran.SerializedModelConfigurator
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab - Trying to configure with ch.qos.logback.classic.util.DefaultJoranConfigurator
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab - Instantiation failure: java.lang.ClassNotFoundException: ch.qos.logback.classic.util.DefaultJoranConfigurator
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab - Trying to configure with ch.qos.logback.classic.BasicConfigurator
14:21:46,500 |-INFO in ch.qos.logback.classic.util.ContextInitializer@132da9ab - Instantiation failure: java.lang.ClassNotFoundException: ch.qos.logback.classic.BasicConfigurator
14:21:46,531 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - Processing appender named [console_aaa]
14:21:46,531 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
14:21:46,532 |-INFO in ch.qos.logback.core.model.processor.ImplicitModelHandler - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
14:21:46,532 |-INFO in ch.qos.logback.classic.model.processor.RootLoggerModelHandler - Setting level of ROOT logger to INFO
14:21:46,532 |-INFO in ch.qos.logback.classic.jul.LevelChangePropagator@ba501d9 - Propagating INFO level on Logger[ROOT] onto the JUL framework
14:21:46,532 |-INFO in ch.qos.logback.core.model.processor.AppenderRefModelHandler - Attaching appender named [console_aaa] to Logger[ROOT]
14:21:46,532 |-INFO in ch.qos.logback.core.model.processor.DefaultProcessor@5e495062 - End of configuration.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.1.5)

14:21:46.534 AAA INFO  c.e.s.SpringLogbackNativeApplication - Starting AOT-processed SpringLogbackNativeApplication using Java 17.0.8.1 with PID 1 (/workspace/com.example.springlogbacknative.SpringLogbackNativeApplication started by cnb in /workspace)
14:21:46.534 AAA INFO  c.e.s.SpringLogbackNativeApplication - No active profile set, falling back to 1 default profile: "default"
14:21:46.542 AAA INFO  c.e.s.SpringLogbackNativeApplication - Started SpringLogbackNativeApplication in 0.033 seconds (process running for 0.046)

I would expect logging.config=classpath:logback-aaa.xml from application.properties replaced with ENV LOGGING_CONFIG: "classpath:logback-replace.xml" provided in docker compose file.

My investigation end inside org.springframework.boot.context.logging.LoggingApplicationListener.initializeSystem where String logConfig = environment.getProperty(CONFIG_PROPERTY); IMHO should return replaced path. And it works in NON native environment.


Solution

  • This is the expected behavior when using XML to configure Logback.

    The Spring Boot reference documentation contains a section on known limitations. Within this section is a link to a page in Spring Boot's wiki that provides up-to-date information on these limitations, including a section on logging where it says the following:

    Logback is supported, including XML configuration. XML configuration is loaded at build time during AOT processing and translated into a fixed, native-friendly format. As a result, loading different XML configuration at runtime is not supported.