Commit f3f562f3 authored by Phillip Webb's avatar Phillip Webb

Support <springProfile> in logback configurations

Include support for a new <springProfile> element which can be used in
`logback-spring.xml` files to selectively enable or disable parts of the
configuration. For example:

	<configuration>
		...
		<springProfile name="staging">
			<logger name="sample.logback" level="TRACE" />
		</springProfile>
		...
	</configuration>

Fixes gh-3338
parent 5bc8f0f7
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="sample.logback" level="DEBUG"/>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="sample.logback" level="DEBUG" />
<springProfile name="staging">
<logger name="sample.logback" level="TRACE" />
</springProfile>
</configuration>
......@@ -35,4 +35,12 @@ public class SampleLogbackApplicationTests {
this.outputCapture.expect(not(containsString("Sample Trace Message")));
}
@Test
public void testProfile() throws Exception {
SampleLogbackApplication
.main(new String[] { "--spring.profiles.active=staging" });
this.outputCapture.expect(containsString("Sample Debug Message"));
this.outputCapture.expect(containsString("Sample Trace Message"));
}
}
......@@ -40,31 +40,35 @@ public abstract class AbstractLoggingSystem extends LoggingSystem {
}
@Override
public void initialize(String configLocation, LogFile logFile) {
public void initialize(LoggingInitializationContext initializationContext,
String configLocation, LogFile logFile) {
if (StringUtils.hasLength(configLocation)) {
initializeWithSpecificConfig(configLocation, logFile);
initializeWithSpecificConfig(initializationContext, configLocation, logFile);
return;
}
initializeWithConventions(logFile);
initializeWithConventions(initializationContext, logFile);
}
private void initializeWithSpecificConfig(String configLocation, LogFile logFile) {
private void initializeWithSpecificConfig(
LoggingInitializationContext initializationContext, String configLocation,
LogFile logFile) {
configLocation = SystemPropertyUtils.resolvePlaceholders(configLocation);
loadConfiguration(configLocation, logFile);
loadConfiguration(initializationContext, configLocation, logFile);
}
private void initializeWithConventions(LogFile logFile) {
private void initializeWithConventions(
LoggingInitializationContext initializationContext, LogFile logFile) {
String config = getSelfInitializationConfig();
if (config != null && logFile == null) {
// self initialization has occurred, reinitialize in case of property changes
reinitialize();
reinitialize(initializationContext);
return;
}
if (config == null) {
config = getSpringInitializationConfig();
}
if (config != null) {
loadConfiguration(config, logFile);
loadConfiguration(initializationContext, config, logFile);
return;
}
loadDefaults(logFile);
......@@ -131,18 +135,22 @@ public abstract class AbstractLoggingSystem extends LoggingSystem {
/**
* Load a specific configuration.
* @param initializationContext the logging initialization context
* @param location the location of the configuration to load (never {@code null})
* @param logFile the file to load or {@code null} if no log file is to be written
*/
protected abstract void loadConfiguration(String location, LogFile logFile);
protected abstract void loadConfiguration(
LoggingInitializationContext initializationContext, String location,
LogFile logFile);
/**
* Reinitialize the logging system if required. Called when
* {@link #getSelfInitializationConfig()} is used and the log file hasn't changed. May
* be used to reload configuration (for example to pickup additional System
* properties).
* @param initializationContext the logging initialization context
*/
protected void reinitialize() {
protected void reinitialize(LoggingInitializationContext initializationContext) {
}
protected final ClassLoader getClassLoader() {
......
......@@ -198,12 +198,14 @@ public class LoggingApplicationListener implements GenericApplicationListener {
private void initializeSystem(ConfigurableEnvironment environment,
LoggingSystem system) {
LoggingInitializationContext initializationContext = new LoggingInitializationContext(
environment);
LogFile logFile = LogFile.get(environment);
String logConfig = environment.getProperty(CONFIG_PROPERTY);
if (StringUtils.hasLength(logConfig)) {
try {
ResourceUtils.getURL(logConfig).openStream().close();
system.initialize(logConfig, logFile);
system.initialize(initializationContext, logConfig, logFile);
}
catch (Exception ex) {
// NOTE: We can't use the logger here to report the problem
......@@ -214,7 +216,7 @@ public class LoggingApplicationListener implements GenericApplicationListener {
}
}
else {
system.initialize(null, logFile);
system.initialize(initializationContext, null, logFile);
}
}
......
/*
* Copyright 2012-2015 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
*
* http://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;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
/**
* Context passed to the {@link LoggingSystem} during initialization.
*
* @author Phillip Webb
* @since 1.3.0
*/
public class LoggingInitializationContext {
private final ConfigurableEnvironment environment;
/**
* Create a new {@link LoggingInitializationContext} instance.
* @param environment the Spring environment.
*/
public LoggingInitializationContext(ConfigurableEnvironment environment) {
this.environment = environment;
}
/**
* Return the Spring environment if available.
* @return the {@link Environment} or {@code null}
*/
public Environment getEnvironment() {
return this.environment;
}
}
......@@ -53,19 +53,21 @@ public abstract class LoggingSystem {
/**
* Reset the logging system to be limit output. This method may be called before
* {@link #initialize(String, LogFile)} to reduce logging noise until the system has
* been fully Initialized.
* {@link #initialize(LoggingInitializationContext, String, LogFile)} to reduce
* logging noise until the system has been fully Initialized.
*/
public abstract void beforeInitialize();
/**
* Fully initialize the logging system.
* @param initializationContext the logging initialization context
* @param configLocation a log configuration location or {@code null} if default
* initialization is required
* @param logFile the log output file that should be written or {@code null} for
* console only output
*/
public abstract void initialize(String configLocation, LogFile logFile);
public abstract void initialize(LoggingInitializationContext initializationContext,
String configLocation, LogFile logFile);
/**
* Clean up the logging system. The default implementation does nothing. Subclasses
......
......@@ -28,6 +28,7 @@ import java.util.logging.Logger;
import org.springframework.boot.logging.AbstractLoggingSystem;
import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
......@@ -81,6 +82,11 @@ public class JavaLoggingSystem extends AbstractLoggingSystem {
}
@Override
protected void loadConfiguration(LoggingInitializationContext initializationContext,
String location, LogFile logFile) {
loadConfiguration(location, logFile);
}
protected void loadConfiguration(String location, LogFile logFile) {
Assert.notNull(location, "Location must not be null");
try {
......
......@@ -25,6 +25,7 @@ import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.logging.Slf4JLoggingSystem;
import org.springframework.util.Assert;
......@@ -79,6 +80,11 @@ public class Log4JLoggingSystem extends Slf4JLoggingSystem {
}
@Override
protected void loadConfiguration(LoggingInitializationContext initializationContext,
String location, LogFile logFile) {
loadConfiguration(location, logFile);
}
protected void loadConfiguration(String location, LogFile logFile) {
Assert.notNull(location, "Location must not be null");
if (logFile != null) {
......@@ -94,7 +100,7 @@ public class Log4JLoggingSystem extends Slf4JLoggingSystem {
}
@Override
protected void reinitialize() {
protected void reinitialize(LoggingInitializationContext initializationContext) {
loadConfiguration(getSelfInitializationConfig(), null);
}
......
......@@ -39,6 +39,7 @@ import org.apache.logging.log4j.core.filter.AbstractFilter;
import org.apache.logging.log4j.message.Message;
import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.logging.Slf4JLoggingSystem;
import org.springframework.util.Assert;
......@@ -128,9 +129,10 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem {
}
@Override
public void initialize(String configLocation, LogFile logFile) {
public void initialize(LoggingInitializationContext initializationContext,
String configLocation, LogFile logFile) {
getLoggerConfig(null).removeFilter(FILTER);
super.initialize(configLocation, logFile);
super.initialize(initializationContext, configLocation, logFile);
}
@Override
......@@ -144,6 +146,11 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem {
}
@Override
protected void loadConfiguration(LoggingInitializationContext initializationContext,
String location, LogFile logFile) {
loadConfiguration(location, logFile);
}
protected void loadConfiguration(String location, LogFile logFile) {
Assert.notNull(location, "Location must not be null");
if (logFile != null) {
......@@ -170,7 +177,7 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem {
}
@Override
protected void reinitialize() {
protected void reinitialize(LoggingInitializationContext initializationContext) {
getLoggerContext().reconfigure();
}
......
......@@ -30,6 +30,7 @@ import org.slf4j.Marker;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.logging.Slf4JLoggingSystem;
import org.springframework.util.Assert;
......@@ -38,8 +39,10 @@ import org.springframework.util.StringUtils;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.classic.util.ContextInitializer;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.spi.FilterReply;
import ch.qos.logback.core.status.Status;
......@@ -93,9 +96,10 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
}
@Override
public void initialize(String configLocation, LogFile logFile) {
public void initialize(LoggingInitializationContext initializationContext,
String configLocation, LogFile logFile) {
getLogger(null).getLoggerContext().getTurboFilterList().remove(FILTER);
super.initialize(configLocation, logFile);
super.initialize(initializationContext, configLocation, logFile);
}
@Override
......@@ -108,23 +112,24 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
}
@Override
protected void loadConfiguration(String location, LogFile logFile) {
protected void loadConfiguration(LoggingInitializationContext initializationContext,
String location, LogFile logFile) {
Assert.notNull(location, "Location must not be null");
if (logFile != null) {
logFile.applyToSystemProperties();
}
LoggerContext context = getLoggerContext();
context.stop();
context.reset();
LoggerContext loggerContext = getLoggerContext();
loggerContext.stop();
loggerContext.reset();
try {
URL url = ResourceUtils.getURL(location);
new ContextInitializer(context).configureByResource(url);
configureByResourceUrl(initializationContext, loggerContext,
ResourceUtils.getURL(location));
}
catch (Exception ex) {
throw new IllegalStateException("Could not initialize Logback logging from "
+ location, ex);
}
List<Status> statuses = context.getStatusManager().getCopyOfStatusList();
List<Status> statuses = loggerContext.getStatusManager().getCopyOfStatusList();
StringBuilder errors = new StringBuilder();
for (Status status : statuses) {
if (status.getLevel() == Status.ERROR) {
......@@ -138,6 +143,20 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
}
}
private void configureByResourceUrl(
LoggingInitializationContext initializationContext,
LoggerContext loggerContext, URL url) throws JoranException {
if (url.toString().endsWith("xml")) {
JoranConfigurator configurator = new SpringBootJoranConfigurator(
initializationContext);
configurator.setContext(loggerContext);
configurator.doConfigure(url);
}
else {
new ContextInitializer(loggerContext).configureByResource(url);
}
}
@Override
public void cleanUp() {
super.cleanUp();
......@@ -145,9 +164,9 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
}
@Override
protected void reinitialize() {
protected void reinitialize(LoggingInitializationContext initializationContext) {
getLoggerContext().reset();
loadConfiguration(getSelfInitializationConfig(), null);
loadConfiguration(initializationContext, getSelfInitializationConfig(), null);
}
private void configureJBossLoggingToUseSlf4j() {
......
/*
* Copyright 2012-2015 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
*
* http://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 org.springframework.boot.logging.LoggingInitializationContext;
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;
/**
* Extended version of the Logback {@link JoranConfigurator} that adds additional Spring
* Boot rules.
*
* @author Phillip Webb
*/
class SpringBootJoranConfigurator extends JoranConfigurator {
private LoggingInitializationContext initializationContext;
public SpringBootJoranConfigurator(LoggingInitializationContext initializationContext) {
this.initializationContext = initializationContext;
}
@Override
public void addInstanceRules(RuleStore rs) {
super.addInstanceRules(rs);
rs.addRule(new ElementSelector("*/springProfile"), new SpringProfileAction(
this.initializationContext.getEnvironment()));
rs.addRule(new ElementSelector("*/springProfile/*"), new NOPAction());
}
}
/*
* Copyright 2012-2015 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
*
* http://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 java.util.ArrayList;
import java.util.List;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import org.xml.sax.Attributes;
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;
/**
* Lockback {@link Action} to support {@code <springProfile>} tags. Allows section of a
* logback configuration to only be enabled when a specific profile is active.
*
* @author Phillip Webb
*/
class SpringProfileAction extends Action implements InPlayListener {
private final Environment environment;
private int depth = 0;
private boolean acceptsProfile;
private List<SaxEvent> events;
public SpringProfileAction(Environment environment) {
this.environment = environment;
}
@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<SaxEvent>();
ic.addInPlayListener(this);
}
private boolean acceptsProfiles(InterpretationContext ic, Attributes attributes) {
String profileName = attributes.getValue(NAME_ATTRIBUTE);
if (!OptionHelper.isEmpty(profileName)) {
OptionHelper.substVars(profileName, ic, this.context);
return this.environment != null
&& this.environment.acceptsProfiles(profileName);
}
return false;
}
@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);
}
}
......@@ -81,7 +81,7 @@ public class JavaLoggerSystemTests extends AbstractLoggingSystemTests {
public void noFile() throws Exception {
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(null, null, null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
......@@ -98,7 +98,7 @@ public class JavaLoggerSystemTests extends AbstractLoggingSystemTests {
}
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
this.loggingSystem.initialize(null, getLogFile(null, tmpDir()));
this.loggingSystem.initialize(null, null, getLogFile(null, tmpDir()));
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
......@@ -109,7 +109,7 @@ public class JavaLoggerSystemTests extends AbstractLoggingSystemTests {
@Test
public void testCustomFormatter() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(null, null, null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
......@@ -121,6 +121,7 @@ public class JavaLoggerSystemTests extends AbstractLoggingSystemTests {
System.setProperty("PID", "1234");
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(
null,
"classpath:"
+ ClassUtils.addResourcePathToPackagePath(getClass(),
"logging.properties"), null);
......@@ -134,7 +135,8 @@ public class JavaLoggerSystemTests extends AbstractLoggingSystemTests {
@Test
public void testNonDefaultConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:logging-nondefault.properties", null);
this.loggingSystem.initialize(null, "classpath:logging-nondefault.properties",
null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("INFO: Hello"));
......@@ -143,13 +145,14 @@ public class JavaLoggerSystemTests extends AbstractLoggingSystemTests {
@Test(expected = IllegalStateException.class)
public void testNonexistentConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:logging-nonexistent.properties", null);
this.loggingSystem.initialize(null, "classpath:logging-nonexistent.properties",
null);
}
@Test
public void setLevel() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(null, null, null);
this.logger.debug("Hello");
this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
this.logger.debug("Hello");
......
......@@ -68,7 +68,7 @@ public class Log4JLoggingSystemTests extends AbstractLoggingSystemTests {
public void noFile() throws Exception {
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(null, null, null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
......@@ -80,7 +80,7 @@ public class Log4JLoggingSystemTests extends AbstractLoggingSystemTests {
public void withFile() throws Exception {
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
this.loggingSystem.initialize(null, getLogFile(null, tmpDir()));
this.loggingSystem.initialize(null, null, getLogFile(null, tmpDir()));
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
......@@ -91,7 +91,7 @@ public class Log4JLoggingSystemTests extends AbstractLoggingSystemTests {
@Test
public void testNonDefaultConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:log4j-nondefault.properties",
this.loggingSystem.initialize(null, "classpath:log4j-nondefault.properties",
getLogFile(null, tmpDir()));
this.logger.info("Hello world");
String output = this.output.toString().trim();
......@@ -103,13 +103,13 @@ public class Log4JLoggingSystemTests extends AbstractLoggingSystemTests {
@Test(expected = IllegalStateException.class)
public void testNonexistentConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:log4j-nonexistent.xml", null);
this.loggingSystem.initialize(null, "classpath:log4j-nonexistent.xml", null);
}
@Test
public void setLevel() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(null, null, null);
this.logger.debug("Hello");
this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
this.logger.debug("Hello");
......@@ -121,7 +121,7 @@ public class Log4JLoggingSystemTests extends AbstractLoggingSystemTests {
@Ignore("Fails on Bamboo")
public void loggingThatUsesJulIsCaptured() {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(null, null, null);
java.util.logging.Logger julLogger = java.util.logging.Logger
.getLogger(getClass().getName());
julLogger.severe("Hello world");
......
......@@ -71,7 +71,7 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
public void noFile() throws Exception {
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(null, null, null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
......@@ -85,7 +85,7 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
public void withFile() throws Exception {
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
this.loggingSystem.initialize(null, getLogFile(null, tmpDir()));
this.loggingSystem.initialize(null, null, getLogFile(null, tmpDir()));
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
......@@ -98,7 +98,7 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
public void testNonDefaultConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:log4j2-nondefault.xml",
this.loggingSystem.initialize(null, "classpath:log4j2-nondefault.xml",
getLogFile(tmpDir() + "/tmp.log", null));
this.logger.info("Hello world");
String output = this.output.toString().trim();
......@@ -116,13 +116,13 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test(expected = IllegalStateException.class)
public void testNonexistentConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:log4j2-nonexistent.xml", null);
this.loggingSystem.initialize(null, "classpath:log4j2-nonexistent.xml", null);
}
@Test
public void setLevel() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(null, null, null);
this.logger.debug("Hello");
this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
this.logger.debug("Hello");
......@@ -134,7 +134,7 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Ignore("Fails on Bamboo")
public void loggingThatUsesJulIsCaptured() {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(null, null, null);
java.util.logging.Logger julLogger = java.util.logging.Logger
.getLogger(getClass().getName());
julLogger.severe("Hello world");
......
......@@ -31,7 +31,9 @@ import org.slf4j.bridge.SLF4JBridgeHandler;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.AbstractLoggingSystemTests;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.test.OutputCapture;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.util.StringUtils;
import ch.qos.logback.classic.Logger;
......@@ -61,9 +63,13 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
private Log logger;
private LoggingInitializationContext initializationContext;
@Before
public void setup() {
this.logger = new SLF4JLogFactory().getInstance(getClass().getName());
this.initializationContext = new LoggingInitializationContext(
new MockEnvironment());
}
@Override
......@@ -76,7 +82,7 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
public void noFile() throws Exception {
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(this.initializationContext, null, null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
......@@ -88,7 +94,8 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
public void withFile() throws Exception {
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
this.loggingSystem.initialize(null, getLogFile(null, tmpDir()));
this.loggingSystem.initialize(this.initializationContext, null,
getLogFile(null, tmpDir()));
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
......@@ -108,7 +115,8 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
@Test
public void testNonDefaultConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:logback-nondefault.xml",
this.loggingSystem.initialize(this.initializationContext,
"classpath:logback-nondefault.xml",
getLogFile(tmpDir() + "/tmp.log", null));
this.logger.info("Hello world");
String output = this.output.toString().trim();
......@@ -121,13 +129,14 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
@Test(expected = IllegalStateException.class)
public void testNonexistentConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:logback-nonexistent.xml", null);
this.loggingSystem.initialize(this.initializationContext,
"classpath:logback-nonexistent.xml", null);
}
@Test
public void setLevel() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(this.initializationContext, null, null);
this.logger.debug("Hello");
this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
this.logger.debug("Hello");
......@@ -138,7 +147,7 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
@Test
public void loggingThatUsesJulIsCaptured() {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null, null);
this.loggingSystem.initialize(this.initializationContext, null, null);
java.util.logging.Logger julLogger = java.util.logging.Logger
.getLogger(getClass().getName());
julLogger.info("Hello world");
......
/*
* Copyright 2012-2015 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
*
* http://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 org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.test.OutputCapture;
import org.springframework.mock.env.MockEnvironment;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
/**
* Tests for {@link SpringBootJoranConfigurator}.
*
* @author Phillip Webb
*/
public class SpringBootJoranConfiguratorTests {
@Rule
public OutputCapture out = new OutputCapture();
private MockEnvironment environment;
private LoggingInitializationContext initializationContext;
private JoranConfigurator configurator;
private LoggerContext context;
private Logger logger;
@Before
public void setup() {
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.logger = this.context.getLogger(getClass());
}
@After
public void reset() {
this.context.reset();
}
@Test
public void profileActive() throws Exception {
this.environment.setActiveProfiles("production");
initialize("production-profile.xml");
this.logger.trace("Hello");
this.out.expect(containsString("Hello"));
}
@Test
public void profileNotActive() throws Exception {
initialize("production-profile.xml");
this.logger.trace("Hello");
this.out.expect(not(containsString("Hello")));
}
@Test
public void profileNestedActiveActive() throws Exception {
doTestNestedProfile(true, "outer", "inner");
}
@Test
public void profileNestedActiveNotActive() throws Exception {
doTestNestedProfile(false, "outer");
}
@Test
public void profileNestedNotActiveActive() throws Exception {
doTestNestedProfile(false, "inner");
}
@Test
public void profileNestedNotActiveNotActive() throws Exception {
doTestNestedProfile(false);
}
private void doTestNestedProfile(boolean expected, String... profiles)
throws JoranException {
this.environment.setActiveProfiles(profiles);
initialize("nested.xml");
this.logger.trace("Hello");
if (expected) {
this.out.expect(containsString("Hello"));
}
else {
this.out.expect(not(containsString("Hello")));
}
}
private void initialize(String config) throws JoranException {
this.configurator.setContext(this.context);
this.configurator.doConfigure(getClass().getResourceAsStream(config));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<springProfile name="outer">
<springProfile name="inner">
<logger name="org.springframework.boot.logging.logback" level="TRACE" />
</springProfile>
</springProfile>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<springProfile name="production">
<logger name="org.springframework.boot.logging.logback" level="TRACE" />
</springProfile>
</configuration>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment