Commit 055ace37 authored by Phillip Webb's avatar Phillip Webb

Support <springProperty> in logback configurations

Include support for a new <springProperty> element which can be used in
`logback-spring.xml` files to add properties from the Spring
Environment. For example:

	<configuration>
		...
		<springProperty name="destination" source="my.loggger.extradest"/>
		<appender name="FILE" class="ch.qos.logback.core.FileAppender">
			<file>${destination}</file>
				...
			</file>
		</appender>
		...
	</configuration>

Fixes gh-1788
parent f3f562f3
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package org.springframework.boot.logging.logback; package org.springframework.boot.logging.logback;
import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.core.env.Environment;
import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.action.NOPAction; import ch.qos.logback.core.joran.action.NOPAction;
...@@ -40,6 +41,9 @@ class SpringBootJoranConfigurator extends JoranConfigurator { ...@@ -40,6 +41,9 @@ class SpringBootJoranConfigurator extends JoranConfigurator {
@Override @Override
public void addInstanceRules(RuleStore rs) { public void addInstanceRules(RuleStore rs) {
super.addInstanceRules(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( rs.addRule(new ElementSelector("*/springProfile"), new SpringProfileAction(
this.initializationContext.getEnvironment())); this.initializationContext.getEnvironment()));
rs.addRule(new ElementSelector("*/springProfile/*"), new NOPAction()); 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 org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.core.env.Environment;
import org.xml.sax.Attributes;
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;
/**
* Lockback {@link Action} to support {@code <springProperty>} tags. Allows logback
* properties to be sourced from the Spring environment.
*
* @author Phillip Webb
*/
class SpringPropertyAction extends Action {
private static final String SOURCE_ATTRIBUTE = "source";
private final Environment environment;
public SpringPropertyAction(Environment environment) {
this.environment = environment;
}
@Override
public void begin(InterpretationContext ic, 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));
if (OptionHelper.isEmpty(name) || OptionHelper.isEmpty(source)) {
addError("The \"name\" and \"source\" attributes of <springProperty> must be set");
}
ActionUtil.setProperty(ic, name, getValue(source), scope);
}
private String getValue(String source) {
if (this.environment == null) {
addWarn("No Spring Environment available to resolve " + source);
return null;
}
String value = this.environment.getProperty(source);
if (value != null) {
return value;
}
int lastDot = source.lastIndexOf(".");
if (lastDot > 0) {
String prefix = source.substring(0, lastDot + 1);
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
this.environment, prefix);
return resolver.getProperty(source.substring(lastDot + 1));
}
return null;
}
@Override
public void end(InterpretationContext ic, String name) throws ActionException {
}
}
...@@ -23,6 +23,7 @@ import org.junit.Test; ...@@ -23,6 +23,7 @@ import org.junit.Test;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.impl.StaticLoggerBinder; import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.boot.test.OutputCapture; import org.springframework.boot.test.OutputCapture;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
...@@ -31,7 +32,9 @@ import ch.qos.logback.classic.joran.JoranConfigurator; ...@@ -31,7 +32,9 @@ import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException; import ch.qos.logback.core.joran.spi.JoranException;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
/** /**
* Tests for {@link SpringBootJoranConfigurator}. * Tests for {@link SpringBootJoranConfigurator}.
...@@ -103,6 +106,20 @@ public class SpringBootJoranConfiguratorTests { ...@@ -103,6 +106,20 @@ public class SpringBootJoranConfiguratorTests {
doTestNestedProfile(false); doTestNestedProfile(false);
} }
@Test
public void springProperty() throws Exception {
EnvironmentTestUtils.addEnvironment(this.environment, "my.example-property:test");
initialize("property.xml");
assertThat(this.context.getProperty("MINE"), equalTo("test"));
}
@Test
public void relaxedSpringProperty() throws Exception {
EnvironmentTestUtils.addEnvironment(this.environment, "my.EXAMPLE_PROPERTY:test");
initialize("property.xml");
assertThat(this.context.getProperty("MINE"), equalTo("test"));
}
private void doTestNestedProfile(boolean expected, String... profiles) private void doTestNestedProfile(boolean expected, String... profiles)
throws JoranException { throws JoranException {
this.environment.setActiveProfiles(profiles); this.environment.setActiveProfiles(profiles);
......
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<springProperty scope="context" name="MINE" source="my.example-property"/>
</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