Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
* @author Andy Wilkinson
* @author Ben Hale
* @author Dhruv Rastogi
* @author Rameel Rizvi
* @since 1.0.0
*/
public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanFactoryInitializationAotProcessor {
Expand Down Expand Up @@ -114,6 +115,8 @@ public FilterReply decide(Marker marker, ch.qos.logback.classic.Logger logger, L

private boolean bridgeHandlerInstalled;

private boolean rootConsoleHandlerRemoved;

public LogbackLoggingSystem(ClassLoader classLoader) {
super(classLoader);
}
Expand Down Expand Up @@ -182,6 +185,23 @@ private void removeDefaultRootHandler() {
Handler[] handlers = rootLogger.getHandlers();
if (handlers.length == 1 && handlers[0] instanceof ConsoleHandler) {
rootLogger.removeHandler(handlers[0]);
this.rootConsoleHandlerRemoved = true;
}
}
catch (Throwable ex) {
// Ignore and continue
}
}

private void restoreDefaultRootHandler() {
if (!this.rootConsoleHandlerRemoved) {
return;
}
this.rootConsoleHandlerRemoved = false;
try {
java.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger("");
if (rootLogger.getHandlers().length == 0) {
rootLogger.addHandler(new ConsoleHandler());
}
}
catch (Throwable ex) {
Expand Down Expand Up @@ -340,6 +360,11 @@ public void cleanUp() {
super.cleanUp();
if (this.bridgeHandlerInstalled) {
removeJdkLoggingBridgeHandler();
// Restore the default JUL root handler that was removed when the bridge
// was installed. Without this, anything logged through JUL after cleanup
// (for example a startup failure reported via a JUL-backed commons-logging
// Log) would be silently discarded (see gh-50404).
restoreDefaultRootHandler();
this.bridgeHandlerInstalled = false;
}
context.getStatusManager().clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.LogManager;
import java.util.stream.Stream;
Expand Down Expand Up @@ -108,6 +109,7 @@
* @author Jonatan Ivanov
* @author Moritz Halbritter
* @author Dhruv Rastogi
* @author Rameel Rizvi
*/
@ExtendWith(OutputCaptureExtension.class)
@ClassPathExclusions({ "log4j-core-*.jar", "log4j-api-*.jar" })
Expand Down Expand Up @@ -355,6 +357,37 @@ void cleanUpLeavesBridgeHandlerInstalledByTheApplicationInPlace() {
}
}

@Test
void cleanUpRestoresDefaultRootHandlerToAvoidSilentlyDiscardingJulLogging(CapturedOutput output) {
// gh-50404: installing the bridge removes the default JUL root ConsoleHandler.
// If cleanUp does not restore it, anything subsequently logged through JUL
// (such as a startup failure reported via a JUL-backed commons-logging Log) is
// silently discarded. Start from the default single-ConsoleHandler state that a
// freshly started application has.
java.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger("");
Handler[] originalHandlers = rootLogger.getHandlers();
for (Handler handler : originalHandlers) {
rootLogger.removeHandler(handler);
}
rootLogger.addHandler(new ConsoleHandler());
try {
this.loggingSystem.beforeInitialize();
assertThat(bridgeHandlerInstalled()).isTrue();
this.loggingSystem.cleanUp();
assertThat(rootLogger.getHandlers()).isNotEmpty();
java.util.logging.Logger.getLogger(getClass().getName()).severe("JUL logging after cleanup");
assertThat(output).contains("JUL logging after cleanup");
}
finally {
for (Handler handler : rootLogger.getHandlers()) {
rootLogger.removeHandler(handler);
}
for (Handler handler : originalHandlers) {
rootLogger.addHandler(handler);
}
}
}

@Test
void standardConfigLocations() {
String[] locations = this.loggingSystem.getStandardConfigLocations();
Expand Down