Skip to content

Commit 6ba8e9b

Browse files
nosanphilwebb
authored andcommitted
Fix SystemStatusListener to prevent superfluous output
Fix `SystemStatusListener` so that superfluous output is not printed when starting an application. This change ensures that the `SystemStatusListener` is not added twice, and that retrospective logging only occurs when `debug` is true. See gh-43931 Signed-off-by: Dmytro Nosan <[email protected]>
1 parent fc01b01 commit 6ba8e9b

File tree

3 files changed

+68
-6
lines changed

3 files changed

+68
-6
lines changed

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

+17-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import ch.qos.logback.core.status.OnPrintStreamStatusListenerBase;
2323
import ch.qos.logback.core.status.Status;
2424
import ch.qos.logback.core.status.StatusListener;
25+
import ch.qos.logback.core.status.StatusManager;
2526

2627
/**
2728
* {@link StatusListener} used to print appropriate status messages to {@link System#out}
@@ -36,6 +37,10 @@ final class SystemStatusListener extends OnPrintStreamStatusListenerBase {
3637

3738
private SystemStatusListener(boolean debug) {
3839
this.debug = debug;
40+
setResetResistant(false);
41+
if (!this.debug) {
42+
setRetrospective(0);
43+
}
3944
}
4045

4146
@Override
@@ -57,9 +62,20 @@ static void addTo(LoggerContext loggerContext) {
5762
static void addTo(LoggerContext loggerContext, boolean debug) {
5863
SystemStatusListener listener = new SystemStatusListener(debug);
5964
listener.setContext(loggerContext);
60-
if (loggerContext.getStatusManager().add(listener)) {
65+
StatusManager sm = loggerContext.getStatusManager();
66+
if (!sm.getCopyOfStatusListenerList().contains(listener) && sm.add(listener)) {
6167
listener.start();
6268
}
6369
}
6470

71+
@Override
72+
public boolean equals(Object obj) {
73+
return (obj != null) && (obj.getClass() == getClass());
74+
}
75+
76+
@Override
77+
public int hashCode() {
78+
return getClass().hashCode();
79+
}
80+
6581
}

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

+49-4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
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.ErrorStatus;
44+
import ch.qos.logback.core.status.InfoStatus;
45+
import ch.qos.logback.core.status.StatusManager;
46+
import ch.qos.logback.core.status.WarnStatus;
4347
import ch.qos.logback.core.util.DynamicClassLoadingException;
4448
import org.junit.jupiter.api.AfterEach;
4549
import org.junit.jupiter.api.BeforeEach;
@@ -645,13 +649,20 @@ void logbackDebugPropertyIsHonored(CapturedOutput output) {
645649
System.setProperty("logback.debug", "true");
646650
try {
647651
this.loggingSystem.beforeInitialize();
652+
LoggerContext loggerContext = this.logger.getLoggerContext();
653+
StatusManager statusManager = loggerContext.getStatusManager();
654+
statusManager.add(new InfoStatus("INFO STATUS MESSAGE", getClass()));
655+
statusManager.add(new WarnStatus("WARN STATUS MESSAGE", getClass()));
656+
statusManager.add(new ErrorStatus("ERROR STATUS MESSAGE", getClass()));
648657
File file = new File(tmpDir(), "logback-test.log");
649658
LogFile logFile = getLogFile(file.getPath(), null);
650659
initialize(this.initializationContext, null, logFile);
651660
assertThat(output).contains("LevelChangePropagator")
652661
.contains("SizeAndTimeBasedFileNamingAndTriggeringPolicy")
653-
.contains("DebugLogbackConfigurator");
654-
LoggerContext loggerContext = this.logger.getLoggerContext();
662+
.contains("DebugLogbackConfigurator")
663+
.contains("INFO STATUS MESSAGE")
664+
.contains("WARN STATUS MESSAGE")
665+
.contains("ERROR STATUS MESSAGE");
655666
assertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList()).allSatisfy((listener) -> {
656667
assertThat(listener).isInstanceOf(SystemStatusListener.class);
657668
assertThat(listener).hasFieldOrPropertyWithValue("debug", true);
@@ -663,7 +674,7 @@ void logbackDebugPropertyIsHonored(CapturedOutput output) {
663674
}
664675

665676
@Test
666-
void logbackErrorStatusListenerShouldBeRegistered(CapturedOutput output) {
677+
void logbackSystemStatusListenerShouldBeRegistered(CapturedOutput output) {
667678
this.loggingSystem.beforeInitialize();
668679
initialize(this.initializationContext, null, getLogFile(tmpDir() + "/tmp.log", null));
669680
LoggerContext loggerContext = this.logger.getLoggerContext();
@@ -680,7 +691,41 @@ void logbackErrorStatusListenerShouldBeRegistered(CapturedOutput output) {
680691
}
681692

682693
@Test
683-
void logbackErrorStatusListenerShouldBeRegisteredWhenUsingCustomLogbackXml(CapturedOutput output) {
694+
void logbackSystemStatusListenerShouldBeRegisteredOnlyOnce() {
695+
this.loggingSystem.beforeInitialize();
696+
initialize(this.initializationContext, null, getLogFile(tmpDir() + "/tmp.log", null));
697+
LoggerContext loggerContext = this.logger.getLoggerContext();
698+
SystemStatusListener.addTo(loggerContext);
699+
SystemStatusListener.addTo(loggerContext, true);
700+
assertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList()).satisfiesOnlyOnce((listener) -> {
701+
assertThat(listener).isInstanceOf(SystemStatusListener.class);
702+
assertThat(listener).hasFieldOrPropertyWithValue("debug", false);
703+
});
704+
}
705+
706+
@Test
707+
void logbackSystemStatusListenerShouldBeRegisteredAndIgnoreAnyRetrospectiveStatusesIfDebugDisabled(
708+
CapturedOutput output) {
709+
this.loggingSystem.beforeInitialize();
710+
LoggerContext loggerContext = this.logger.getLoggerContext();
711+
StatusManager statusManager = loggerContext.getStatusManager();
712+
statusManager.add(new InfoStatus("INFO STATUS MESSAGE", getClass()));
713+
statusManager.add(new WarnStatus("WARN STATUS MESSAGE", getClass()));
714+
statusManager.add(new ErrorStatus("ERROR STATUS MESSAGE", getClass()));
715+
initialize(this.initializationContext, null, getLogFile(tmpDir() + "/tmp.log", null));
716+
assertThat(statusManager.getCopyOfStatusListenerList()).allSatisfy((listener) -> {
717+
assertThat(listener).isInstanceOf(SystemStatusListener.class);
718+
assertThat(listener).hasFieldOrPropertyWithValue("debug", false);
719+
});
720+
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");
725+
}
726+
727+
@Test
728+
void logbackSystemStatusListenerShouldBeRegisteredWhenUsingCustomLogbackXml(CapturedOutput output) {
684729
this.loggingSystem.beforeInitialize();
685730
initialize(this.initializationContext, "classpath:logback-include-defaults.xml", null);
686731
LoggerContext loggerContext = this.logger.getLoggerContext();

spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-structured-logging/src/test/java/smoketest/structuredlogging/SampleStructuredLoggingApplicationTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@
3636
class SampleStructuredLoggingApplicationTests {
3737

3838
@AfterEach
39-
void reset() {
39+
void reset(CapturedOutput output) {
4040
LoggingSystem.get(getClass().getClassLoader()).cleanUp();
4141
for (LoggingSystemProperty property : LoggingSystemProperty.values()) {
4242
System.getProperties().remove(property.getEnvironmentVariableName());
4343
}
44+
assertThat(output).doesNotContain("-INFO in ch.qos.logback.classic.LoggerContext");
4445
}
4546

4647
@Test

0 commit comments

Comments
 (0)