From 04776232f7ac10f3cbaf79638e378c1af6dafcbf Mon Sep 17 00:00:00 2001 From: Alexander Heusingfeld Date: Sat, 23 May 2015 18:20:48 +0200 Subject: [PATCH] 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 --- .../src/main/resources/log4j2.xml | 2 +- .../logging/log4j2/Log4J2LoggingSystem.java | 15 +++++++++++- .../log4j2/Log4J2LoggingSystemTests.java | 23 +++++++++++++++++-- .../src/test/resources/log4j2-nondefault.xml | 2 +- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/spring-boot-samples/spring-boot-sample-actuator-log4j2/src/main/resources/log4j2.xml b/spring-boot-samples/spring-boot-sample-actuator-log4j2/src/main/resources/log4j2.xml index 0f526e7079..501a92243b 100644 --- a/spring-boot-samples/spring-boot-sample-actuator-log4j2/src/main/resources/log4j2.xml +++ b/spring-boot-samples/spring-boot-sample-actuator-log4j2/src/main/resources/log4j2.xml @@ -1,5 +1,5 @@ - + ???? [%d{yyyy-MM-dd HH:mm:ss.SSS}] log4j2%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java index 18780942da..409a84814a 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java @@ -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(); diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java index d28b24a4e4..e90de8b656 100644 --- a/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java @@ -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); diff --git a/spring-boot/src/test/resources/log4j2-nondefault.xml b/spring-boot/src/test/resources/log4j2-nondefault.xml index 9ab4cd276b..ecaa4dc5ef 100644 --- a/spring-boot/src/test/resources/log4j2-nondefault.xml +++ b/spring-boot/src/test/resources/log4j2-nondefault.xml @@ -1,5 +1,5 @@ - + ???? ${sys:LOG_FILE} %d{yyyy-MM-dd HH:mm:ss.SSS}] service%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n