Allow auto-reload of log4j2 config

Log4j2 can auto-reload its configuration file as long as the reference
to a `java.io.File` is provided in the `ConfigurationSource`. Previously,
we always created such `ConfigurationSource` with only the URL regardless
of its type.

Detect when the configuration URL points to a File and create the
`ConfigurationSource` accordingly.

The `spring-boot-sample-actuator-log4j2` has been updated to reload the
logging configuration every 30 sec if necessary.

Fixes gh-3024, gh-3030
This commit is contained in:
Alexander Heusingfeld 2015-05-23 18:20:48 +02:00 committed by Stephane Nicoll
parent f0b203f6da
commit 04776232f7
4 changed files with 37 additions and 5 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="PID">????</Property>
<Property name="LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}] log4j2%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property>

View File

@ -16,6 +16,8 @@
package org.springframework.boot.logging.log4j2;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
@ -48,6 +50,7 @@ import org.springframework.util.ResourceUtils;
*
* @author Daniel Fullarton
* @author Andy Wilkinson
* @author Alexander Heusingfeld
* @since 1.2.0
*/
public class Log4J2LoggingSystem extends Slf4JLoggingSystem {
@ -149,7 +152,7 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem {
try {
LoggerContext ctx = getLoggerContext();
URL url = ResourceUtils.getURL(location);
ConfigurationSource source = new ConfigurationSource(url.openStream(), url);
ConfigurationSource source = getConfigurationSource(url);
ctx.start(ConfigurationFactory.getInstance().getConfiguration(source));
}
catch (Exception ex) {
@ -158,6 +161,16 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem {
}
}
private ConfigurationSource getConfigurationSource(URL url) throws IOException {
InputStream stream = url.openStream();
if (ResourceUtils.isFileURL(url)) {
return new ConfigurationSource(stream,
ResourceUtils.getFile(url));
} else {
return new ConfigurationSource(stream, url);
}
}
@Override
protected void reinitialize() {
getLoggerContext().reconfigure();

View File

@ -21,22 +21,27 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.FileConfigurationMonitor;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.logging.AbstractLoggingSystemTests;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.test.OutputCapture;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@ -72,6 +77,8 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertFalse(new File(tmpDir() + "/spring.log").exists());
assertThat(this.loggingSystem.getConfiguration().getConfigurationSource()
.getFile(), is(notNullValue()));
}
@Test
@ -84,6 +91,8 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertTrue(new File(tmpDir() + "/spring.log").exists());
assertThat(this.loggingSystem.getConfiguration().getConfigurationSource()
.getFile(), is(notNullValue()));
}
@Test
@ -96,6 +105,12 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertTrue("Wrong output:\n" + output, output.contains(tmpDir() + "/tmp.log"));
assertFalse(new File(tmpDir() + "/tmp.log").exists());
assertThat(this.loggingSystem.getConfiguration().getConfigurationSource()
.getFile().getAbsolutePath(), containsString("log4j2-nondefault.xml"));
// we assume that "log4j2-nondefault.xml" contains the 'monitorInterval'
// attribute, so we check that a monitor is created
assertThat(this.loggingSystem.getConfiguration().getConfigurationMonitor(),
is(instanceOf(FileConfigurationMonitor.class)));
}
@Test(expected = IllegalStateException.class)
@ -167,6 +182,10 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
super(TestLog4J2LoggingSystem.class.getClassLoader());
}
public Configuration getConfiguration() {
return ((org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false)).getConfiguration();
}
@Override
protected boolean isClassAvailable(String className) {
return this.availableClasses.contains(className);

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="PID">????</Property>
<Property name="LOG_PATTERN">${sys:LOG_FILE} %d{yyyy-MM-dd HH:mm:ss.SSS}] service%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property>