Skip to content

Generate Logback configurator during AOT processing - #52466

Open
ceki wants to merge 2 commits into
spring-projects:mainfrom
ceki:logback-tyler-integration
Open

ceki wants to merge 2 commits into
spring-projects:mainfrom
ceki:logback-tyler-integration

Conversation

@ceki

@ceki ceki commented Oct 27, 2026

Copy link
Copy Markdown

Generate Logback configurator during AOT processing

Overview

At the moment, Logback XML configuration in a native image relies on the model serialized during AOT processing (META-INF/spring/logback-model). That model is deserialized and processed at runtime, which depends on reflection and on Logback's model handlers running inside the native image.

This PR uses logback-tyler. When tyler-base is on the AOT processing classpath, the application's Logback XML configuration is translated into Java source during AOT processing. The result is a GeneratedLogbackConfigurator class that is compiled into the application and used at runtime instead of the serialized model.

How it works

  • AOT processing: SpringBootJoranConfigurator passes the configuration file (getTopURL()) to SpringBootModelToJava, a subclass of Tyler's ModelToJava. The configurator source is contributed as org.springframework.boot.logging.logback.aot.GeneratedLogbackConfigurator, together with a reflection hint for its public constructor. Includes such as Boot's base.xml are resolved at translation time, so nothing is parsed from XML at runtime.

  • Spring-specific elements: two Boot-specific Tyler model handlers translate <springProperty> and <springProfile>:

    • <springProperty> becomes PropertyModelHandlerHelper.setProperty(this, name, springProperty(source, defaultValue), scope).
    • <springProfile name="..."> becomes if (acceptsProfiles("...")) { ... } around the nested elements.

    springProperty(...) and acceptsProfiles(...) are provided by the new SpringBootTylerConfiguratorBase and are evaluated against the Environment at runtime. Activating a profile when the native image is launched (--spring.profiles.active=staging) therefore behaves as it does on the JVM. The profile matching logic is extracted to SpringProfileModelHandler.acceptsProfiles(...), so the XML and generated paths share it.

  • Runtime: when AOT-generated artifacts are in use, LogbackLoggingSystem instantiates the generated configurator if it is present and uses it to configure the LoggerContext. Otherwise it falls back to the serialized model, as before.

  • Failure handling: any warning or error reported while parsing, checking or translating the configuration fails AOT processing with an IllegalStateException that lists the problems. A configuration that could not be translated faithfully is not silently shipped. For example, a <springProfile> nested inside a <logger> element, which only produces a warning at runtime, now fails the build.

  • Fallback: if Tyler is not on the AOT processing classpath, or the configuration was not loaded from a URL, the existing serialized-model contribution is used unchanged.

Dependencies

  • Upgrade to Logback 1.6.6.
  • Add dependency management for ch.qos.logback.tyler:tyler-base 1.0.5.
  • tyler-base is an optional dependency of spring-boot. It is needed only during AOT processing, not at runtime.

The Logback upgrade could be split into a separate commit if preferred.

User opt-in

Users currently opt in by adding Tyler to the AOT processing classpath:

dependencies {
	processAotClasspath("ch.qos.logback.tyler:tyler-base")
}

Maven has no AOT-only classpath, so tyler-base has to be added as a regular dependency. A follow-up could have the Gradle and Maven plugins add it automatically.

Testing

  • SpringBootModelToJavaTests: compiles the translated configurator and checks that it produces the same LoggerContext state as SpringBootJoranConfigurator across several profile and property combinations. The fixture covers nested and negated profiles, ${...} in profile names, conversion rules and the base.xml include. Translation failures are also covered.
  • GeneratedConfiguratorAotContributionTests: checks the contributed source and hint, that the contributed source compiles, matching and differing contributions, the fallback without Tyler, and failure on configurations that cannot be translated.
  • LogbackLoggingSystemGeneratedConfiguratorTests: checks the runtime path with spring.aot.enabled=true, with and without a generated configurator.
  • :core:spring-boot:check passes.
  • Manual check: I built a native image (GraalVM 25) of the Logback smoke-test application, with its logback-spring.xml and base.xml include, against Logback 1.6.6 and logback-tyler 1.0.5. With the default and staging profiles it logs as expected, the file appender works, and no logback-model resource is generated.

Related issues

  • Support Janino in a native image #33758 (Janino in a native image, declined): no longer applicable. Logback has dropped Janino support, and <if condition="..."> expressions are no longer honored, so there are no runtime-compiled conditions left to support. The issue's comments also suggested combining Tyler-generated code with Boot's Logback support, which is what this PR does.
  • Provide a hook for configuring Logback programatically #25847 (programmatic Logback configuration hook): related. The generated configurator is a programmatic Configurator that supports <springProperty>, <springProfile> and Boot's default includes, which are the obstacles described in the issue. This PR does not add a public hook for user-written configurators.
  • Reduce XML classes in native image when using Logback #33324 (reduce XML classes in native images): a step toward it. When the generated configurator is used, no XML is parsed at runtime. However, LogbackLoggingSystem still references SpringBootJoranConfigurator for the non-AOT path, so the XML classes are likely still reachable during native image analysis. Making them unreachable would need further changes, for example skipping the Joran path when a generated configurator is present.

  Previously, AOT processing serialized the Logback configuration model
  to META-INF/spring/logback-model, and this was deserialized and
  processed at runtime. The deserialization relied on reflection, which
  made the approach fragile in a native image.

  This commit uses logback-tyler, when it is on the AOT processing
  classpath, to translate the Logback XML configuration into Java source
  for a GeneratedLogbackConfigurator class. The class extends the new
  SpringBootTylerConfiguratorBase. When AOT-generated artifacts are in
  use, LogbackLoggingSystem instantiates that class to configure Logback.
  <springProperty> and <springProfile> elements are translated by
  Spring Boot-specific Tyler model handlers into code that is evaluated
  against the Environment at runtime, so profiles and properties still
  take effect at runtime. Any warning or error reported during
  translation fails AOT processing.

  When Tyler is not available, or the configuration was not loaded from
  a URL, the existing serialized-model approach is used.

  This commit also upgrades to Logback 1.6.6 and adds dependency
  management for logback-tyler 1.0.5.

Signed-off-by: ceki <ceki@qos.ch>
Copilot AI balanced review requested due to automatic review settings October 27, 2026 18:33
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue that has not yet been triaged. Contributions will not be accepted. label Oct 27, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Valid Logback configurations can produce uncompilable generated code or silently change behavior during translation.

5 open issues
What changed in this PR

Adds optional Tyler-based Java generation to Spring Boot’s Logback AOT support, allowing runtime configuration without deserializing a Logback model.

Changes:

  • Generates configurator source with runtime support for Spring properties and profiles.
  • Prefers generated configurators at startup while retaining the serialized-model fallback.
  • Updates dependencies and adds translation, contribution, and runtime tests.
File Description
platform/​spring-boot-dependencies/​build.gradle Upgrades Logback and manages Tyler.
core/​spring-boot/​src/​test/​java/​org/​springframework/​boot/​logging/​logback/​SpringBootModelToJavaTests.java Tests translation equivalence and failure handling.
core/​spring-boot/​src/​test/​java/​org/​springframework/​boot/​logging/​logback/​LogbackLoggingSystemGeneratedConfiguratorTests.java Tests generated-configurator startup and fallback.
core/​spring-boot/​src/​test/​java/​org/​springframework/​boot/​logging/​logback/​LogbackConfigurationAotContributionTests.java Keeps existing tests on the serialized-model path.
core/​spring-boot/​src/​test/​java/​org/​springframework/​boot/​logging/​logback/​GeneratedConfiguratorAotContributionTests.java Tests generated source, hints, and contribution consistency.
core/​spring-boot/​src/​main/​java/​org/​springframework/​boot/​logging/​logback/​SpringProfileModelHandler.java Shares profile-matching logic with generated configuration.
core/​spring-boot/​src/​main/​java/​org/​springframework/​boot/​logging/​logback/​SpringBootTylerConfiguratorBase.java Provides runtime Spring property and profile helpers.
core/​spring-boot/​src/​main/​java/​org/​springframework/​boot/​logging/​logback/​SpringBootModelToJava.java Translates XML and Spring-specific elements into Java.
core/​spring-boot/​src/​main/​java/​org/​springframework/​boot/​logging/​logback/​SpringBootJoranConfigurator.java Contributes generated source when Tyler is available.
core/​spring-boot/​src/​main/​java/​org/​springframework/​boot/​logging/​logback/​LogbackLoggingSystem.java Loads generated configurators during AOT startup.
core/​spring-boot/​build.gradle Adds the optional Tyler dependency.
config/​checkstyle/​checkstyle-suppressions.xml Permits logging imports in the new runtime tests.

Review effort: Balanced

@ceki

ceki commented Oct 28, 2026

Copy link
Copy Markdown
Author

Most of the review items automatically generated have easy fixes in logback-tyler that will be adressed by version logback-tyler 1.0.6. However, the remark about "Tyler translates in document order rather than preserving Joran's property-first processing" seems more serious/pervasive. I am looking into it.

In the meantime, please do not merge this PR.

@wilkinsona
wilkinsona marked this pull request as draft October 28, 2026 10:47
Upgrade to logback-tyler 1.0.6, which fixes the translation issues
raised in the review of spring-projectsgh-52466:

- Properties are now available to the appenders and loggers that
  precede them, as with Joran's two processing phases. Conditions,
  including <springProfile>, are evaluated once, where they appear in
  the configuration.
- The packagingData attribute of <configuration> is translated.
- Logger, appender and appender-ref names are substituted at runtime.
- Appenders with the same name can be defined in mutually exclusive
  branches, for example in <springProfile name=dev> and

The <springProfile> translation handler now extends Tyler's
GuardModelHandler, so that the elements it contains are guarded in
both phases.

The configuration is now passed to the XML parser as a byte stream
so that its encoding declaration is honored. Previously, it was
decoded as UTF-8, which corrupted configurations that use another
encoding, such as ISO-8859-1, and broke the parsing of UTF-16
configurations.

An <appender-ref> to an appender that is never declared now fails AOT
processing, as Tyler reports it while translating. With Joran, it
only produces a warning at runtime.

See spring-projectsgh-52466

Signed-off-by: ceki <ceki@qos.ch>
@ceki

ceki commented Oct 28, 2026 •

Copy link
Copy Markdown
Author

All five issues raised during review were reproduced and are now fixed in logback-tyler version 1.0.6, which commit 2 of this PR now uses.

@wilkinsona
wilkinsona marked this pull request as ready for review October 29, 2026 09:08

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue that has not yet been triaged. Contributions will not be accepted.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants