From 29e493897178ffd62643787e2b074d02b2ec07e7 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 11 Mar 2026 11:26:34 +0000 Subject: [PATCH] Polish "Add more styling support to the Logback and Log4j2 color converters" See gh-49285 --- .../boot/logging/log4j2/ColorConverter.java | 17 +++------ .../boot/logging/logback/ColorConverter.java | 3 -- .../logging/log4j2/ColorConverterTests.java | 29 +++++---------- .../reference/pages/features/logging.adoc | 37 ++++++++++++++++--- 4 files changed, 47 insertions(+), 39 deletions(-) diff --git a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ColorConverter.java b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ColorConverter.java index 0757f3851b0..ba2bc58b35b 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ColorConverter.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ColorConverter.java @@ -61,14 +61,11 @@ public final class ColorConverter extends LogEventPatternConverter { static { Map ansiElements = new HashMap<>(); - // Foreground colors (e.g. "red", "bright_blue") Arrays.stream(AnsiColor.values()) .filter((color) -> color != AnsiColor.DEFAULT) .forEach((color) -> ansiElements.put(color.name().toLowerCase(Locale.ROOT), color)); - // Text styles (e.g. "bold", "italic", "underline", "reverse", "faint", "normal") Arrays.stream(AnsiStyle.values()) .forEach((style) -> ansiElements.put(style.name().toLowerCase(Locale.ROOT), style)); - // Background colors with "bg_" prefix (e.g. "bg_red", "bg_bright_blue") Arrays.stream(AnsiBackground.values()) .filter((bg) -> bg != AnsiBackground.DEFAULT) .forEach((bg) -> ansiElements.put("bg_" + bg.name().toLowerCase(Locale.ROOT), bg)); @@ -153,14 +150,12 @@ public final class ColorConverter extends LogEventPatternConverter { PatternParser parser = PatternLayout.createPatternParser(config); List formatters = parser.parse(options[0]); List stylings = new ArrayList<>(); - for (int i = 1; i < options.length; i++) { - if (options[i] != null) { - String[] optionParts = options[i].split(","); - for (String optionPart : optionParts) { - AnsiElement element = ELEMENTS.get(optionPart.trim().toLowerCase(Locale.ROOT)); - if (element != null) { - stylings.add(element); - } + if (options.length >= 2 && options[1] != null) { + String[] optionParts = options[1].split(","); + for (String optionPart : optionParts) { + AnsiElement element = ELEMENTS.get(optionPart.trim().toLowerCase(Locale.ROOT)); + if (element != null) { + stylings.add(element); } } } diff --git a/core/spring-boot/src/main/java/org/springframework/boot/logging/logback/ColorConverter.java b/core/spring-boot/src/main/java/org/springframework/boot/logging/logback/ColorConverter.java index 12fc43aab06..4a16f7784b9 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/logging/logback/ColorConverter.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/logging/logback/ColorConverter.java @@ -51,14 +51,11 @@ public class ColorConverter extends CompositeConverter { static { Map ansiElements = new HashMap<>(); - // Foreground colors (e.g. "red", "bright_blue") Arrays.stream(AnsiColor.values()) .filter((color) -> color != AnsiColor.DEFAULT) .forEach((color) -> ansiElements.put(color.name().toLowerCase(Locale.ROOT), color)); - // Text styles (e.g. "bold", "italic", "underline", "reverse", "faint", "normal") Arrays.stream(AnsiStyle.values()) .forEach((style) -> ansiElements.put(style.name().toLowerCase(Locale.ROOT), style)); - // Background colors with "bg_" prefix (e.g. "bg_red", "bg_bright_blue") Arrays.stream(AnsiBackground.values()) .filter((bg) -> bg != AnsiBackground.DEFAULT) .forEach((bg) -> ansiElements.put("bg_" + bg.name().toLowerCase(Locale.ROOT), bg)); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ColorConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ColorConverterTests.java index ca07f8c56ce..fe76b5a144e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ColorConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ColorConverterTests.java @@ -237,24 +237,17 @@ class ColorConverterTests { } @Test - void multipleStylesCommaSeparated() { + void multipleStyles() { StringBuilder output = new StringBuilder(); newConverter("bold, red").format(this.event, output); assertThat(output).hasToString("\033[1;31min\033[0;39m"); } - @Test - void multipleStylesMultipleOptions() { - StringBuilder output = new StringBuilder(); - newConverter("bold", "red").format(this.event, output); - assertThat(output).hasToString("\033[1;31min\033[0;39m"); - } - @Test void highlightFatal() { this.event.setLevel(Level.FATAL); StringBuilder output = new StringBuilder(); - newConverter((String) null).format(this.event, output); + newConverter(null).format(this.event, output); assertThat(output).hasToString("\033[31min\033[0;39m"); } @@ -262,7 +255,7 @@ class ColorConverterTests { void highlightError() { this.event.setLevel(Level.ERROR); StringBuilder output = new StringBuilder(); - newConverter((String) null).format(this.event, output); + newConverter(null).format(this.event, output); assertThat(output).hasToString("\033[31min\033[0;39m"); } @@ -270,7 +263,7 @@ class ColorConverterTests { void highlightWarn() { this.event.setLevel(Level.WARN); StringBuilder output = new StringBuilder(); - newConverter((String) null).format(this.event, output); + newConverter(null).format(this.event, output); assertThat(output).hasToString("\033[33min\033[0;39m"); } @@ -278,7 +271,7 @@ class ColorConverterTests { void highlightDebug() { this.event.setLevel(Level.DEBUG); StringBuilder output = new StringBuilder(); - newConverter((String) null).format(this.event, output); + newConverter(null).format(this.event, output); assertThat(output).hasToString("\033[32min\033[0;39m"); } @@ -286,17 +279,13 @@ class ColorConverterTests { void highlightTrace() { this.event.setLevel(Level.TRACE); StringBuilder output = new StringBuilder(); - newConverter((String) null).format(this.event, output); + newConverter(null).format(this.event, output); assertThat(output).hasToString("\033[32min\033[0;39m"); } - private ColorConverter newConverter(@Nullable String... stylings) { - if (stylings == null) { - stylings = new String[] { null }; - } - String[] options = new String[1 + stylings.length]; - options[0] = this.in; - System.arraycopy(stylings, 0, options, 1, stylings.length); + private ColorConverter newConverter(@Nullable String additionalOptions) { + String[] options = (additionalOptions != null) ? new String[] { this.in, additionalOptions } + : new String[] { this.in }; ColorConverter converter = ColorConverter.newInstance(null, options); assertThat(converter).isNotNull(); return converter; diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc index 69ffa2d30cf..53760e83f54 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc @@ -113,15 +113,15 @@ The following table describes the mapping of log levels to colors: | Green |=== -Alternatively, you can specify the color or style that should be used by providing it as an option to the conversion. -For example, to make the text yellow, use the following setting: +Alternatively, you can specify the color and styles that should be used by providing them as options to the conversion. +For example, to make the text yellow and bold, use the following setting: [source] ---- -%clr(%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}){yellow} +%clr(%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}){yellow,bold} ---- -The following colors and styles are supported: +The following text colors are supported: * `black` * `blue` @@ -134,13 +134,40 @@ The following colors and styles are supported: * `bright_white` * `bright_yellow` * `cyan` -* `faint` * `green` * `magenta` * `red` * `white` * `yellow` +The following background colors are supported: + +* `bg_black` +* `bg_blue` +* `bg_bright_black` +* `bg_bright_blue` +* `bg_bright_cyan` +* `bg_bright_green` +* `bg_bright_magenta` +* `bg_bright_red` +* `bg_bright_white` +* `bg_bright_yellow` +* `bg_cyan` +* `bg_green` +* `bg_magenta` +* `bg_red` +* `bg_white` +* `bg_yellow` + +The following styles are supported: + +* `bold` +* `faint` +* `italic` +* `normal` +* `reverse` +* `underline` + [[features.logging.file-output]]