mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
Upgrade to Logback 1.4 and SLF4J 2.0
Closes gh-12649
This commit is contained in:
parent
05d2f3cc8e
commit
0bfa9cd704
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 "
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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<>();
|
@ -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" />
|
||||
|
Loading…
Reference in New Issue
Block a user