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
This commit is contained in:
@@ -17,39 +17,73 @@
|
||||
package org.springframework.boot.logging.logback;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.core.status.OnPrintStreamStatusListenerBase;
|
||||
import ch.qos.logback.core.BasicStatusManager;
|
||||
import ch.qos.logback.core.status.OnConsoleStatusListener;
|
||||
import ch.qos.logback.core.status.Status;
|
||||
import ch.qos.logback.core.status.StatusListener;
|
||||
import ch.qos.logback.core.status.StatusManager;
|
||||
import ch.qos.logback.core.util.StatusPrinter2;
|
||||
|
||||
/**
|
||||
* {@link StatusListener} used to print appropriate status messages to {@link System#out}
|
||||
* or {@link System#err}.
|
||||
* or {@link System#err}. Note that this class extends {@link OnConsoleStatusListener} so
|
||||
* that {@link BasicStatusManager#add(StatusListener)} does not add the same listener
|
||||
* twice. It also implement a version of retrospectivePrint that can filter status
|
||||
* messages by level.
|
||||
*
|
||||
* @author Dmytro Nosan
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
final class SystemStatusListener extends OnPrintStreamStatusListenerBase {
|
||||
final class SystemStatusListener extends OnConsoleStatusListener {
|
||||
|
||||
static final long RETROSPECTIVE_THRESHOLD = 300;
|
||||
|
||||
private static final StatusPrinter2 PRINTER = new StatusPrinter2();
|
||||
|
||||
private final boolean debug;
|
||||
|
||||
private SystemStatusListener(boolean debug) {
|
||||
this.debug = debug;
|
||||
setResetResistant(false);
|
||||
if (!this.debug) {
|
||||
setRetrospective(0);
|
||||
setRetrospective(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
super.start();
|
||||
retrospectivePrint();
|
||||
}
|
||||
|
||||
private void retrospectivePrint() {
|
||||
if (this.context == null) {
|
||||
return;
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
List<Status> statusList = this.context.getStatusManager().getCopyOfStatusList();
|
||||
statusList.stream().filter((status) -> isPrintable(status, now)).forEach(this::print);
|
||||
}
|
||||
|
||||
private void print(Status status) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
PRINTER.buildStr(sb, "", status);
|
||||
getPrintStream().print(sb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStatusEvent(Status status) {
|
||||
if (this.debug || status.getLevel() >= Status.WARN) {
|
||||
if (isPrintable(status, 0)) {
|
||||
super.addStatusEvent(status);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPrintable(Status status, long now) {
|
||||
boolean timstampInRange = (now == 0 || (now - status.getTimestamp()) < RETROSPECTIVE_THRESHOLD);
|
||||
return timstampInRange && (this.debug || status.getLevel() >= Status.WARN);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PrintStream getPrintStream() {
|
||||
return (!this.debug) ? System.err : System.out;
|
||||
@@ -62,8 +96,8 @@ final class SystemStatusListener extends OnPrintStreamStatusListenerBase {
|
||||
static void addTo(LoggerContext loggerContext, boolean debug) {
|
||||
SystemStatusListener listener = new SystemStatusListener(debug);
|
||||
listener.setContext(loggerContext);
|
||||
StatusManager sm = loggerContext.getStatusManager();
|
||||
if (!sm.getCopyOfStatusListenerList().contains(listener) && sm.add(listener)) {
|
||||
StatusManager statusManager = loggerContext.getStatusManager();
|
||||
if (statusManager.add(listener)) {
|
||||
listener.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,8 +704,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void logbackSystemStatusListenerShouldBeRegisteredAndIgnoreAnyRetrospectiveStatusesIfDebugDisabled(
|
||||
CapturedOutput output) {
|
||||
void logbackSystemStatusListenerShouldBeRegisteredAndFilterStatusByLevelIfDebugDisabled(CapturedOutput output) {
|
||||
this.loggingSystem.beforeInitialize();
|
||||
LoggerContext loggerContext = this.logger.getLoggerContext();
|
||||
StatusManager statusManager = loggerContext.getStatusManager();
|
||||
@@ -718,10 +717,10 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
|
||||
assertThat(listener).hasFieldOrPropertyWithValue("debug", false);
|
||||
});
|
||||
this.logger.info("Hello world");
|
||||
assertThat(output).doesNotContain("INFO STATUS MESSAGE")
|
||||
.doesNotContain("WARN STATUS MESSAGE")
|
||||
.doesNotContain("ERROR STATUS MESSAGE")
|
||||
.contains("Hello world");
|
||||
assertThat(output).doesNotContain("INFO STATUS MESSAGE");
|
||||
assertThat(output).contains("WARN STATUS MESSAGE");
|
||||
assertThat(output).contains("ERROR STATUS MESSAGE");
|
||||
assertThat(output).contains("Hello world");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user