Skip to content

Disable Jansi in generated logback-spring.xml to fix console logging after DevTools restart#15694

Open
jamesfredley wants to merge 3 commits into
7.0.xfrom
fix/forge-logback-withjansi-devtools
Open

Disable Jansi in generated logback-spring.xml to fix console logging after DevTools restart#15694
jamesfredley wants to merge 3 commits into
7.0.xfrom
fix/forge-logback-withjansi-devtools

Conversation

@jamesfredley

Copy link
Copy Markdown
Contributor

Summary

Grails Forge generated grails-app/conf/logback-spring.xml with <withJansi>true</withJansi> on non-Windows operating systems. This breaks console logging after the first Spring Boot DevTools restart.

Root cause

  • Jansi's AnsiConsole.systemInstall() globally replaces System.out/System.err and tracks installation with a static reference counter. That state lives in the Spring Boot DevTools base classloader, so it survives restarts.
  • Logback's ConsoleAppender calls systemInstall() on start() but never calls systemUninstall() on stop(). After the first DevTools restart, the old appender closes the shared Jansi stream while the counter stays above zero, so systemInstall() is a no-op and the new appender writes to a closed, stale stream. Console logging then silently stops - exactly the reported behavior (works at startup, dies after the first reload).
  • Spring Boot deliberately does not enable Jansi in its own logback defaults; it renders ANSI colors via its own AnsiOutput and the %clr converter, which does not replace System.out. There is therefore no benefit to enabling Jansi.

Change

  • Always generate <withJansi>false</withJansi> and remove the now-pointless OS-based toggle in Logback, making Forge consistent with the base profile skeleton (which already hardcodes false).
  • Add a LogbackSpec regression test asserting the generated config disables Jansi for every application type.

Verification

  • :grails-forge-core:compileJava passes and the generated Rocker template emits the literal <withJansi>false</withJansi>.
  • New LogbackSpec test covers all application types.

Fixes #15663

…after DevTools restart

Grails Forge generated logback-spring.xml with <withJansi>true</withJansi>
on non-Windows operating systems. Jansi's AnsiConsole.systemInstall()
globally replaces System.out/System.err and tracks installation with a
static reference counter that lives in the Spring Boot DevTools base
classloader, so it survives restarts.

Logback's ConsoleAppender calls systemInstall() on start() but never calls
systemUninstall() on stop(). After the first DevTools restart the old
appender closes the shared Jansi stream while the counter stays above zero,
so systemInstall() is a no-op and the new appender writes to a closed,
stale stream. Console logging then silently stops, which matches the
reported behavior (logging works at startup, dies after the first reload).

Spring Boot does not enable Jansi in its own logback defaults; it renders
ANSI colors via its own AnsiOutput and the %clr converter, which works
without globally replacing System.out. There is therefore no benefit to
enabling Jansi, so this removes the OS-based toggle and always generates
<withJansi>false</withJansi>, matching the base profile skeleton.

Fixes #15663

Assisted-by: claude-code:claude-opus-4.8
Copilot AI review requested due to automatic review settings May 29, 2026 04:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates Grails Forge’s generated Logback configuration to disable Jansi consistently, addressing console logging loss after Spring Boot DevTools restarts and aligning Forge output with the base profile skeleton.

Changes:

  • Removes OS-dependent Jansi toggling from the Logback feature.
  • Hard-codes <withJansi>false</withJansi> in the generated logback-spring.xml.
  • Adds regression coverage across all application types for the generated Logback config.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/Logback.java Removes OS lookup and passes the simplified template arguments.
grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/template/logback.rocker.raw Emits <withJansi>false</withJansi> directly in generated Logback config.
grails-forge/grails-forge-core/src/test/groovy/org/grails/forge/feature/logging/LogbackSpec.groovy Adds a regression test asserting generated configs disable Jansi.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@jdaugherty jdaugherty left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I disagree with this PR. It breaks the color logging. We should only be disabling jansi if devtools is selected as the reloading, we shouldn't remove it by default.

OperatingSystem operatingSystem = generatorContext.getOperatingSystem();
boolean jansi = false;

if (operatingSystem != OperatingSystem.WINDOWS) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This breaks color logging on other OSs. I don't agree with this solution.

@bito-code-review

Copy link
Copy Markdown

The change explicitly sets <withJansi>false</withJansi> in the logback-spring.xml template, removing the previous logic that conditionally enabled Jansi based on the operating system. This modification is intended to prevent issues with console logging after a Spring Boot DevTools restart, as noted in the added test case in LogbackSpec.groovy.

grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/template/logback.rocker.raw

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
-        <withJansi>@jansi</withJansi>
+        <withJansi>false</withJansi>

@jamesfredley

Copy link
Copy Markdown
Contributor Author

@jdaugherty we should look into why Spring Boot deliberately does not enable Jansi in its own logback defaults. This has been a landmine for Grails for multiple versions. Color is nice, but not at the cost that has been paid, and this time this is Mac/Linux too.

The PR that updates Jansi for CLI, might improve this situation. No sure.

@jdaugherty

Copy link
Copy Markdown
Contributor

@jdaugherty we should look into why Spring Boot deliberately does not enable Jansi in its own logback defaults. This has been a landmine for Grails for multiple versions. Color is nice, but not at the cost that has been paid, and this time this is Mac/Linux too.

The PR that updates Jansi for CLI, might improve this situation. No sure.

Windows is horrible with utf-8 / coloring. It's the only platform that has this issue. For why Spring Boot doesn't use that default, it doesn't have a lot of defaults. That doesn't stop us from having convention over configuration. This should be a requirement of Linux/Mac OS

@testlens-app

testlens-app Bot commented Jun 2, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: ab395d6
▶️ Tests: 12960 executed
⚪️ Checks: 32/32 completed


Learn more about TestLens at testlens.app.

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

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

<withJansi>true</withJansi> breaks console logging after first reload in Grails 7.1.0

3 participants