Use Console charset for console logging when available

Prior to this commit, LogbackLoggingSystemProperties
doesn't respect Console.charset(). It used Charset.getDefaultCharset()
for logback and  UTF-8 for log42j as defaults.

This commit changes the behaviour of LogbackLoggingSystemProperties to use
 Console.charset() when available. If no console is present, the default
 charset is used instead.

These changes bring consistency across logging implementations.

See gh-43118

Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>
This commit is contained in:
Dmytro Nosan 2025-02-19 12:12:21 +02:00 committed by Moritz Halbritter
parent 93648792b1
commit a250bbb7e4
4 changed files with 65 additions and 15 deletions

View File

@ -16,8 +16,8 @@
package org.springframework.boot.logging;
import java.io.Console;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.function.BiConsumer;
import java.util.function.Function;
@ -91,8 +91,12 @@ public class LoggingSystemProperties {
this.setter = (setter != null) ? setter : systemPropertySetter;
}
protected Console getConsole() {
return System.console();
}
protected Charset getDefaultCharset() {
return StandardCharsets.UTF_8;
return Charset.defaultCharset();
}
public final void apply() {
@ -116,12 +120,11 @@ public class LoggingSystemProperties {
}
protected void apply(LogFile logFile, PropertyResolver resolver) {
String defaultCharsetName = getDefaultCharset().name();
setSystemProperty(LoggingSystemProperty.APPLICATION_NAME, resolver);
setSystemProperty(LoggingSystemProperty.APPLICATION_GROUP, resolver);
setSystemProperty(LoggingSystemProperty.PID, new ApplicationPid().toString());
setSystemProperty(LoggingSystemProperty.CONSOLE_CHARSET, resolver, defaultCharsetName);
setSystemProperty(LoggingSystemProperty.FILE_CHARSET, resolver, defaultCharsetName);
setSystemProperty(LoggingSystemProperty.CONSOLE_CHARSET, resolver, getConsoleCharset().name());
setSystemProperty(LoggingSystemProperty.FILE_CHARSET, resolver, getDefaultCharset().name());
setSystemProperty(LoggingSystemProperty.CONSOLE_THRESHOLD, resolver, this::thresholdMapper);
setSystemProperty(LoggingSystemProperty.FILE_THRESHOLD, resolver, this::thresholdMapper);
setSystemProperty(LoggingSystemProperty.EXCEPTION_CONVERSION_WORD, resolver);
@ -137,6 +140,11 @@ public class LoggingSystemProperties {
}
}
private Charset getConsoleCharset() {
Console console = getConsole();
return (console != null) ? console.charset() : getDefaultCharset();
}
private void setSystemProperty(LoggingSystemProperty property, PropertyResolver resolver) {
setSystemProperty(property, resolver, Function.identity());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,7 +16,7 @@
package org.springframework.boot.logging.logback;
import java.nio.charset.Charset;
import java.io.Console;
import java.util.function.BiConsumer;
import java.util.function.Function;
@ -71,8 +71,8 @@ public class LogbackLoggingSystemProperties extends LoggingSystemProperties {
}
@Override
protected Charset getDefaultCharset() {
return Charset.defaultCharset();
protected Console getConsole() {
return super.getConsole();
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,9 @@
package org.springframework.boot.logging;
import java.io.Console;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
@ -31,6 +34,9 @@ import org.springframework.core.env.StandardEnvironment;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
/**
* Tests for {@link LoggingSystemProperties}.
@ -72,9 +78,22 @@ class LoggingSystemPropertiesTests {
}
@Test
void consoleCharsetWhenNoPropertyUsesUtf8() {
new LoggingSystemProperties(new MockEnvironment()).apply(null);
assertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_CHARSET)).isEqualTo("UTF-8");
void consoleCharsetWhenNoPropertyUsesCharsetDefault() {
LoggingSystemProperties loggingSystemProperties = spy(new LoggingSystemProperties(new MockEnvironment()));
given(loggingSystemProperties.getConsole()).willReturn(null);
loggingSystemProperties.apply(null);
assertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_CHARSET)).isEqualTo(Charset.defaultCharset().name());
}
@Test
void consoleCharsetWhenNoPropertyUsesSystemConsoleCharsetWhenAvailable() {
LoggingSystemProperties loggingSystemProperties = spy(new LoggingSystemProperties(new MockEnvironment()));
Console console = mock(Console.class);
given(console.charset()).willReturn(StandardCharsets.UTF_16BE);
given(loggingSystemProperties.getConsole()).willReturn(console);
loggingSystemProperties.apply(null);
assertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_CHARSET))
.isEqualTo(StandardCharsets.UTF_16BE.name());
}
@Test

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,7 +16,9 @@
package org.springframework.boot.logging.logback;
import java.io.Console;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Set;
@ -31,6 +33,9 @@ import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
/**
* Tests for {@link LogbackLoggingSystemProperties}.
@ -102,11 +107,29 @@ class LogbackLoggingSystemPropertiesTests {
@Test
void consoleCharsetWhenNoPropertyUsesDefault() {
new LoggingSystemProperties(new MockEnvironment()).apply(null);
LogbackLoggingSystemProperties logbackLoggingSystemProperties = spy(
new LogbackLoggingSystemProperties(new MockEnvironment(), null, null));
given(logbackLoggingSystemProperties.getConsole()).willReturn(null);
logbackLoggingSystemProperties.apply(null);
assertThat(System.getProperty(LoggingSystemProperty.CONSOLE_CHARSET.getEnvironmentVariableName()))
.isEqualTo(Charset.defaultCharset().name());
}
@Test
void consoleCharsetWhenNoPropertyUsesSystemConsoleCharsetWhenAvailable() {
LogbackLoggingSystemProperties logbackLoggingSystemProperties = spy(
new LogbackLoggingSystemProperties(new MockEnvironment(), null, null));
Console console = mock(Console.class);
given(console.charset()).willReturn(StandardCharsets.UTF_16BE);
given(logbackLoggingSystemProperties.getConsole()).willReturn(console);
logbackLoggingSystemProperties.apply(null);
assertThat(System.getProperty(LoggingSystemProperty.CONSOLE_CHARSET.getEnvironmentVariableName()))
.isEqualTo(StandardCharsets.UTF_16BE.name());
}
@Test
void fileCharsetWhenNoPropertyUsesDefault() {
new LoggingSystemProperties(new MockEnvironment()).apply(null);