LogbackLoggingSystem Class — spring-boot Architecture
Architecture documentation for the LogbackLoggingSystem class in LogbackLoggingSystem.java from the spring-boot codebase.
Entity Profile
Relationship Graph
Source Code
core/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java lines 80–521
public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanFactoryInitializationAotProcessor {
private static final String BRIDGE_HANDLER = "org.slf4j.bridge.SLF4JBridgeHandler";
private static final String CONFIGURATION_FILE_PROPERTY = "logback.configurationFile";
private static final LogLevels<Level> LEVELS = createLogLevels();
@SuppressWarnings("deprecation")
private static LogLevels<Level> createLogLevels() {
LogLevels<Level> levels = new LogLevels<>();
levels.map(LogLevel.TRACE, Level.TRACE);
levels.map(LogLevel.TRACE, Level.ALL);
levels.map(LogLevel.DEBUG, Level.DEBUG);
levels.map(LogLevel.INFO, Level.INFO);
levels.map(LogLevel.WARN, Level.WARN);
levels.map(LogLevel.ERROR, Level.ERROR);
levels.map(LogLevel.FATAL, Level.ERROR);
levels.map(LogLevel.OFF, Level.OFF);
return levels;
}
private static final TurboFilter SUPPRESS_ALL_FILTER = new TurboFilter() {
@Override
public FilterReply decide(Marker marker, ch.qos.logback.classic.Logger logger, Level level, String format,
Object[] params, Throwable t) {
return FilterReply.DENY;
}
};
private final StatusPrinter2 statusPrinter = new StatusPrinter2();
public LogbackLoggingSystem(ClassLoader classLoader) {
super(classLoader);
}
@Override
public LoggingSystemProperties getSystemProperties(ConfigurableEnvironment environment) {
return new LogbackLoggingSystemProperties(environment, getDefaultValueResolver(environment), null);
}
@Override
protected String[] getStandardConfigLocations() {
return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" };
}
@Override
public void beforeInitialize() {
LoggerContext loggerContext = getLoggerContext();
if (isAlreadyInitialized(loggerContext)) {
return;
}
super.beforeInitialize();
configureJdkLoggingBridgeHandler();
loggerContext.getTurboFilterList().add(SUPPRESS_ALL_FILTER);
}
private void configureJdkLoggingBridgeHandler() {
try {
if (isBridgeJulIntoSlf4j()) {
removeJdkLoggingBridgeHandler();
SLF4JBridgeHandler.install();
}
}
catch (Throwable ex) {
// Ignore. No java.util.logging bridge is installed.
}
}
private boolean isBridgeJulIntoSlf4j() {
return isBridgeHandlerAvailable() && isJulUsingASingleConsoleHandlerAtMost();
}
private boolean isBridgeHandlerAvailable() {
return ClassUtils.isPresent(BRIDGE_HANDLER, getClassLoader());
}
private boolean isJulUsingASingleConsoleHandlerAtMost() {
java.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger("");
Handler[] handlers = rootLogger.getHandlers();
return handlers.length == 0 || (handlers.length == 1 && handlers[0] instanceof ConsoleHandler);
}
private void removeJdkLoggingBridgeHandler() {
try {
removeDefaultRootHandler();
SLF4JBridgeHandler.uninstall();
}
catch (Throwable ex) {
// Ignore and continue
}
}
private void removeDefaultRootHandler() {
try {
java.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger("");
Handler[] handlers = rootLogger.getHandlers();
if (handlers.length == 1 && handlers[0] instanceof ConsoleHandler) {
rootLogger.removeHandler(handlers[0]);
}
}
catch (Throwable ex) {
// Ignore and continue
}
}
@Override
public void initialize(LoggingInitializationContext initializationContext, @Nullable String configLocation,
@Nullable LogFile logFile) {
LoggerContext loggerContext = getLoggerContext();
putInitializationContextObjects(loggerContext, initializationContext);
if (isAlreadyInitialized(loggerContext)) {
return;
}
if (!initializeFromAotGeneratedArtifactsIfPossible(initializationContext, logFile)) {
super.initialize(initializationContext, configLocation, logFile);
}
loggerContext.getTurboFilterList().remove(SUPPRESS_ALL_FILTER);
markAsInitialized(loggerContext);
if (StringUtils.hasText(System.getProperty(CONFIGURATION_FILE_PROPERTY))) {
getLogger(LogbackLoggingSystem.class.getName()).warn("Ignoring '" + CONFIGURATION_FILE_PROPERTY
+ "' system property. Please use 'logging.config' instead.");
}
}
private boolean initializeFromAotGeneratedArtifactsIfPossible(LoggingInitializationContext initializationContext,
@Nullable LogFile logFile) {
if (!AotDetector.useGeneratedArtifacts()) {
return false;
}
if (initializationContext != null) {
Environment environment = initializationContext.getEnvironment();
Assert.state(environment != null, "'environment' must not be null");
applySystemProperties(environment, logFile);
}
LoggerContext loggerContext = getLoggerContext();
stopAndReset(loggerContext);
withLoggingSuppressed(() -> putInitializationContextObjects(loggerContext, initializationContext));
SystemStatusListener.addTo(loggerContext);
SpringBootJoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext);
configurator.setContext(loggerContext);
boolean configuredUsingAotGeneratedArtifacts = configurator.configureUsingAotGeneratedArtifacts();
if (configuredUsingAotGeneratedArtifacts) {
reportConfigurationErrorsIfNecessary(loggerContext);
}
return configuredUsingAotGeneratedArtifacts;
}
@Override
protected void loadDefaults(LoggingInitializationContext initializationContext, @Nullable LogFile logFile) {
LoggerContext loggerContext = getLoggerContext();
stopAndReset(loggerContext);
withLoggingSuppressed(() -> {
boolean debug = Boolean.getBoolean("logback.debug");
putInitializationContextObjects(loggerContext, initializationContext);
SystemStatusListener.addTo(loggerContext, debug);
Environment environment = initializationContext.getEnvironment();
Assert.state(environment != null, "'environment' must not be null");
// Apply system properties directly in case the same JVM runs multiple apps
new LogbackLoggingSystemProperties(environment, getDefaultValueResolver(environment),
loggerContext::putProperty)
.apply(logFile);
LogbackConfigurator configurator = (!debug) ? new LogbackConfigurator(loggerContext)
: new DebugLogbackConfigurator(loggerContext);
new DefaultLogbackConfiguration(logFile).apply(configurator);
loggerContext.setPackagingDataEnabled(true);
loggerContext.start();
});
}
@Override
protected void loadConfiguration(LoggingInitializationContext initializationContext, String location,
@Nullable LogFile logFile) {
LoggerContext loggerContext = getLoggerContext();
stopAndReset(loggerContext);
withLoggingSuppressed(() -> {
putInitializationContextObjects(loggerContext, initializationContext);
if (initializationContext != null) {
Environment environment = initializationContext.getEnvironment();
Assert.state(environment != null, "'environment' must not be null");
applySystemProperties(environment, logFile);
}
SystemStatusListener.addTo(loggerContext);
try {
Resource resource = ApplicationResourceLoader.get().getResource(location);
configureByResourceUrl(initializationContext, loggerContext, resource.getURL());
}
catch (Exception ex) {
throw new IllegalStateException("Could not initialize Logback logging from " + location, ex);
}
loggerContext.start();
});
reportConfigurationErrorsIfNecessary(loggerContext);
}
private void reportConfigurationErrorsIfNecessary(LoggerContext loggerContext) {
StringBuilder errors = new StringBuilder();
List<Throwable> suppressedExceptions = new ArrayList<>();
for (Status status : loggerContext.getStatusManager().getCopyOfStatusList()) {
if (status.getLevel() == Status.ERROR) {
errors.append((!errors.isEmpty()) ? String.format("%n") : "");
errors.append(status);
if (status.getThrowable() != null) {
suppressedExceptions.add(status.getThrowable());
}
}
}
if (errors.isEmpty()) {
if (!StatusUtil.contextHasStatusListener(loggerContext)) {
this.statusPrinter.printInCaseOfErrorsOrWarnings(loggerContext);
}
return;
}
IllegalStateException ex = new IllegalStateException(
String.format("Logback configuration error detected: %n%s", errors));
suppressedExceptions.forEach(ex::addSuppressed);
throw ex;
}
private void configureByResourceUrl(LoggingInitializationContext initializationContext, LoggerContext loggerContext,
URL url) throws JoranException {
JoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext);
configurator.setContext(loggerContext);
configurator.doConfigure(url);
}
private void stopAndReset(LoggerContext loggerContext) {
loggerContext.stop();
loggerContext.reset();
if (isBridgeHandlerInstalled()) {
addLevelChangePropagator(loggerContext);
}
}
private boolean isBridgeHandlerInstalled() {
if (!isBridgeHandlerAvailable()) {
return false;
}
java.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger("");
Handler[] handlers = rootLogger.getHandlers();
return handlers.length == 1 && handlers[0] instanceof SLF4JBridgeHandler;
}
private void addLevelChangePropagator(LoggerContext loggerContext) {
LevelChangePropagator levelChangePropagator = new LevelChangePropagator();
levelChangePropagator.setResetJUL(true);
levelChangePropagator.setContext(loggerContext);
loggerContext.addListener(levelChangePropagator);
}
@Override
public void cleanUp() {
LoggerContext context = getLoggerContext();
markAsUninitialized(context);
super.cleanUp();
if (isBridgeHandlerAvailable()) {
removeJdkLoggingBridgeHandler();
}
context.getStatusManager().clear();
context.getTurboFilterList().remove(SUPPRESS_ALL_FILTER);
}
@Override
protected void reinitialize(LoggingInitializationContext initializationContext) {
LoggerContext loggerContext = getLoggerContext();
loggerContext.reset();
loggerContext.getStatusManager().clear();
String location = getSelfInitializationConfig();
Assert.state(location != null, "location must not be null");
loadConfiguration(initializationContext, location, null);
}
private void putInitializationContextObjects(LoggerContext loggerContext,
LoggingInitializationContext initializationContext) {
withLoggingSuppressed(
() -> loggerContext.putObject(Environment.class.getName(), initializationContext.getEnvironment()));
}
@Override
public List<LoggerConfiguration> getLoggerConfigurations() {
List<LoggerConfiguration> result = new ArrayList<>();
for (ch.qos.logback.classic.Logger logger : getLoggerContext().getLoggerList()) {
result.add(getLoggerConfiguration(logger));
}
result.sort(CONFIGURATION_COMPARATOR);
return result;
}
@Override
public @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) {
String name = getLoggerName(loggerName);
LoggerContext loggerContext = getLoggerContext();
return getLoggerConfiguration(loggerContext.exists(name));
}
private String getLoggerName(@Nullable String name) {
if (!StringUtils.hasLength(name) || Logger.ROOT_LOGGER_NAME.equals(name)) {
return ROOT_LOGGER_NAME;
}
return name;
}
private @Nullable LoggerConfiguration getLoggerConfiguration(ch.qos.logback.classic.@Nullable Logger logger) {
if (logger == null) {
return null;
}
LogLevel level = LEVELS.convertNativeToSystem(logger.getLevel());
LogLevel effectiveLevel = LEVELS.convertNativeToSystem(logger.getEffectiveLevel());
String name = getLoggerName(logger.getName());
Assert.state(effectiveLevel != null, "effectiveLevel must not be null");
return new LoggerConfiguration(name, level, effectiveLevel);
}
@Override
public Set<LogLevel> getSupportedLogLevels() {
return LEVELS.getSupported();
}
@Override
public void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) {
ch.qos.logback.classic.Logger logger = getLogger(loggerName);
if (logger != null) {
logger.setLevel(LEVELS.convertSystemToNative(level));
}
}
@Override
public Runnable getShutdownHandler() {
return () -> getLoggerContext().stop();
}
private ch.qos.logback.classic.Logger getLogger(@Nullable String name) {
LoggerContext factory = getLoggerContext();
return factory.getLogger(getLoggerName(name));
}
private LoggerContext getLoggerContext() {
ILoggerFactory factory = getLoggerFactory();
Assert.state(factory instanceof LoggerContext,
() -> String.format(
"LoggerFactory is not a Logback LoggerContext but Logback is on "
+ "the classpath. Either remove Logback or the competing "
+ "implementation (%s loaded from %s). If you are using "
+ "WebLogic you will need to add 'org.slf4j' to "
+ "prefer-application-packages in WEB-INF/weblogic.xml",
factory.getClass(), getLocation(factory)));
return (LoggerContext) factory;
}
private ILoggerFactory getLoggerFactory() {
ILoggerFactory factory = LoggerFactory.getILoggerFactory();
while (factory instanceof SubstituteLoggerFactory) {
try {
Thread.sleep(50);
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Interrupted while waiting for non-substitute logger factory", ex);
}
factory = LoggerFactory.getILoggerFactory();
}
return factory;
}
private Object getLocation(ILoggerFactory factory) {
try {
ProtectionDomain protectionDomain = factory.getClass().getProtectionDomain();
CodeSource codeSource = protectionDomain.getCodeSource();
if (codeSource != null) {
return codeSource.getLocation();
}
}
catch (SecurityException ex) {
// Unable to determine location
}
return "unknown location";
}
private boolean isAlreadyInitialized(LoggerContext loggerContext) {
return loggerContext.getObject(LoggingSystem.class.getName()) != null;
}
private void markAsInitialized(LoggerContext loggerContext) {
loggerContext.putObject(LoggingSystem.class.getName(), new Object());
}
private void markAsUninitialized(LoggerContext loggerContext) {
loggerContext.removeObject(LoggingSystem.class.getName());
}
@Override
protected String getDefaultLogCorrelationPattern() {
return "%correlationId";
}
@Override
public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
String key = BeanFactoryInitializationAotContribution.class.getName();
LoggerContext context = getLoggerContext();
BeanFactoryInitializationAotContribution contribution = (BeanFactoryInitializationAotContribution) context
.getObject(key);
context.removeObject(key);
return contribution;
}
private void withLoggingSuppressed(Runnable action) {
TurboFilterList turboFilters = getLoggerContext().getTurboFilterList();
turboFilters.add(SUPPRESS_ALL_FILTER);
try {
action.run();
}
finally {
turboFilters.remove(SUPPRESS_ALL_FILTER);
}
}
void setStatusPrinterStream(PrintStream stream) {
this.statusPrinter.setPrintStream(stream);
}
/**
* {@link LoggingSystemFactory} that returns {@link LogbackLoggingSystem} if possible.
*/
@Order(Ordered.HIGHEST_PRECEDENCE + 1024)
public static class Factory implements LoggingSystemFactory {
private static final boolean PRESENT = ClassUtils.isPresent("ch.qos.logback.classic.LoggerContext",
Factory.class.getClassLoader());
@Override
public @Nullable LoggingSystem getLoggingSystem(ClassLoader classLoader) {
if (PRESENT) {
return new LogbackLoggingSystem(classLoader);
}
return null;
}
}
}
Domain
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free