Allow JoranConfigurators to be passed ahead of time in logback
See gh-33643
This commit is contained in:
parent
e5bc9a2fcb
commit
4f17a9cc9d
|
@ -20,6 +20,8 @@ import java.net.URL;
|
|||
import java.security.CodeSource;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.ConsoleHandler;
|
||||
|
@ -83,6 +85,8 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanF
|
|||
|
||||
private static final LogLevels<Level> LEVELS = new LogLevels<>();
|
||||
|
||||
private Collection<JoranConfigurator> configurators = Collections.emptyList();
|
||||
|
||||
static {
|
||||
LEVELS.map(LogLevel.TRACE, Level.TRACE);
|
||||
LEVELS.map(LogLevel.TRACE, Level.ALL);
|
||||
|
@ -184,7 +188,7 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanF
|
|||
if (isAlreadyInitialized(loggerContext)) {
|
||||
return;
|
||||
}
|
||||
if (!initializeFromAotGeneratedArtifactsIfPossible(initializationContext, logFile)) {
|
||||
if (!initializeFromAotGeneratedArtifactsIfPossible(initializationContext, this.configurators, logFile)) {
|
||||
super.initialize(initializationContext, configLocation, logFile);
|
||||
}
|
||||
loggerContext.getTurboFilterList().remove(FILTER);
|
||||
|
@ -196,7 +200,7 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanF
|
|||
}
|
||||
|
||||
private boolean initializeFromAotGeneratedArtifactsIfPossible(LoggingInitializationContext initializationContext,
|
||||
LogFile logFile) {
|
||||
Collection<JoranConfigurator> configurators, LogFile logFile) {
|
||||
if (!AotDetector.useGeneratedArtifacts()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -205,7 +209,8 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanF
|
|||
}
|
||||
LoggerContext loggerContext = getLoggerContext();
|
||||
stopAndReset(loggerContext);
|
||||
SpringBootJoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext);
|
||||
SpringBootJoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext,
|
||||
configurators);
|
||||
configurator.setContext(loggerContext);
|
||||
return configurator.configureUsingAotGeneratedArtifacts();
|
||||
}
|
||||
|
@ -260,7 +265,7 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanF
|
|||
private void configureByResourceUrl(LoggingInitializationContext initializationContext, LoggerContext loggerContext,
|
||||
URL url) throws JoranException {
|
||||
if (url.toString().endsWith("xml")) {
|
||||
JoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext);
|
||||
JoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext, this.configurators);
|
||||
configurator.setContext(loggerContext);
|
||||
configurator.doConfigure(url);
|
||||
}
|
||||
|
@ -415,6 +420,8 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanF
|
|||
BeanFactoryInitializationAotContribution contribution = (BeanFactoryInitializationAotContribution) context
|
||||
.getObject(key);
|
||||
context.removeObject(key);
|
||||
this.configurators = beanFactory.getBeansOfType(JoranConfigurator.class).values();
|
||||
this.configurators.forEach((configurator) -> configurator.setContext(context));
|
||||
return contribution;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.io.Serializable;
|
|||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
@ -78,8 +79,16 @@ class SpringBootJoranConfigurator extends JoranConfigurator {
|
|||
|
||||
private final LoggingInitializationContext initializationContext;
|
||||
|
||||
private final Collection<JoranConfigurator> configurators;
|
||||
|
||||
SpringBootJoranConfigurator(LoggingInitializationContext initializationContext) {
|
||||
this(initializationContext, Collections.emptyList());
|
||||
}
|
||||
|
||||
SpringBootJoranConfigurator(LoggingInitializationContext initializationContext,
|
||||
Collection<JoranConfigurator> configurators) {
|
||||
this.initializationContext = initializationContext;
|
||||
this.configurators = configurators;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,6 +114,7 @@ class SpringBootJoranConfigurator extends JoranConfigurator {
|
|||
ruleStore.addRule(new ElementSelector("configuration/springProperty"), SpringPropertyAction::new);
|
||||
ruleStore.addRule(new ElementSelector("*/springProfile"), SpringProfileAction::new);
|
||||
ruleStore.addTransparentPathPart("springProfile");
|
||||
this.configurators.forEach((configurator) -> configurator.addElementSelectorAndActionAssociations(ruleStore));
|
||||
}
|
||||
|
||||
boolean configureUsingAotGeneratedArtifacts() {
|
||||
|
@ -124,6 +134,7 @@ class SpringBootJoranConfigurator extends JoranConfigurator {
|
|||
getContext().putObject(BeanFactoryInitializationAotContribution.class.getName(),
|
||||
new LogbackConfigurationAotContribution(model, getModelInterpretationContext(), getContext()));
|
||||
}
|
||||
this.configurators.forEach((configurator) -> configurator.processModel(model));
|
||||
}
|
||||
|
||||
private boolean isAotProcessingInProgress() {
|
||||
|
|
|
@ -33,9 +33,14 @@ import java.util.logging.LogManager;
|
|||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.joran.JoranConfigurator;
|
||||
import ch.qos.logback.classic.spi.LoggerContextListener;
|
||||
import ch.qos.logback.core.ConsoleAppender;
|
||||
import ch.qos.logback.core.encoder.LayoutWrappingEncoder;
|
||||
import ch.qos.logback.core.joran.action.Action;
|
||||
import ch.qos.logback.core.joran.spi.ElementSelector;
|
||||
import ch.qos.logback.core.joran.spi.RuleStore;
|
||||
import ch.qos.logback.core.joran.spi.SaxEventInterpretationContext;
|
||||
import ch.qos.logback.core.rolling.RollingFileAppender;
|
||||
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
|
||||
import ch.qos.logback.core.util.StatusPrinter;
|
||||
|
@ -46,8 +51,10 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.bridge.SLF4JBridgeHandler;
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.boot.convert.ApplicationConversionService;
|
||||
import org.springframework.boot.logging.AbstractLoggingSystemTests;
|
||||
import org.springframework.boot.logging.LogFile;
|
||||
|
@ -651,7 +658,8 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
|
|||
|
||||
@Test
|
||||
void whenContextHasNoAotContributionThenProcessAheadOfTimeReturnsNull() {
|
||||
BeanFactoryInitializationAotContribution contribution = this.loggingSystem.processAheadOfTime(null);
|
||||
BeanFactoryInitializationAotContribution contribution = this.loggingSystem
|
||||
.processAheadOfTime(new DefaultListableBeanFactory());
|
||||
assertThat(contribution).isNull();
|
||||
}
|
||||
|
||||
|
@ -660,11 +668,48 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
|
|||
LoggerContext context = ((LoggerContext) LoggerFactory.getILoggerFactory());
|
||||
context.putObject(BeanFactoryInitializationAotContribution.class.getName(),
|
||||
mock(BeanFactoryInitializationAotContribution.class));
|
||||
BeanFactoryInitializationAotContribution contribution = this.loggingSystem.processAheadOfTime(null);
|
||||
BeanFactoryInitializationAotContribution contribution = this.loggingSystem
|
||||
.processAheadOfTime(new DefaultListableBeanFactory());
|
||||
assertThat(context.getObject(BeanFactoryInitializationAotContribution.class.getName())).isNull();
|
||||
assertThat(contribution).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenContextHasConfiguratorsThenInitializeExecutesThem(CapturedOutput output) {
|
||||
LoggerContext context = ((LoggerContext) LoggerFactory.getILoggerFactory());
|
||||
context.putObject(BeanFactoryInitializationAotContribution.class.getName(),
|
||||
mock(BeanFactoryInitializationAotContribution.class));
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
beanFactory.registerSingleton("joranConfigurator1", new JoranConfigurator() {
|
||||
@Override
|
||||
public void addElementSelectorAndActionAssociations(RuleStore ruleStore) {
|
||||
ruleStore.addRule(new ElementSelector("*/rule1"), () -> new Action() {
|
||||
@Override
|
||||
public void begin(SaxEventInterpretationContext intercon, String name, Attributes attributes) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(SaxEventInterpretationContext intercon, String name) {
|
||||
}
|
||||
});
|
||||
ruleStore.addRule(new ElementSelector("*/rule2"), () -> new Action() {
|
||||
@Override
|
||||
public void begin(SaxEventInterpretationContext intercon, String name, Attributes attributes) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(SaxEventInterpretationContext intercon, String name) {
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
this.loggingSystem.processAheadOfTime(beanFactory);
|
||||
this.loggingSystem.beforeInitialize();
|
||||
initialize(this.initializationContext, "classpath:logback-custom-rules.xml", null);
|
||||
assertThat(output).doesNotContain("Ignoring unknown property [rule1] in [ch.qos.logback.classic.LoggerContext]")
|
||||
.doesNotContain("Ignoring unknown property [rule2] in [ch.qos.logback.classic.LoggerContext]");
|
||||
}
|
||||
|
||||
@Test // gh-33610
|
||||
void springProfileIfNestedWithinSecondPhaseElementSanityChecker(CapturedOutput output) {
|
||||
this.loggingSystem.beforeInitialize();
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%property{LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<rule1/>
|
||||
<rule2/>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
</root>
|
||||
</configuration>
|
Loading…
Reference in New Issue