Upgrade to Logback 1.4 and SLF4J 2.0

Closes gh-12649
This commit is contained in:
Andy Wilkinson 2022-09-28 21:14:08 +01:00
parent 05d2f3cc8e
commit 0bfa9cd704
19 changed files with 355 additions and 190 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,7 +24,7 @@ import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
import org.junit.jupiter.api.Test;
import org.slf4j.impl.StaticLoggerBinder;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasMetricsExportAutoConfiguration;
@ -76,8 +76,7 @@ class MeterRegistryConfigurerIntegrationTests {
void counterIsIncrementedOncePerEventWithoutCompositeMeterRegistry() {
new ApplicationContextRunner().with(MetricsRun.limitedTo(JmxMetricsExportAutoConfiguration.class))
.withConfiguration(AutoConfigurations.of(LogbackMetricsAutoConfiguration.class)).run((context) -> {
Logger logger = ((LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory())
.getLogger("test-logger");
Logger logger = ((LoggerContext) LoggerFactory.getILoggerFactory()).getLogger("test-logger");
logger.error("Error.");
Map<String, MeterRegistry> registriesByName = context.getBeansOfType(MeterRegistry.class);
assertThat(registriesByName).hasSize(1);
@ -92,8 +91,7 @@ class MeterRegistryConfigurerIntegrationTests {
.with(MetricsRun.limitedTo(JmxMetricsExportAutoConfiguration.class,
PrometheusMetricsExportAutoConfiguration.class))
.withConfiguration(AutoConfigurations.of(LogbackMetricsAutoConfiguration.class)).run((context) -> {
Logger logger = ((LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory())
.getLogger("test-logger");
Logger logger = ((LoggerContext) LoggerFactory.getILoggerFactory()).getLogger("test-logger");
logger.error("Error.");
Map<String, MeterRegistry> registriesByName = context.getBeansOfType(MeterRegistry.class);
assertThat(registriesByName).hasSize(3);

View File

@ -23,7 +23,7 @@ import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.impl.StaticLoggerBinder;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
@ -147,8 +147,8 @@ class ConditionEvaluationReportLoggingListenerTests {
}
private void withDebugLogging(Runnable runnable) {
LoggerContext context = (LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory();
Logger logger = context.getLogger(ConditionEvaluationReportLoggingListener.class);
Logger logger = ((LoggerContext) LoggerFactory.getILoggerFactory())
.getLogger(ConditionEvaluationReportLoggingListener.class);
Level currentLevel = logger.getLevel();
logger.setLevel(Level.DEBUG);
try {

View File

@ -863,7 +863,7 @@ bom {
]
}
}
library("Logback", "1.2.11") {
library("Logback", "1.4.1") {
group("ch.qos.logback") {
modules = [
"logback-access",
@ -1366,7 +1366,7 @@ bom {
]
}
}
library("SLF4J", "1.7.36") {
library("SLF4J", "2.0.2") {
group("org.slf4j") {
modules = [
"jcl-over-slf4j",
@ -1375,9 +1375,11 @@ bom {
"slf4j-api",
"slf4j-ext",
"slf4j-jcl",
"slf4j-jdk-platform-logging",
"slf4j-jdk14",
"slf4j-log4j12",
"slf4j-nop",
"slf4j-reload4j",
"slf4j-simple"
]
}

View File

@ -5,7 +5,7 @@ plugins {
description = "Starter for using Log4j2 for logging. An alternative to spring-boot-starter-logging"
dependencies {
api("org.apache.logging.log4j:log4j-slf4j-impl")
api("org.apache.logging.log4j:log4j-slf4j2-impl")
api("org.apache.logging.log4j:log4j-core")
api("org.apache.logging.log4j:log4j-jul")
}

View File

@ -19,7 +19,7 @@ package org.springframework.boot.loader.tools;
import ch.qos.logback.classic.Level;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.impl.StaticLoggerBinder;
import org.slf4j.LoggerFactory;
import org.springframework.util.ClassUtils;
@ -32,7 +32,7 @@ import org.springframework.util.ClassUtils;
public abstract class LogbackInitializer {
public static void initialize() {
if (ClassUtils.isPresent("org.slf4j.impl.StaticLoggerBinder", null)
if (ClassUtils.isPresent("org.slf4j.LoggerFactory", null)
&& ClassUtils.isPresent("ch.qos.logback.classic.Logger", null)) {
new Initializer().setRootLogLevel();
}
@ -41,7 +41,7 @@ public abstract class LogbackInitializer {
private static class Initializer {
void setRootLogLevel() {
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
ILoggerFactory factory = LoggerFactory.getILoggerFactory();
Logger logger = factory.getLogger(Logger.ROOT_LOGGER_NAME);
((ch.qos.logback.classic.Logger) logger).setLevel(Level.INFO);
}

View File

@ -25,6 +25,7 @@ import ch.qos.logback.core.Appender;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
import ch.qos.logback.core.spi.ScanException;
import ch.qos.logback.core.util.FileSize;
import ch.qos.logback.core.util.OptionHelper;
@ -146,7 +147,12 @@ class DefaultLogbackConfiguration {
}
private String resolve(LogbackConfigurator config, String val) {
return OptionHelper.substVars(val, config.getContext());
try {
return OptionHelper.substVars(val, config.getContext());
}
catch (ScanException ex) {
throw new RuntimeException(ex);
}
}
}

View File

@ -39,9 +39,9 @@ import ch.qos.logback.core.status.Status;
import ch.qos.logback.core.util.StatusListenerConfigHelper;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.AbstractLoggingSystem;
import org.springframework.boot.logging.LogFile;
@ -348,7 +348,7 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem {
}
private LoggerContext getLoggerContext() {
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
ILoggerFactory factory = LoggerFactory.getILoggerFactory();
Assert.isInstanceOf(LoggerContext.class, factory,
() -> String.format(
"LoggerFactory is not a Logback LoggerContext but Logback is on "

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,18 +17,18 @@
package org.springframework.boot.logging.logback;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.action.NOPAction;
import ch.qos.logback.core.joran.spi.ElementSelector;
import ch.qos.logback.core.joran.spi.RuleStore;
import ch.qos.logback.core.model.processor.DefaultProcessor;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.core.env.Environment;
/**
* Extended version of the Logback {@link JoranConfigurator} that adds additional Spring
* Boot rules.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
class SpringBootJoranConfigurator extends JoranConfigurator {
@ -39,12 +39,22 @@ class SpringBootJoranConfigurator extends JoranConfigurator {
}
@Override
public void addInstanceRules(RuleStore rs) {
super.addInstanceRules(rs);
Environment environment = this.initializationContext.getEnvironment();
rs.addRule(new ElementSelector("configuration/springProperty"), new SpringPropertyAction(environment));
rs.addRule(new ElementSelector("*/springProfile"), new SpringProfileAction(environment));
rs.addRule(new ElementSelector("*/springProfile/*"), new NOPAction());
protected void addModelHandlerAssociations(DefaultProcessor defaultProcessor) {
super.addModelHandlerAssociations(defaultProcessor);
defaultProcessor.addHandler(SpringPropertyModel.class,
(handlerContext, handlerMic) -> new SpringPropertyModelHandler(this.context,
this.initializationContext.getEnvironment()));
defaultProcessor.addHandler(SpringProfileModel.class,
(handlerContext, handlerMic) -> new SpringProfileModelHandler(this.context,
this.initializationContext.getEnvironment()));
}
@Override
public void addElementSelectorAndActionAssociations(RuleStore ruleStore) {
super.addElementSelectorAndActionAssociations(ruleStore);
ruleStore.addRule(new ElementSelector("configuration/springProperty"), SpringPropertyAction::new);
ruleStore.addRule(new ElementSelector("*/springProfile"), SpringProfileAction::new);
ruleStore.addTransparentPathPart("springProfile");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,102 +16,29 @@
package org.springframework.boot.logging.logback;
import java.util.ArrayList;
import java.util.List;
import ch.qos.logback.core.joran.action.Action;
import ch.qos.logback.core.joran.event.InPlayListener;
import ch.qos.logback.core.joran.event.SaxEvent;
import ch.qos.logback.core.joran.spi.ActionException;
import ch.qos.logback.core.joran.spi.InterpretationContext;
import ch.qos.logback.core.joran.spi.Interpreter;
import ch.qos.logback.core.util.OptionHelper;
import ch.qos.logback.core.joran.action.BaseModelAction;
import ch.qos.logback.core.joran.spi.SaxEventInterpretationContext;
import ch.qos.logback.core.model.Model;
import org.xml.sax.Attributes;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Logback {@link Action} to support {@code <springProfile>} tags. Allows section of a
* logback configuration to only be enabled when a specific profile is active.
* Logback {@link BaseModelAction} for {@code <springProperty>} tags. Allows a section of
* a Logback configuration to only be enabled when a specific profile is active.
*
* @author Phillip Webb
* @author Eddú Meléndez
* @author Andy Wilkinson
* @see SpringProfileModel
* @see SpringProfileModelHandler
*/
class SpringProfileAction extends Action implements InPlayListener {
private final Environment environment;
private int depth = 0;
private boolean acceptsProfile;
private List<SaxEvent> events;
SpringProfileAction(Environment environment) {
this.environment = environment;
}
class SpringProfileAction extends BaseModelAction {
@Override
public void begin(InterpretationContext ic, String name, Attributes attributes) throws ActionException {
this.depth++;
if (this.depth != 1) {
return;
}
ic.pushObject(this);
this.acceptsProfile = acceptsProfiles(ic, attributes);
this.events = new ArrayList<>();
ic.addInPlayListener(this);
}
private boolean acceptsProfiles(InterpretationContext ic, Attributes attributes) {
if (this.environment == null) {
return false;
}
String[] profileNames = StringUtils
.trimArrayElements(StringUtils.commaDelimitedListToStringArray(attributes.getValue(NAME_ATTRIBUTE)));
if (profileNames.length == 0) {
return false;
}
for (int i = 0; i < profileNames.length; i++) {
profileNames[i] = OptionHelper.substVars(profileNames[i], ic, this.context);
}
return this.environment.acceptsProfiles(Profiles.of(profileNames));
}
@Override
public void end(InterpretationContext ic, String name) throws ActionException {
this.depth--;
if (this.depth != 0) {
return;
}
ic.removeInPlayListener(this);
verifyAndPop(ic);
if (this.acceptsProfile) {
addEventsToPlayer(ic);
}
}
private void verifyAndPop(InterpretationContext ic) {
Object o = ic.peekObject();
Assert.state(o != null, "Unexpected null object on stack");
Assert.isInstanceOf(SpringProfileAction.class, o, "logback stack error");
Assert.state(o == this, "ProfileAction different than current one on stack");
ic.popObject();
}
private void addEventsToPlayer(InterpretationContext ic) {
Interpreter interpreter = ic.getJoranInterpreter();
this.events.remove(0);
this.events.remove(this.events.size() - 1);
interpreter.getEventPlayer().addEventsDynamically(this.events, 1);
}
@Override
public void inPlay(SaxEvent event) {
this.events.add(event);
protected Model buildCurrentModel(SaxEventInterpretationContext interpretationContext, String name,
Attributes attributes) {
SpringProfileModel model = new SpringProfileModel();
model.setName(attributes.getValue(NAME_ATTRIBUTE));
return model;
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.logging.logback;
import ch.qos.logback.core.model.NamedModel;
/**
* Logback {@link NamedModel model} to support {@code <springProfile>} tags.
*
* @author Andy Wilkinson
* @see SpringProfileAction
* @see SpringProfileModelHandler
*/
class SpringProfileModel extends NamedModel {
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.logging.logback;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.model.Model;
import ch.qos.logback.core.model.processor.ModelHandlerBase;
import ch.qos.logback.core.model.processor.ModelHandlerException;
import ch.qos.logback.core.model.processor.ModelInterpretationContext;
import ch.qos.logback.core.spi.ScanException;
import ch.qos.logback.core.util.OptionHelper;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.util.StringUtils;
/**
* Logback {@link ModelHandlerBase model handler} to support {@code <springProfile>} tags.
*
* @author Phillip Webb
* @author Eddú Meléndez
* @author Andy Wilkinson
* @see SpringProfileModel
* @see SpringProfileAction
*/
class SpringProfileModelHandler extends ModelHandlerBase {
private final Environment environment;
SpringProfileModelHandler(Context context, Environment environment) {
super(context);
this.environment = environment;
}
@Override
public void handle(ModelInterpretationContext intercon, Model model) throws ModelHandlerException {
SpringProfileModel profileModel = (SpringProfileModel) model;
if (!acceptsProfiles(intercon, profileModel)) {
model.markAsSkipped();
}
}
private boolean acceptsProfiles(ModelInterpretationContext ic, SpringProfileModel model) {
if (this.environment == null) {
return false;
}
String[] profileNames = StringUtils
.trimArrayElements(StringUtils.commaDelimitedListToStringArray(model.getName()));
if (profileNames.length == 0) {
return false;
}
for (int i = 0; i < profileNames.length; i++) {
try {
profileNames[i] = OptionHelper.substVars(profileNames[i], ic, this.context);
}
catch (ScanException ex) {
throw new RuntimeException(ex);
}
}
return this.environment.acceptsProfiles(Profiles.of(profileNames));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,58 +16,37 @@
package org.springframework.boot.logging.logback;
import ch.qos.logback.core.joran.action.Action;
import ch.qos.logback.core.joran.action.ActionUtil;
import ch.qos.logback.core.joran.action.ActionUtil.Scope;
import ch.qos.logback.core.joran.spi.ActionException;
import ch.qos.logback.core.joran.spi.InterpretationContext;
import ch.qos.logback.core.util.OptionHelper;
import ch.qos.logback.core.joran.action.BaseModelAction;
import ch.qos.logback.core.joran.spi.SaxEventInterpretationContext;
import ch.qos.logback.core.model.Model;
import org.xml.sax.Attributes;
import org.springframework.core.env.Environment;
/**
* Logback {@link Action} to support {@code <springProperty>} tags. Allows logback
* Logback {@link BaseModelAction} for {@code <springProperty>} tags. Allows Logback
* properties to be sourced from the Spring environment.
*
* @author Phillip Webb
* @author Eddú Meléndez
* @author Madhura Bhave
* @author Andy Wilkinson
* @see SpringPropertyModel
* @see SpringPropertyModelHandler
*/
class SpringPropertyAction extends Action {
class SpringPropertyAction extends BaseModelAction {
private static final String SOURCE_ATTRIBUTE = "source";
private static final String DEFAULT_VALUE_ATTRIBUTE = "defaultValue";
private final Environment environment;
SpringPropertyAction(Environment environment) {
this.environment = environment;
}
@Override
public void begin(InterpretationContext context, String elementName, Attributes attributes) throws ActionException {
String name = attributes.getValue(NAME_ATTRIBUTE);
String source = attributes.getValue(SOURCE_ATTRIBUTE);
Scope scope = ActionUtil.stringToScope(attributes.getValue(SCOPE_ATTRIBUTE));
String defaultValue = attributes.getValue(DEFAULT_VALUE_ATTRIBUTE);
if (OptionHelper.isEmpty(name) || OptionHelper.isEmpty(source)) {
addError("The \"name\" and \"source\" attributes of <springProperty> must be set");
}
ActionUtil.setProperty(context, name, getValue(source, defaultValue), scope);
}
private String getValue(String source, String defaultValue) {
if (this.environment == null) {
addWarn("No Spring Environment available to resolve " + source);
return defaultValue;
}
return this.environment.getProperty(source, defaultValue);
}
@Override
public void end(InterpretationContext context, String name) throws ActionException {
protected Model buildCurrentModel(SaxEventInterpretationContext interpretationContext, String name,
Attributes attributes) {
SpringPropertyModel model = new SpringPropertyModel();
model.setName(attributes.getValue(NAME_ATTRIBUTE));
model.setSource(attributes.getValue(SOURCE_ATTRIBUTE));
model.setScope(attributes.getValue(SCOPE_ATTRIBUTE));
model.setDefaultValue(attributes.getValue(DEFAULT_VALUE_ATTRIBUTE));
return model;
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.logging.logback;
import ch.qos.logback.core.model.NamedModel;
/**
* Logback {@link NamedModel model} to support {@code <springProperty>} tags. Allows
* Logback properties to be sourced from the Spring environment.
*
* @author Andy Wilkinson
* @see SpringPropertyAction
* @see SpringPropertyModelHandler
*/
class SpringPropertyModel extends NamedModel {
private String scope;
private String defaultValue;
private String source;
String getScope() {
return this.scope;
}
void setScope(String scope) {
this.scope = scope;
}
String getDefaultValue() {
return this.defaultValue;
}
void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
String getSource() {
return this.source;
}
void setSource(String source) {
this.source = source;
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.logging.logback;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.joran.action.ActionUtil;
import ch.qos.logback.core.joran.action.ActionUtil.Scope;
import ch.qos.logback.core.model.Model;
import ch.qos.logback.core.model.ModelUtil;
import ch.qos.logback.core.model.processor.ModelHandlerBase;
import ch.qos.logback.core.model.processor.ModelHandlerException;
import ch.qos.logback.core.model.processor.ModelInterpretationContext;
import ch.qos.logback.core.util.OptionHelper;
import org.springframework.core.env.Environment;
/**
* Logback {@link ModelHandlerBase model handler} to support {@code <springProperty>}
* tags. Allows Logback properties to be sourced from the Spring environment.
*
* @author Phillip Webb
* @author Eddú Meléndez
* @author Madhura Bhave
* @author Andy Wilkinson
* @see SpringPropertyAction
* @see SpringPropertyModel
*/
class SpringPropertyModelHandler extends ModelHandlerBase {
private final Environment environment;
SpringPropertyModelHandler(Context context, Environment environment) {
super(context);
this.environment = environment;
}
@Override
public void handle(ModelInterpretationContext intercon, Model model) throws ModelHandlerException {
SpringPropertyModel propertyModel = (SpringPropertyModel) model;
Scope scope = ActionUtil.stringToScope(propertyModel.getScope());
String defaultValue = propertyModel.getDefaultValue();
String source = propertyModel.getSource();
if (OptionHelper.isNullOrEmpty(propertyModel.getName()) || OptionHelper.isNullOrEmpty(source)) {
addError("The \"name\" and \"source\" attributes of <springProperty> must be set");
}
ModelUtil.setProperty(intercon, propertyModel.getName(), getValue(source, defaultValue), scope);
}
private String getValue(String source, String defaultValue) {
if (this.environment == null) {
addWarn("No Spring Environment available to resolve " + source);
return defaultValue;
}
return this.environment.getProperty(source, defaultValue);
}
}

View File

@ -41,8 +41,8 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.DefaultBootstrapContext;
import org.springframework.boot.SpringApplication;
@ -101,7 +101,7 @@ class LoggingApplicationListenerTests {
private final LoggingApplicationListener listener = new LoggingApplicationListener();
private final LoggerContext loggerContext = (LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory();
private final LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
private final ch.qos.logback.classic.Logger logger = this.loggerContext.getLogger(getClass());

View File

@ -43,8 +43,8 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.boot.logging.AbstractLoggingSystemTests;
@ -103,7 +103,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
System.getProperties().remove(LoggingSystemProperties.FILE_LOG_CHARSET);
this.systemPropertyNames = new HashSet<>(System.getProperties().keySet());
this.loggingSystem.cleanUp();
this.logger = ((LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory()).getLogger(getClass());
this.logger = ((LoggerContext) LoggerFactory.getILoggerFactory()).getLogger(getClass());
this.environment = new MockEnvironment();
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
this.environment.setConversionService((ConfigurableConversionService) conversionService);
@ -114,7 +114,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
void cleanUp() {
System.getProperties().keySet().retainAll(this.systemPropertyNames);
this.loggingSystem.cleanUp();
((LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory()).stop();
((LoggerContext) LoggerFactory.getILoggerFactory()).stop();
}
@Test
@ -243,7 +243,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
void getLoggingConfigurationForALL() {
this.loggingSystem.beforeInitialize();
initialize(this.initializationContext, null, null);
Logger logger = (Logger) StaticLoggerBinder.getSingleton().getLoggerFactory().getLogger(getClass().getName());
Logger logger = (Logger) LoggerFactory.getILoggerFactory().getLogger(getClass().getName());
logger.setLevel(Level.ALL);
LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(getClass().getName());
assertThat(configuration)
@ -255,7 +255,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
this.loggingSystem.beforeInitialize();
initialize(this.initializationContext, null, null);
this.loggingSystem.setLogLevel(getClass().getName(), LogLevel.TRACE);
Logger logger = (Logger) StaticLoggerBinder.getSingleton().getLoggerFactory().getLogger(getClass().getName());
Logger logger = (Logger) LoggerFactory.getILoggerFactory().getLogger(getClass().getName());
assertThat(logger.getLevel()).isEqualTo(Level.TRACE);
}
@ -516,9 +516,9 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
this.environment.setProperty("logging.logback.rollingpolicy.max-history", "20");
this.loggingSystem.beforeInitialize();
initialize(this.initializationContext, null, null);
LoggerContext loggerContext = (LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory();
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
Map<String, String> properties = loggerContext.getCopyOfPropertyMap();
Set<String> expectedProperties = new HashSet<String>();
Set<String> expectedProperties = new HashSet<>();
ReflectionUtils.doWithFields(LogbackLoggingSystemProperties.class,
(field) -> expectedProperties.add((String) field.get(null)), this::isPublicStaticFinal);
expectedProperties.removeAll(Arrays.asList("LOG_FILE", "LOG_PATH"));
@ -533,7 +533,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void initializationIsOnlyPerformedOnceUntilCleanedUp() {
LoggerContext loggerContext = (LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory();
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
LoggerContextListener listener = mock(LoggerContextListener.class);
loggerContext.addListener(listener);
this.loggingSystem.beforeInitialize();
@ -635,7 +635,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
}
private static Logger getRootLogger() {
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
ILoggerFactory factory = LoggerFactory.getILoggerFactory();
LoggerContext context = (LoggerContext) factory;
return context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -26,7 +26,6 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.logging.LoggingInitializationContext;
@ -65,8 +64,7 @@ class SpringBootJoranConfiguratorTests {
this.environment = new MockEnvironment();
this.initializationContext = new LoggingInitializationContext(this.environment);
this.configurator = new SpringBootJoranConfigurator(this.initializationContext);
StaticLoggerBinder binder = StaticLoggerBinder.getSingleton();
this.context = (LoggerContext) binder.getLoggerFactory();
this.context = (LoggerContext) LoggerFactory.getILoggerFactory();
this.logger = this.context.getLogger(getClass());
}

View File

@ -21,38 +21,34 @@ import java.util.List;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.ContextBase;
import ch.qos.logback.core.joran.action.Action;
import ch.qos.logback.core.joran.spi.ActionException;
import ch.qos.logback.core.joran.spi.InterpretationContext;
import ch.qos.logback.core.model.processor.ModelHandlerException;
import ch.qos.logback.core.model.processor.ModelInterpretationContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.xml.sax.Attributes;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link SpringProfileAction}.
* Tests for {@link SpringProfileModelHandler}.
*
* @author Andy Wilkinson
*/
class SpringProfileActionTests {
class SpringProfileModelHandlerTests {
private final Environment environment = mock(Environment.class);
private final SpringProfileAction action = new SpringProfileAction(this.environment);
private final Context context = new ContextBase();
private final InterpretationContext interpretationContext = new InterpretationContext(this.context, null);
private final SpringProfileModelHandler action = new SpringProfileModelHandler(this.context, this.environment);
private final Attributes attributes = mock(Attributes.class);
private final ModelInterpretationContext interpretationContext = new ModelInterpretationContext(this.context);
@BeforeEach
void setUp() {
@ -60,9 +56,10 @@ class SpringProfileActionTests {
}
@Test
void environmentIsQueriedWithProfileFromNameAttribute() throws ActionException {
given(this.attributes.getValue(Action.NAME_ATTRIBUTE)).willReturn("dev");
this.action.begin(this.interpretationContext, null, this.attributes);
void environmentIsQueriedWithProfileFromModelName() throws ActionException, ModelHandlerException {
SpringProfileModel model = new SpringProfileModel();
model.setName("dev");
this.action.handle(this.interpretationContext, model);
ArgumentCaptor<Profiles> profiles = ArgumentCaptor.forClass(Profiles.class);
then(this.environment).should().acceptsProfiles(profiles.capture());
List<String> profileNames = new ArrayList<>();
@ -74,9 +71,10 @@ class SpringProfileActionTests {
}
@Test
void environmentIsQueriedWithMultipleProfilesFromCommaSeparatedNameAttribute() throws ActionException {
given(this.attributes.getValue(Action.NAME_ATTRIBUTE)).willReturn("dev,qa");
this.action.begin(this.interpretationContext, null, this.attributes);
void environmentIsQueriedWithMultipleProfilesFromCommaSeparatedModelName() throws ModelHandlerException {
SpringProfileModel model = new SpringProfileModel();
model.setName("dev,qa");
this.action.handle(this.interpretationContext, model);
ArgumentCaptor<Profiles> profiles = ArgumentCaptor.forClass(Profiles.class);
then(this.environment).should().acceptsProfiles(profiles.capture());
List<String> profileNames = new ArrayList<>();
@ -88,10 +86,11 @@ class SpringProfileActionTests {
}
@Test
void environmentIsQueriedWithResolvedValueWhenNameAttributeUsesAPlaceholder() throws ActionException {
given(this.attributes.getValue(Action.NAME_ATTRIBUTE)).willReturn("${profile}");
void environmentIsQueriedWithResolvedValueWhenModelNameUsesAPlaceholder() throws ModelHandlerException {
SpringProfileModel model = new SpringProfileModel();
model.setName("${profile}");
this.context.putProperty("profile", "dev");
this.action.begin(this.interpretationContext, null, this.attributes);
this.action.handle(this.interpretationContext, model);
ArgumentCaptor<Profiles> profiles = ArgumentCaptor.forClass(Profiles.class);
then(this.environment).should().acceptsProfiles(profiles.capture());
List<String> profileNames = new ArrayList<>();
@ -104,11 +103,12 @@ class SpringProfileActionTests {
@Test
void environmentIsQueriedWithResolvedValuesFromCommaSeparatedNameNameAttributeWithPlaceholders()
throws ActionException {
given(this.attributes.getValue(Action.NAME_ATTRIBUTE)).willReturn("${profile1},${profile2}");
throws ModelHandlerException {
SpringProfileModel model = new SpringProfileModel();
model.setName("${profile1},${profile2}");
this.context.putProperty("profile1", "dev");
this.context.putProperty("profile2", "qa");
this.action.begin(this.interpretationContext, null, this.attributes);
this.action.handle(this.interpretationContext, model);
ArgumentCaptor<Profiles> profiles = ArgumentCaptor.forClass(Profiles.class);
then(this.environment).should().acceptsProfiles(profiles.capture());
List<String> profileNames = new ArrayList<>();

View File

@ -3,6 +3,12 @@
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<suppress files="ConditionEvaluationReportLoggingListenerTests\.java" checks="IllegalImport" />
<suppress files="LoggingApplicationListenerTests\.java" checks="IllegalImport" />
<suppress files="LogbackInitializer\.java" checks="IllegalImport" />
<suppress files="LogbackLoggingSystem\.java" checks="IllegalImport" />
<suppress files="LogbackLoggingSystemTests\.java" checks="IllegalImport" />
<suppress files="MeterRegistryConfigurerIntegrationTests\.java" checks="IllegalImport" />
<suppress files="SpringApplicationTests\.java" checks="FinalClass" />
<suppress files=".+Configuration\.java" checks="HideUtilityClassConstructor" />
<suppress files=".+Application\.java" checks="HideUtilityClassConstructor" />