Skip to content

Commit 0bfa9cd

Browse files
committed
Upgrade to Logback 1.4 and SLF4J 2.0
Closes gh-12649
1 parent 05d2f3c commit 0bfa9cd

File tree

19 files changed

+355
-190
lines changed

19 files changed

+355
-190
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryConfigurerIntegrationTests.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
2424
import io.micrometer.core.instrument.binder.MeterBinder;
2525
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
2626
import org.junit.jupiter.api.Test;
27-
import org.slf4j.impl.StaticLoggerBinder;
27+
import org.slf4j.LoggerFactory;
2828

2929
import org.springframework.beans.factory.config.BeanPostProcessor;
3030
import org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasMetricsExportAutoConfiguration;
@@ -76,8 +76,7 @@ void customizersAreAppliedBeforeBindersAreCreated() {
7676
void counterIsIncrementedOncePerEventWithoutCompositeMeterRegistry() {
7777
new ApplicationContextRunner().with(MetricsRun.limitedTo(JmxMetricsExportAutoConfiguration.class))
7878
.withConfiguration(AutoConfigurations.of(LogbackMetricsAutoConfiguration.class)).run((context) -> {
79-
Logger logger = ((LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory())
80-
.getLogger("test-logger");
79+
Logger logger = ((LoggerContext) LoggerFactory.getILoggerFactory()).getLogger("test-logger");
8180
logger.error("Error.");
8281
Map<String, MeterRegistry> registriesByName = context.getBeansOfType(MeterRegistry.class);
8382
assertThat(registriesByName).hasSize(1);
@@ -92,8 +91,7 @@ void counterIsIncrementedOncePerEventWithCompositeMeterRegistry() {
9291
.with(MetricsRun.limitedTo(JmxMetricsExportAutoConfiguration.class,
9392
PrometheusMetricsExportAutoConfiguration.class))
9493
.withConfiguration(AutoConfigurations.of(LogbackMetricsAutoConfiguration.class)).run((context) -> {
95-
Logger logger = ((LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory())
96-
.getLogger("test-logger");
94+
Logger logger = ((LoggerContext) LoggerFactory.getILoggerFactory()).getLogger("test-logger");
9795
logger.error("Error.");
9896
Map<String, MeterRegistry> registriesByName = context.getBeansOfType(MeterRegistry.class);
9997
assertThat(registriesByName).hasSize(3);

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/logging/ConditionEvaluationReportLoggingListenerTests.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import ch.qos.logback.classic.LoggerContext;
2424
import org.junit.jupiter.api.Test;
2525
import org.junit.jupiter.api.extension.ExtendWith;
26-
import org.slf4j.impl.StaticLoggerBinder;
26+
import org.slf4j.LoggerFactory;
2727

2828
import org.springframework.boot.SpringApplication;
2929
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
@@ -147,8 +147,8 @@ void noErrorIfNotInitialized(CapturedOutput output) {
147147
}
148148

149149
private void withDebugLogging(Runnable runnable) {
150-
LoggerContext context = (LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory();
151-
Logger logger = context.getLogger(ConditionEvaluationReportLoggingListener.class);
150+
Logger logger = ((LoggerContext) LoggerFactory.getILoggerFactory())
151+
.getLogger(ConditionEvaluationReportLoggingListener.class);
152152
Level currentLevel = logger.getLevel();
153153
logger.setLevel(Level.DEBUG);
154154
try {

spring-boot-project/spring-boot-dependencies/build.gradle

+4-2
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ bom {
863863
]
864864
}
865865
}
866-
library("Logback", "1.2.11") {
866+
library("Logback", "1.4.1") {
867867
group("ch.qos.logback") {
868868
modules = [
869869
"logback-access",
@@ -1366,7 +1366,7 @@ bom {
13661366
]
13671367
}
13681368
}
1369-
library("SLF4J", "1.7.36") {
1369+
library("SLF4J", "2.0.2") {
13701370
group("org.slf4j") {
13711371
modules = [
13721372
"jcl-over-slf4j",
@@ -1375,9 +1375,11 @@ bom {
13751375
"slf4j-api",
13761376
"slf4j-ext",
13771377
"slf4j-jcl",
1378+
"slf4j-jdk-platform-logging",
13781379
"slf4j-jdk14",
13791380
"slf4j-log4j12",
13801381
"slf4j-nop",
1382+
"slf4j-reload4j",
13811383
"slf4j-simple"
13821384
]
13831385
}

spring-boot-project/spring-boot-starters/spring-boot-starter-log4j2/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ plugins {
55
description = "Starter for using Log4j2 for logging. An alternative to spring-boot-starter-logging"
66

77
dependencies {
8-
api("org.apache.logging.log4j:log4j-slf4j-impl")
8+
api("org.apache.logging.log4j:log4j-slf4j2-impl")
99
api("org.apache.logging.log4j:log4j-core")
1010
api("org.apache.logging.log4j:log4j-jul")
1111
}

spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LogbackInitializer.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import ch.qos.logback.classic.Level;
2020
import org.slf4j.ILoggerFactory;
2121
import org.slf4j.Logger;
22-
import org.slf4j.impl.StaticLoggerBinder;
22+
import org.slf4j.LoggerFactory;
2323

2424
import org.springframework.util.ClassUtils;
2525

@@ -32,7 +32,7 @@
3232
public abstract class LogbackInitializer {
3333

3434
public static void initialize() {
35-
if (ClassUtils.isPresent("org.slf4j.impl.StaticLoggerBinder", null)
35+
if (ClassUtils.isPresent("org.slf4j.LoggerFactory", null)
3636
&& ClassUtils.isPresent("ch.qos.logback.classic.Logger", null)) {
3737
new Initializer().setRootLogLevel();
3838
}
@@ -41,7 +41,7 @@ public static void initialize() {
4141
private static class Initializer {
4242

4343
void setRootLogLevel() {
44-
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
44+
ILoggerFactory factory = LoggerFactory.getILoggerFactory();
4545
Logger logger = factory.getLogger(Logger.ROOT_LOGGER_NAME);
4646
((ch.qos.logback.classic.Logger) logger).setLevel(Level.INFO);
4747
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import ch.qos.logback.core.ConsoleAppender;
2626
import ch.qos.logback.core.rolling.RollingFileAppender;
2727
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
28+
import ch.qos.logback.core.spi.ScanException;
2829
import ch.qos.logback.core.util.FileSize;
2930
import ch.qos.logback.core.util.OptionHelper;
3031

@@ -146,7 +147,12 @@ private Charset resolveCharset(LogbackConfigurator config, String val) {
146147
}
147148

148149
private String resolve(LogbackConfigurator config, String val) {
149-
return OptionHelper.substVars(val, config.getContext());
150+
try {
151+
return OptionHelper.substVars(val, config.getContext());
152+
}
153+
catch (ScanException ex) {
154+
throw new RuntimeException(ex);
155+
}
150156
}
151157

152158
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@
3939
import ch.qos.logback.core.util.StatusListenerConfigHelper;
4040
import org.slf4j.ILoggerFactory;
4141
import org.slf4j.Logger;
42+
import org.slf4j.LoggerFactory;
4243
import org.slf4j.Marker;
4344
import org.slf4j.bridge.SLF4JBridgeHandler;
44-
import org.slf4j.impl.StaticLoggerBinder;
4545

4646
import org.springframework.boot.logging.AbstractLoggingSystem;
4747
import org.springframework.boot.logging.LogFile;
@@ -348,7 +348,7 @@ private ch.qos.logback.classic.Logger getLogger(String name) {
348348
}
349349

350350
private LoggerContext getLoggerContext() {
351-
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
351+
ILoggerFactory factory = LoggerFactory.getILoggerFactory();
352352
Assert.isInstanceOf(LoggerContext.class, factory,
353353
() -> String.format(
354354
"LoggerFactory is not a Logback LoggerContext but Logback is on "

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringBootJoranConfigurator.java

+19-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,18 +17,18 @@
1717
package org.springframework.boot.logging.logback;
1818

1919
import ch.qos.logback.classic.joran.JoranConfigurator;
20-
import ch.qos.logback.core.joran.action.NOPAction;
2120
import ch.qos.logback.core.joran.spi.ElementSelector;
2221
import ch.qos.logback.core.joran.spi.RuleStore;
22+
import ch.qos.logback.core.model.processor.DefaultProcessor;
2323

2424
import org.springframework.boot.logging.LoggingInitializationContext;
25-
import org.springframework.core.env.Environment;
2625

2726
/**
2827
* Extended version of the Logback {@link JoranConfigurator} that adds additional Spring
2928
* Boot rules.
3029
*
3130
* @author Phillip Webb
31+
* @author Andy Wilkinson
3232
*/
3333
class SpringBootJoranConfigurator extends JoranConfigurator {
3434

@@ -39,12 +39,22 @@ class SpringBootJoranConfigurator extends JoranConfigurator {
3939
}
4040

4141
@Override
42-
public void addInstanceRules(RuleStore rs) {
43-
super.addInstanceRules(rs);
44-
Environment environment = this.initializationContext.getEnvironment();
45-
rs.addRule(new ElementSelector("configuration/springProperty"), new SpringPropertyAction(environment));
46-
rs.addRule(new ElementSelector("*/springProfile"), new SpringProfileAction(environment));
47-
rs.addRule(new ElementSelector("*/springProfile/*"), new NOPAction());
42+
protected void addModelHandlerAssociations(DefaultProcessor defaultProcessor) {
43+
super.addModelHandlerAssociations(defaultProcessor);
44+
defaultProcessor.addHandler(SpringPropertyModel.class,
45+
(handlerContext, handlerMic) -> new SpringPropertyModelHandler(this.context,
46+
this.initializationContext.getEnvironment()));
47+
defaultProcessor.addHandler(SpringProfileModel.class,
48+
(handlerContext, handlerMic) -> new SpringProfileModelHandler(this.context,
49+
this.initializationContext.getEnvironment()));
50+
}
51+
52+
@Override
53+
public void addElementSelectorAndActionAssociations(RuleStore ruleStore) {
54+
super.addElementSelectorAndActionAssociations(ruleStore);
55+
ruleStore.addRule(new ElementSelector("configuration/springProperty"), SpringPropertyAction::new);
56+
ruleStore.addRule(new ElementSelector("*/springProfile"), SpringProfileAction::new);
57+
ruleStore.addTransparentPathPart("springProfile");
4858
}
4959

5060
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,102 +16,29 @@
1616

1717
package org.springframework.boot.logging.logback;
1818

19-
import java.util.ArrayList;
20-
import java.util.List;
21-
22-
import ch.qos.logback.core.joran.action.Action;
23-
import ch.qos.logback.core.joran.event.InPlayListener;
24-
import ch.qos.logback.core.joran.event.SaxEvent;
25-
import ch.qos.logback.core.joran.spi.ActionException;
26-
import ch.qos.logback.core.joran.spi.InterpretationContext;
27-
import ch.qos.logback.core.joran.spi.Interpreter;
28-
import ch.qos.logback.core.util.OptionHelper;
19+
import ch.qos.logback.core.joran.action.BaseModelAction;
20+
import ch.qos.logback.core.joran.spi.SaxEventInterpretationContext;
21+
import ch.qos.logback.core.model.Model;
2922
import org.xml.sax.Attributes;
3023

31-
import org.springframework.core.env.Environment;
32-
import org.springframework.core.env.Profiles;
33-
import org.springframework.util.Assert;
34-
import org.springframework.util.StringUtils;
35-
3624
/**
37-
* Logback {@link Action} to support {@code <springProfile>} tags. Allows section of a
38-
* logback configuration to only be enabled when a specific profile is active.
25+
* Logback {@link BaseModelAction} for {@code <springProperty>} tags. Allows a section of
26+
* a Logback configuration to only be enabled when a specific profile is active.
3927
*
4028
* @author Phillip Webb
4129
* @author Eddú Meléndez
30+
* @author Andy Wilkinson
31+
* @see SpringProfileModel
32+
* @see SpringProfileModelHandler
4233
*/
43-
class SpringProfileAction extends Action implements InPlayListener {
44-
45-
private final Environment environment;
46-
47-
private int depth = 0;
48-
49-
private boolean acceptsProfile;
50-
51-
private List<SaxEvent> events;
52-
53-
SpringProfileAction(Environment environment) {
54-
this.environment = environment;
55-
}
56-
57-
@Override
58-
public void begin(InterpretationContext ic, String name, Attributes attributes) throws ActionException {
59-
this.depth++;
60-
if (this.depth != 1) {
61-
return;
62-
}
63-
ic.pushObject(this);
64-
this.acceptsProfile = acceptsProfiles(ic, attributes);
65-
this.events = new ArrayList<>();
66-
ic.addInPlayListener(this);
67-
}
68-
69-
private boolean acceptsProfiles(InterpretationContext ic, Attributes attributes) {
70-
if (this.environment == null) {
71-
return false;
72-
}
73-
String[] profileNames = StringUtils
74-
.trimArrayElements(StringUtils.commaDelimitedListToStringArray(attributes.getValue(NAME_ATTRIBUTE)));
75-
if (profileNames.length == 0) {
76-
return false;
77-
}
78-
for (int i = 0; i < profileNames.length; i++) {
79-
profileNames[i] = OptionHelper.substVars(profileNames[i], ic, this.context);
80-
}
81-
return this.environment.acceptsProfiles(Profiles.of(profileNames));
82-
}
83-
84-
@Override
85-
public void end(InterpretationContext ic, String name) throws ActionException {
86-
this.depth--;
87-
if (this.depth != 0) {
88-
return;
89-
}
90-
ic.removeInPlayListener(this);
91-
verifyAndPop(ic);
92-
if (this.acceptsProfile) {
93-
addEventsToPlayer(ic);
94-
}
95-
}
96-
97-
private void verifyAndPop(InterpretationContext ic) {
98-
Object o = ic.peekObject();
99-
Assert.state(o != null, "Unexpected null object on stack");
100-
Assert.isInstanceOf(SpringProfileAction.class, o, "logback stack error");
101-
Assert.state(o == this, "ProfileAction different than current one on stack");
102-
ic.popObject();
103-
}
104-
105-
private void addEventsToPlayer(InterpretationContext ic) {
106-
Interpreter interpreter = ic.getJoranInterpreter();
107-
this.events.remove(0);
108-
this.events.remove(this.events.size() - 1);
109-
interpreter.getEventPlayer().addEventsDynamically(this.events, 1);
110-
}
34+
class SpringProfileAction extends BaseModelAction {
11135

11236
@Override
113-
public void inPlay(SaxEvent event) {
114-
this.events.add(event);
37+
protected Model buildCurrentModel(SaxEventInterpretationContext interpretationContext, String name,
38+
Attributes attributes) {
39+
SpringProfileModel model = new SpringProfileModel();
40+
model.setName(attributes.getValue(NAME_ATTRIBUTE));
41+
return model;
11542
}
11643

11744
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.logging.logback;
18+
19+
import ch.qos.logback.core.model.NamedModel;
20+
21+
/**
22+
* Logback {@link NamedModel model} to support {@code <springProfile>} tags.
23+
*
24+
* @author Andy Wilkinson
25+
* @see SpringProfileAction
26+
* @see SpringProfileModelHandler
27+
*/
28+
class SpringProfileModel extends NamedModel {
29+
30+
}

0 commit comments

Comments
 (0)