Skip to content

Commit 8536950

Browse files
committed
Polish Logback StatusListener code
Introduce a `SystemStatusListener` class to simplify Logback status listener registration for both debug and regular output. See gh-43931
1 parent 258eb29 commit 8536950

File tree

6 files changed

+185
-235
lines changed

6 files changed

+185
-235
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/FilteringStatusListener.java

Lines changed: 0 additions & 80 deletions
This file was deleted.

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,8 @@
3535
import ch.qos.logback.classic.turbo.TurboFilter;
3636
import ch.qos.logback.core.joran.spi.JoranException;
3737
import ch.qos.logback.core.spi.FilterReply;
38-
import ch.qos.logback.core.status.OnConsoleStatusListener;
39-
import ch.qos.logback.core.status.OnErrorConsoleStatusListener;
4038
import ch.qos.logback.core.status.Status;
4139
import ch.qos.logback.core.status.StatusUtil;
42-
import ch.qos.logback.core.util.StatusListenerConfigHelper;
4340
import ch.qos.logback.core.util.StatusPrinter2;
4441
import org.slf4j.ILoggerFactory;
4542
import org.slf4j.Logger;
@@ -216,7 +213,7 @@ private boolean initializeFromAotGeneratedArtifactsIfPossible(LoggingInitializat
216213
LoggerContext loggerContext = getLoggerContext();
217214
stopAndReset(loggerContext);
218215
withLoggingSuppressed(() -> putInitializationContextObjects(loggerContext, initializationContext));
219-
addOnErrorConsoleStatusListener(loggerContext);
216+
SystemStatusListener.addTo(loggerContext);
220217
SpringBootJoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext);
221218
configurator.setContext(loggerContext);
222219
boolean configuredUsingAotGeneratedArtifacts = configurator.configureUsingAotGeneratedArtifacts();
@@ -231,21 +228,16 @@ protected void loadDefaults(LoggingInitializationContext initializationContext,
231228
LoggerContext loggerContext = getLoggerContext();
232229
stopAndReset(loggerContext);
233230
withLoggingSuppressed(() -> {
234-
putInitializationContextObjects(loggerContext, initializationContext);
235231
boolean debug = Boolean.getBoolean("logback.debug");
236-
if (debug) {
237-
StatusListenerConfigHelper.addOnConsoleListenerInstance(loggerContext, new OnConsoleStatusListener());
238-
}
239-
else {
240-
addOnErrorConsoleStatusListener(loggerContext);
241-
}
232+
putInitializationContextObjects(loggerContext, initializationContext);
233+
SystemStatusListener.addTo(loggerContext, debug);
242234
Environment environment = initializationContext.getEnvironment();
243235
// Apply system properties directly in case the same JVM runs multiple apps
244236
new LogbackLoggingSystemProperties(environment, getDefaultValueResolver(environment),
245237
loggerContext::putProperty)
246238
.apply(logFile);
247-
LogbackConfigurator configurator = debug ? new DebugLogbackConfigurator(loggerContext)
248-
: new LogbackConfigurator(loggerContext);
239+
LogbackConfigurator configurator = (!debug) ? new LogbackConfigurator(loggerContext)
240+
: new DebugLogbackConfigurator(loggerContext);
249241
new DefaultLogbackConfiguration(logFile).apply(configurator);
250242
loggerContext.setPackagingDataEnabled(true);
251243
loggerContext.start();
@@ -262,7 +254,7 @@ protected void loadConfiguration(LoggingInitializationContext initializationCont
262254
if (initializationContext != null) {
263255
applySystemProperties(initializationContext.getEnvironment(), logFile);
264256
}
265-
addOnErrorConsoleStatusListener(loggerContext);
257+
SystemStatusListener.addTo(loggerContext);
266258
try {
267259
Resource resource = ApplicationResourceLoader.get().getResource(location);
268260
configureByResourceUrl(initializationContext, loggerContext, resource.getURL());
@@ -493,15 +485,6 @@ private void withLoggingSuppressed(Runnable action) {
493485
}
494486
}
495487

496-
private void addOnErrorConsoleStatusListener(LoggerContext context) {
497-
FilteringStatusListener listener = new FilteringStatusListener(new OnErrorConsoleStatusListener(),
498-
Status.WARN);
499-
listener.setContext(context);
500-
if (context.getStatusManager().add(listener)) {
501-
listener.start();
502-
}
503-
}
504-
505488
void setStatusPrinterStream(PrintStream stream) {
506489
this.statusPrinter.setPrintStream(stream);
507490
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.logging.logback;
18+
19+
import java.io.PrintStream;
20+
21+
import ch.qos.logback.classic.LoggerContext;
22+
import ch.qos.logback.core.status.OnPrintStreamStatusListenerBase;
23+
import ch.qos.logback.core.status.Status;
24+
import ch.qos.logback.core.status.StatusListener;
25+
26+
/**
27+
* {@link StatusListener} used to print appropriate status messages to {@link System#out}
28+
* or {@link System#err}.
29+
*
30+
* @author Dmytro Nosan
31+
* @author Phillip Webb
32+
*/
33+
final class SystemStatusListener extends OnPrintStreamStatusListenerBase {
34+
35+
private final boolean debug;
36+
37+
private SystemStatusListener(boolean debug) {
38+
this.debug = debug;
39+
}
40+
41+
@Override
42+
public void addStatusEvent(Status status) {
43+
if (this.debug || status.getLevel() >= Status.WARN) {
44+
super.addStatusEvent(status);
45+
}
46+
}
47+
48+
@Override
49+
protected PrintStream getPrintStream() {
50+
return (!this.debug) ? System.err : System.out;
51+
}
52+
53+
static void addTo(LoggerContext loggerContext) {
54+
addTo(loggerContext, false);
55+
}
56+
57+
static void addTo(LoggerContext loggerContext, boolean debug) {
58+
SystemStatusListener listener = new SystemStatusListener(debug);
59+
listener.setContext(loggerContext);
60+
if (loggerContext.getStatusManager().add(listener)) {
61+
listener.start();
62+
}
63+
}
64+
65+
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/FilteringStatusListenerTests.java

Lines changed: 0 additions & 121 deletions
This file was deleted.

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@
4040
import ch.qos.logback.core.joran.spi.JoranException;
4141
import ch.qos.logback.core.rolling.RollingFileAppender;
4242
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
43-
import ch.qos.logback.core.status.OnConsoleStatusListener;
44-
import ch.qos.logback.core.status.OnErrorConsoleStatusListener;
45-
import ch.qos.logback.core.status.Status;
4643
import ch.qos.logback.core.util.DynamicClassLoadingException;
4744
import org.junit.jupiter.api.AfterEach;
4845
import org.junit.jupiter.api.BeforeEach;
@@ -655,8 +652,10 @@ void logbackDebugPropertyIsHonored(CapturedOutput output) {
655652
.contains("SizeAndTimeBasedFileNamingAndTriggeringPolicy")
656653
.contains("DebugLogbackConfigurator");
657654
LoggerContext loggerContext = this.logger.getLoggerContext();
658-
assertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList())
659-
.allSatisfy((listener) -> assertThat(listener).isInstanceOf(OnConsoleStatusListener.class));
655+
assertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList()).allSatisfy((listener) -> {
656+
assertThat(listener).isInstanceOf(SystemStatusListener.class);
657+
assertThat(listener).hasFieldOrPropertyWithValue("debug", true);
658+
});
660659
}
661660
finally {
662661
System.clearProperty("logback.debug");
@@ -669,9 +668,8 @@ void logbackErrorStatusListenerShouldBeRegistered(CapturedOutput output) {
669668
initialize(this.initializationContext, null, getLogFile(tmpDir() + "/tmp.log", null));
670669
LoggerContext loggerContext = this.logger.getLoggerContext();
671670
assertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList()).allSatisfy((listener) -> {
672-
assertThat(listener).isInstanceOf(FilteringStatusListener.class);
673-
assertThat(listener).hasFieldOrPropertyWithValue("levelThreshold", Status.WARN);
674-
assertThat(listener).extracting("delegate").isInstanceOf(OnErrorConsoleStatusListener.class);
671+
assertThat(listener).isInstanceOf(SystemStatusListener.class);
672+
assertThat(listener).hasFieldOrPropertyWithValue("debug", false);
675673
});
676674
AlwaysFailAppender appender = new AlwaysFailAppender();
677675
appender.setContext(loggerContext);
@@ -687,9 +685,8 @@ void logbackErrorStatusListenerShouldBeRegisteredWhenUsingCustomLogbackXml(Captu
687685
initialize(this.initializationContext, "classpath:logback-include-defaults.xml", null);
688686
LoggerContext loggerContext = this.logger.getLoggerContext();
689687
assertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList()).allSatisfy((listener) -> {
690-
assertThat(listener).isInstanceOf(FilteringStatusListener.class);
691-
assertThat(listener).hasFieldOrPropertyWithValue("levelThreshold", Status.WARN);
692-
assertThat(listener).extracting("delegate").isInstanceOf(OnErrorConsoleStatusListener.class);
688+
assertThat(listener).isInstanceOf(SystemStatusListener.class);
689+
assertThat(listener).hasFieldOrPropertyWithValue("debug", false);
693690
});
694691
AlwaysFailAppender appender = new AlwaysFailAppender();
695692
appender.setContext(loggerContext);

0 commit comments

Comments
 (0)