Skip to content

Commit c884529

Browse files
committed
Refine SystemStatusListener superfluous output fix
Change `SystemStatusListener` to a `OnConsoleStatusListener` to ensure that it cannot be added twice from different threads. Also add a local `retrospectivePrint()` that is used for non-debug output that will print ERROR and WARN status, but not INFO. See gh-43931
1 parent 6ba8e9b commit c884529

File tree

2 files changed

+47
-14
lines changed

2 files changed

+47
-14
lines changed

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

+42-8
Original file line numberDiff line numberDiff line change
@@ -17,39 +17,73 @@
1717
package org.springframework.boot.logging.logback;
1818

1919
import java.io.PrintStream;
20+
import java.util.List;
2021

2122
import ch.qos.logback.classic.LoggerContext;
22-
import ch.qos.logback.core.status.OnPrintStreamStatusListenerBase;
23+
import ch.qos.logback.core.BasicStatusManager;
24+
import ch.qos.logback.core.status.OnConsoleStatusListener;
2325
import ch.qos.logback.core.status.Status;
2426
import ch.qos.logback.core.status.StatusListener;
2527
import ch.qos.logback.core.status.StatusManager;
28+
import ch.qos.logback.core.util.StatusPrinter2;
2629

2730
/**
2831
* {@link StatusListener} used to print appropriate status messages to {@link System#out}
29-
* or {@link System#err}.
32+
* or {@link System#err}. Note that this class extends {@link OnConsoleStatusListener} so
33+
* that {@link BasicStatusManager#add(StatusListener)} does not add the same listener
34+
* twice. It also implement a version of retrospectivePrint that can filter status
35+
* messages by level.
3036
*
3137
* @author Dmytro Nosan
3238
* @author Phillip Webb
3339
*/
34-
final class SystemStatusListener extends OnPrintStreamStatusListenerBase {
40+
final class SystemStatusListener extends OnConsoleStatusListener {
41+
42+
static final long RETROSPECTIVE_THRESHOLD = 300;
43+
44+
private static final StatusPrinter2 PRINTER = new StatusPrinter2();
3545

3646
private final boolean debug;
3747

3848
private SystemStatusListener(boolean debug) {
3949
this.debug = debug;
4050
setResetResistant(false);
41-
if (!this.debug) {
42-
setRetrospective(0);
51+
setRetrospective(0);
52+
}
53+
54+
@Override
55+
public void start() {
56+
super.start();
57+
retrospectivePrint();
58+
}
59+
60+
private void retrospectivePrint() {
61+
if (this.context == null) {
62+
return;
4363
}
64+
long now = System.currentTimeMillis();
65+
List<Status> statusList = this.context.getStatusManager().getCopyOfStatusList();
66+
statusList.stream().filter((status) -> isPrintable(status, now)).forEach(this::print);
67+
}
68+
69+
private void print(Status status) {
70+
StringBuilder sb = new StringBuilder();
71+
PRINTER.buildStr(sb, "", status);
72+
getPrintStream().print(sb);
4473
}
4574

4675
@Override
4776
public void addStatusEvent(Status status) {
48-
if (this.debug || status.getLevel() >= Status.WARN) {
77+
if (isPrintable(status, 0)) {
4978
super.addStatusEvent(status);
5079
}
5180
}
5281

82+
private boolean isPrintable(Status status, long now) {
83+
boolean timstampInRange = (now == 0 || (now - status.getTimestamp()) < RETROSPECTIVE_THRESHOLD);
84+
return timstampInRange && (this.debug || status.getLevel() >= Status.WARN);
85+
}
86+
5387
@Override
5488
protected PrintStream getPrintStream() {
5589
return (!this.debug) ? System.err : System.out;
@@ -62,8 +96,8 @@ static void addTo(LoggerContext loggerContext) {
6296
static void addTo(LoggerContext loggerContext, boolean debug) {
6397
SystemStatusListener listener = new SystemStatusListener(debug);
6498
listener.setContext(loggerContext);
65-
StatusManager sm = loggerContext.getStatusManager();
66-
if (!sm.getCopyOfStatusListenerList().contains(listener) && sm.add(listener)) {
99+
StatusManager statusManager = loggerContext.getStatusManager();
100+
if (statusManager.add(listener)) {
67101
listener.start();
68102
}
69103
}

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

+5-6
Original file line numberDiff line numberDiff line change
@@ -704,8 +704,7 @@ void logbackSystemStatusListenerShouldBeRegisteredOnlyOnce() {
704704
}
705705

706706
@Test
707-
void logbackSystemStatusListenerShouldBeRegisteredAndIgnoreAnyRetrospectiveStatusesIfDebugDisabled(
708-
CapturedOutput output) {
707+
void logbackSystemStatusListenerShouldBeRegisteredAndFilterStatusByLevelIfDebugDisabled(CapturedOutput output) {
709708
this.loggingSystem.beforeInitialize();
710709
LoggerContext loggerContext = this.logger.getLoggerContext();
711710
StatusManager statusManager = loggerContext.getStatusManager();
@@ -718,10 +717,10 @@ void logbackSystemStatusListenerShouldBeRegisteredAndIgnoreAnyRetrospectiveStatu
718717
assertThat(listener).hasFieldOrPropertyWithValue("debug", false);
719718
});
720719
this.logger.info("Hello world");
721-
assertThat(output).doesNotContain("INFO STATUS MESSAGE")
722-
.doesNotContain("WARN STATUS MESSAGE")
723-
.doesNotContain("ERROR STATUS MESSAGE")
724-
.contains("Hello world");
720+
assertThat(output).doesNotContain("INFO STATUS MESSAGE");
721+
assertThat(output).contains("WARN STATUS MESSAGE");
722+
assertThat(output).contains("ERROR STATUS MESSAGE");
723+
assertThat(output).contains("Hello world");
725724
}
726725

727726
@Test

0 commit comments

Comments
 (0)