Commit 4c70958d authored by Ralph Goers's avatar Ralph Goers
Browse files

LOG4J2-2893 - Allow reconfiguration when Log4j 1 configuration files are updated.

parent 2b89c1fa
release-2.x CVE-creation-process LOG4J2-2829 LOG4J2-2948 LOG4J2-3004 LOG4J2-3051 LOG4J2-3056 LOG4J2-3075 LOG4J2-3080 LOG4J2-3116 LOG4J2-3185 LOG4J2-3301 LOG4J2-3368 LOG4J2-3393 api-separation-documentation dependabot/maven/com.h2database-h2-2.0.206 dependabot/maven/com.h2database-h2-2.1.210 dependabot/maven/com.h2database-h2-2.1.212 dependabot/maven/com.sleepycat-je-18.3.12 dependabot/maven/de.flapdoodle.embed-de.flapdoodle.embed.mongo-3.3.1 dependabot/maven/de.flapdoodle.embed-de.flapdoodle.embed.mongo-3.4.5 dependabot/maven/io.fabric8-docker-maven-plugin-0.39.0 dependabot/maven/io.fabric8-kubernetes-client-5.11.2 dependabot/maven/javax.servlet-javax.servlet-api-4.0.1 dependabot/maven/jmh.version-1.34 dependabot/maven/log4j-cassandra/org.apache.cassandra-cassandra-all-3.0.26 dependabot/maven/logbackVersion-1.2.10 dependabot/maven/mockitoVersion-4.3.1 dependabot/maven/mongodb3.version-3.12.10 dependabot/maven/net.javacrumbs.json-unit-json-unit-2.31.0 dependabot/maven/org.apache.activemq-activemq-broker-5.17.0 dependabot/maven/org.apache.activemq-activemq-broker-5.17.1 dependabot/maven/org.apache.felix-maven-bundle-plugin-5.1.4 dependabot/maven/org.apache.felix-maven-bundle-plugin-5.1.5 dependabot/maven/org.apache.felix-org.apache.felix.framework-7.0.3 dependabot/maven/org.apache.kafka-kafka-clients-3.0.0 dependabot/maven/org.apache.kafka-kafka-clients-3.1.0 dependabot/maven/org.apache.maven-maven-core-3.8.4 dependabot/maven/org.apache.maven.plugins-maven-checkstyle-plugin-3.1.2 dependabot/maven/org.apache.maven.plugins-maven-pdf-plugin-1.6.0 dependabot/maven/org.apache.maven.plugins-maven-project-info-reports-plugin-3.2.2 dependabot/maven/org.apache.maven.plugins-maven-scm-plugin-1.12.2 dependabot/maven/org.apache.maven.plugins-maven-site-plugin-3.12.0 dependabot/maven/org.apache.tomcat-tomcat-catalina-10.0.14 dependabot/maven/org.awaitility-awaitility-4.1.1 dependabot/maven/org.codehaus.mojo-build-helper-maven-plugin-3.2.0 dependabot/maven/org.codehaus.mojo-build-helper-maven-plugin-3.3.0 dependabot/maven/org.codehaus.plexus-plexus-utils-3.4.1 dependabot/maven/org.lightcouch-lightcouch-0.2.0 dependabot/maven/org.liquibase-liquibase-core-3.10.3 dependabot/maven/org.liquibase-liquibase-core-4.6.2 dependabot/maven/org.liquibase-liquibase-core-4.7.0 dependabot/maven/org.springframework.ws-spring-ws-core-3.1.2 dependabot/maven/slf4jVersion-1.7.36 dependabot/maven/spring-boot.version-2.6.2 dependabot/maven/xmlunitVersion-2.9.0 ldap-controls log4j-2.17.1-site slf4j-2.0 rel/2.17.2 rel/2.17.1 rel/2.17.0 rel/2.16.0 rel/2.15.0 rel/2.14.1 log4j-2.17.2-rc1 log4j-2.17.1-rc1 log4j-2.17.0-rc1 log4j-2.16.0-rc1 log4j-2.15.1-rc1 log4j-2.15.0-rc2 log4j-2.15.0-rc1 log4j-2.14.1-rc1
No related merge requests found
Showing with 233 additions and 0 deletions
+233 -0
......@@ -26,11 +26,13 @@ import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.Filter;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.status.StatusConfiguration;
import org.apache.logging.log4j.util.LoaderUtil;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
......@@ -90,6 +92,23 @@ public class PropertiesConfiguration extends Log4j1Configuration {
doConfigure(props);
}
@Override
public Configuration reconfigure() {
try {
final ConfigurationSource source = getConfigurationSource().resetInputStream();
if (source == null) {
return null;
}
final PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory();
final PropertiesConfiguration config =
(PropertiesConfiguration) factory.getConfiguration(getLoggerContext(), source);
return config == null || config.getState() != State.INITIALIZING ? null : config;
} catch (final IOException ex) {
LOGGER.error("Cannot locate file {}: {}", getConfigurationSource(), ex);
}
return null;
}
/**
* Read configuration from a file. <b>The existing configuration is
* not cleared nor reset.</b> If you require a different behavior,
......
......@@ -22,6 +22,8 @@ import org.apache.log4j.Level;
import org.apache.log4j.bridge.AppenderAdapter;
import org.apache.log4j.bridge.AppenderWrapper;
import org.apache.log4j.config.Log4j1Configuration;
import org.apache.log4j.config.PropertiesConfiguration;
import org.apache.log4j.config.PropertiesConfigurationFactory;
import org.apache.log4j.config.PropertySetter;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.rewrite.RewritePolicy;
......@@ -29,6 +31,7 @@ import org.apache.log4j.spi.AppenderAttachable;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.Filter;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.status.StatusConfiguration;
......@@ -171,6 +174,23 @@ public class XmlConfiguration extends Log4j1Configuration {
}
}
@Override
public Configuration reconfigure() {
try {
final ConfigurationSource source = getConfigurationSource().resetInputStream();
if (source == null) {
return null;
}
final XmlConfigurationFactory factory = new XmlConfigurationFactory();
final XmlConfiguration config =
(XmlConfiguration) factory.getConfiguration(getLoggerContext(), source);
return config == null || config.getState() != State.INITIALIZING ? null : config;
} catch (final IOException ex) {
LOGGER.error("Cannot locate file {}: {}", getConfigurationSource(), ex);
}
return null;
}
/**
* Delegates unrecognized content to created instance if it supports UnrecognizedElementParser.
*
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.log4j.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationListener;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.Reconfigurable;
import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.junit.Test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Test reconfiguring with an XML configuration.
*/
public class PropertiesReconfigurationTest {
private static final String CONFIG = "target/test-classes/log4j1-file.properties";
private static final long FIVE_MINUTES = 5 * 60 * 1000;
private CountDownLatch toggle = new CountDownLatch(1);
@Test
public void testReconfiguration() throws Exception {
System.setProperty(Log4j1Configuration.MONITOR_INTERVAL, "1");
File file = new File(CONFIG);
assertNotNull("No Config file", file);
long configMillis = file.lastModified();
assertTrue("Unable to modified file time", file.setLastModified(configMillis - FIVE_MINUTES));
LoggerContext context = configure(file);
Logger logger = LogManager.getLogger("test");
logger.info("Hello");
Configuration original = context.getConfiguration();
TestListener listener = new TestListener();
original.addListener(listener);
file.setLastModified(System.currentTimeMillis());
try {
if (!toggle.await(3, TimeUnit.SECONDS)) {
fail("Reconfiguration timed out");
}
// Allow reconfiguration to complete.
Thread.sleep(500);
} catch (InterruptedException ie) {
fail("Reconfiguration interupted");
}
Configuration updated = context.getConfiguration();
assertTrue("Configurations are the same", original != updated);
}
private class TestListener implements ConfigurationListener {
public synchronized void onChange(final Reconfigurable reconfigurable) {
toggle.countDown();
}
}
private LoggerContext configure(File configFile) throws Exception {
InputStream is = new FileInputStream(configFile);
ConfigurationSource source = new ConfigurationSource(is, configFile);
LoggerContextFactory factory = org.apache.logging.log4j.LogManager.getFactory();
LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
Configuration configuration = new PropertiesConfigurationFactory().getConfiguration(context, source);
assertNotNull("No configuration created", configuration);
Configurator.reconfigure(configuration);
return context;
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.log4j.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.XmlConfigurationFactory;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationListener;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.Reconfigurable;
import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.junit.Test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Test reconfiguring with an XML configuration.
*/
public class XmlReconfigurationTest {
private static final String CONFIG = "target/test-classes/log4j1-file.xml";
private static final long FIVE_MINUTES = 5 * 60 * 1000;
private CountDownLatch toggle = new CountDownLatch(1);
@Test
public void testReconfiguration() throws Exception {
System.setProperty(Log4j1Configuration.MONITOR_INTERVAL, "1");
File file = new File(CONFIG);
assertNotNull("No Config file", file);
long configMillis = file.lastModified();
assertTrue("Unable to modified file time", file.setLastModified(configMillis - FIVE_MINUTES));
LoggerContext context = configure(file);
Logger logger = LogManager.getLogger("test");
logger.info("Hello");
Configuration original = context.getConfiguration();
TestListener listener = new TestListener();
original.addListener(listener);
file.setLastModified(System.currentTimeMillis());
try {
if (!toggle.await(3, TimeUnit.SECONDS)) {
fail("Reconfiguration timed out");
}
// Allow reconfiguration to complete.
Thread.sleep(500);
} catch (InterruptedException ie) {
fail("Reconfiguration interupted");
}
Configuration updated = context.getConfiguration();
assertTrue("Configurations are the same", original != updated);
}
private class TestListener implements ConfigurationListener {
public synchronized void onChange(final Reconfigurable reconfigurable) {
toggle.countDown();
}
}
private LoggerContext configure(File configFile) throws Exception {
InputStream is = new FileInputStream(configFile);
ConfigurationSource source = new ConfigurationSource(is, configFile);
LoggerContextFactory factory = org.apache.logging.log4j.LogManager.getFactory();
LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
Configuration configuration = new XmlConfigurationFactory().getConfiguration(context, source);
assertNotNull("No configuration created", configuration);
Configurator.reconfigure(configuration);
return context;
}
}
......@@ -94,6 +94,9 @@
Support stack trace truncation in JsonTemplateLayout.
</action>
<!-- UPDATES -->
<action issue="LOG4J2-2893" dev="rgoers" type="update">
Allow reconfiguration when Log4j 1 configuration files are updated.
</action>
<action dev="rgoers" type="update">
Update Spring dependencies to 5.3.2, Spring Boot to 2.3.6, and Spring Cloud to Hoxton.SR9
</action>
......
Supports Markdown
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