This is an automated email from the ASF dual-hosted git repository.
pkarwasz pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/release-2.x by this push:
new 1e90f9aeb1 [LOG4J2-3483] Adds support for Apache Extras
RollingFileAppender
1e90f9aeb1 is described below
commit 1e90f9aeb1a559bbbb7d2510a93fe718505ba30c
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Mon May 23 22:41:09 2022 +0200
[LOG4J2-3483] Adds support for Apache Extras RollingFileAppender
Adds a builder for Apache Extras' `RollingFileAppender`.
---
.../org/apache/log4j/builders/AbstractBuilder.java | 27 +++
.../org/apache/log4j/builders/BuilderManager.java | 7 +
.../EnhancedRollingFileAppenderBuilder.java | 241 +++++++++++++++++++++
.../rolling/CompositeTriggeringPolicyBuilder.java | 74 +++++++
.../rolling/SizeBasedTriggeringPolicyBuilder.java | 75 +++++++
.../rolling/TimeBasedRollingPolicyBuilder.java | 56 +++++
.../builders/rolling/TriggeringPolicyBuilder.java | 24 ++
.../log4j/config/PropertiesConfiguration.java | 9 +
.../org/apache/log4j/xml/XmlConfiguration.java | 7 +
.../config/AbstractLog4j1ConfigurationTest.java | 73 +++++++
.../log4j/config/PropertiesConfigurationTest.java | 11 +-
.../apache/log4j/config/XmlConfigurationTest.java | 26 ++-
.../log4j-EnhancedRollingFileAppender.properties | 66 ++++++
.../log4j-EnhancedRollingFileAppender.xml | 94 ++++++++
src/changes/changes.xml | 4 +
15 files changed, 792 insertions(+), 2 deletions(-)
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
index 6bf0c2cbc0..16240f45a5 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.log4j.bridge.FilterAdapter;
@@ -120,6 +121,19 @@ public abstract class AbstractBuilder<T> implements
Builder<T> {
return defaultValue;
}
+ public long getLongProperty(final String key, final long defaultValue) {
+ String value = null;
+ try {
+ value = getProperty(key);
+ if (value != null) {
+ return Long.parseLong(value);
+ }
+ } catch (final Exception ex) {
+ LOGGER.warn("Error converting value {} of {} to a long: {}",
value, key, ex.getMessage());
+ }
+ return defaultValue;
+ }
+
protected String getNameAttribute(final Element element) {
return element.getAttribute(NAME_ATTR);
}
@@ -195,6 +209,19 @@ public abstract class AbstractBuilder<T> implements
Builder<T> {
}
}
+ protected void set(final String name, final Element element, AtomicLong
ref) {
+ final String value = getValueAttribute(element);
+ if (value == null) {
+ LOGGER.warn("No value for {} parameter, using default {}", name,
ref);
+ } else {
+ try {
+ ref.set(Long.parseLong(value));
+ } catch (NumberFormatException e) {
+ LOGGER.warn("{} parsing {} parameter, using default {}: {}",
e.getClass().getName(), name, ref, e.getMessage(), e);
+ }
+ }
+ }
+
protected void set(final String name, final Element element,
AtomicReference<String> ref) {
final String value = getValueAttribute(element);
if (value == null) {
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
index 226fa3a865..dba7d267df 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
@@ -32,11 +32,13 @@ import org.apache.log4j.builders.appender.AppenderBuilder;
import org.apache.log4j.builders.filter.FilterBuilder;
import org.apache.log4j.builders.layout.LayoutBuilder;
import org.apache.log4j.builders.rewrite.RewritePolicyBuilder;
+import org.apache.log4j.builders.rolling.TriggeringPolicyBuilder;
import org.apache.log4j.config.PropertiesConfiguration;
import org.apache.log4j.rewrite.RewritePolicy;
import org.apache.log4j.spi.Filter;
import org.apache.log4j.xml.XmlConfiguration;
import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
import org.apache.logging.log4j.core.config.plugins.util.PluginType;
import org.apache.logging.log4j.status.StatusLogger;
@@ -161,4 +163,9 @@ public class BuilderManager {
INVALID_REWRITE_POLICY);
}
+ public TriggeringPolicy parseTriggeringPolicy(final String className,
final Element policyElement,
+ final XmlConfiguration config) {
+ return newInstance(this.<TriggeringPolicyBuilder>getPlugin(className),
b -> b.parse(policyElement, config),
+ (TriggeringPolicy) null);
+ }
}
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/EnhancedRollingFileAppenderBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/EnhancedRollingFileAppenderBuilder.java
new file mode 100644
index 0000000000..91f124167a
--- /dev/null
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/EnhancedRollingFileAppenderBuilder.java
@@ -0,0 +1,241 @@
+/*
+ * 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.builders.appender;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
+import
org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+/**
+ * Build a File Appender
+ */
+@Plugin(name = "org.apache.log4j.rolling.RollingFileAppender", category =
CATEGORY)
+
+public class EnhancedRollingFileAppenderBuilder extends
AbstractBuilder<Appender> implements AppenderBuilder<Appender> {
+
+ private static final String TIME_BASED_ROLLING_POLICY =
"org.apache.log4j.rolling.TimeBasedRollingPolicy";
+ private static final String FIXED_WINDOW_ROLLING_POLICY =
"org.apache.log4j.rolling.FixedWindowRollingPolicy";
+ private static final Logger LOGGER = StatusLogger.getLogger();
+ private static final String TRIGGERING_TAG = "triggeringPolicy";
+ private static final String ROLLING_TAG = "rollingPolicy";
+ private static final int DEFAULT_MIN_INDEX = 1;
+ private static final int DEFAULT_MAX_INDEX = 7;
+ private static final String ACTIVE_FILE_PARAM = "ActiveFileName";
+ private static final String FILE_PATTERN_PARAM = "FileNamePattern";
+ private static final String MIN_INDEX_PARAM = "MinIndex";
+ private static final String MAX_INDEX_PARAM = "MaxIndex";
+
+ public EnhancedRollingFileAppenderBuilder() {
+ }
+
+ public EnhancedRollingFileAppenderBuilder(final String prefix, final
Properties properties) {
+ super(prefix, properties);
+ }
+
+ private void parseRollingPolicy(Element element, XmlConfiguration
configuration,
+ AtomicReference<String> rollingPolicyClassName,
AtomicReference<String> activeFileName,
+ AtomicReference<String> fileNamePattern, AtomicInteger minIndex,
+ AtomicInteger maxIndex) {
+
rollingPolicyClassName.set(configuration.subst(element.getAttribute("class"),
getProperties()));
+ forEachElement(element.getChildNodes(), currentElement -> {
+ switch (currentElement.getTagName()) {
+ case PARAM_TAG:
+ switch (getNameAttributeKey(currentElement)) {
+ case ACTIVE_FILE_PARAM:
+ set(ACTIVE_FILE_PARAM, currentElement,
activeFileName);
+ break;
+ case FILE_PATTERN_PARAM:
+ set(FILE_PATTERN_PARAM, currentElement,
fileNamePattern);
+ break;
+ case MIN_INDEX_PARAM:
+ set(MIN_INDEX_PARAM, currentElement, minIndex);
+ break;
+ case MAX_INDEX_PARAM:
+ set(MAX_INDEX_PARAM, currentElement, maxIndex);
+ }
+ }
+ });
+ }
+
+ @Override
+ public Appender parseAppender(Element element, XmlConfiguration
configuration) {
+ // FileAppender
+ final String name = getNameAttribute(element);
+ final AtomicReference<Layout> layout = new AtomicReference<>();
+ final AtomicReference<Filter> filter = new AtomicReference<>();
+ final AtomicReference<String> fileName = new AtomicReference<>();
+ final AtomicReference<String> level = new AtomicReference<>();
+ final AtomicBoolean immediateFlush = new AtomicBoolean(true);
+ final AtomicBoolean append = new AtomicBoolean(true);
+ final AtomicBoolean bufferedIo = new AtomicBoolean();
+ final AtomicInteger bufferSize = new AtomicInteger(8192);
+ // specific to RollingFileAppender
+ final AtomicReference<String> rollingPolicyClassName = new
AtomicReference<>();
+ final AtomicReference<String> activeFileName = new AtomicReference<>();
+ final AtomicReference<String> fileNamePattern = new
AtomicReference<>();
+ final AtomicInteger minIndex = new AtomicInteger(DEFAULT_MIN_INDEX);
+ final AtomicInteger maxIndex = new AtomicInteger(DEFAULT_MAX_INDEX);
+ final AtomicReference<TriggeringPolicy> triggeringPolicy = new
AtomicReference<>();
+ forEachElement(element.getChildNodes(), currentElement -> {
+ switch (currentElement.getTagName()) {
+ case ROLLING_TAG:
+ parseRollingPolicy(currentElement, configuration,
rollingPolicyClassName, activeFileName,
+ fileNamePattern, minIndex, maxIndex);
+ break;
+ case TRIGGERING_TAG:
+
triggeringPolicy.set(configuration.parseTriggeringPolicy(currentElement));
+ break;
+ case LAYOUT_TAG:
+ layout.set(configuration.parseLayout(currentElement));
+ break;
+ case FILTER_TAG:
+ configuration.addFilter(filter, currentElement);
+ break;
+ case PARAM_TAG:
+ switch (getNameAttributeKey(currentElement)) {
+ case FILE_PARAM:
+ set(FILE_PARAM, currentElement, fileName);
+ break;
+ case APPEND_PARAM:
+ set(APPEND_PARAM, currentElement, append);
+ break;
+ case BUFFERED_IO_PARAM:
+ set(BUFFERED_IO_PARAM, currentElement, bufferedIo);
+ break;
+ case BUFFER_SIZE_PARAM:
+ set(BUFFER_SIZE_PARAM, currentElement, bufferSize);
+ break;
+ case THRESHOLD_PARAM:
+ set(THRESHOLD_PARAM, currentElement, level);
+ break;
+ case IMMEDIATE_FLUSH_PARAM:
+ set(IMMEDIATE_FLUSH_PARAM, currentElement,
immediateFlush);
+ break;
+ }
+ break;
+ }
+ });
+ return createAppender(name, layout.get(), filter.get(),
fileName.get(), level.get(), immediateFlush.get(),
+ append.get(), bufferedIo.get(), bufferSize.get(),
rollingPolicyClassName.get(), activeFileName.get(),
+ fileNamePattern.get(), minIndex.get(), maxIndex.get(),
triggeringPolicy.get(), configuration);
+ }
+
+ @Override
+ public Appender parseAppender(String name, String appenderPrefix, String
layoutPrefix, String filterPrefix,
+ Properties props, PropertiesConfiguration configuration) {
+ final Layout layout = configuration.parseLayout(layoutPrefix, name,
props);
+ final Filter filter = configuration.parseAppenderFilters(props,
filterPrefix, name);
+ final String level = getProperty(THRESHOLD_PARAM);
+ final String fileName = getProperty(FILE_PARAM);
+ final boolean append = getBooleanProperty(APPEND_PARAM, true);
+ final boolean immediateFlush =
getBooleanProperty(IMMEDIATE_FLUSH_PARAM, true);
+ final boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM,
false);
+ final int bufferSize = Integer.parseInt(getProperty(BUFFER_SIZE_PARAM,
"8192"));
+ final String rollingPolicyClassName = getProperty(ROLLING_TAG);
+ final int minIndex = getIntegerProperty(ROLLING_TAG + "." +
MIN_INDEX_PARAM, DEFAULT_MIN_INDEX);
+ final int maxIndex = getIntegerProperty(ROLLING_TAG + "." +
MAX_INDEX_PARAM, DEFAULT_MAX_INDEX);
+ final String activeFileName = getProperty(ROLLING_TAG + "." +
ACTIVE_FILE_PARAM);
+ final String fileNamePattern = getProperty(ROLLING_TAG + "." +
FILE_PATTERN_PARAM);
+ final TriggeringPolicy triggeringPolicy =
configuration.parseTriggeringPolicy(props,
+ appenderPrefix + "." + TRIGGERING_TAG);
+ return createAppender(name, layout, filter, fileName, level,
immediateFlush, append, bufferedIo, bufferSize,
+ rollingPolicyClassName, activeFileName, fileNamePattern,
minIndex, maxIndex, triggeringPolicy,
+ configuration);
+ }
+
+ private Appender createAppender(final String name, final Layout layout,
final Filter filter, final String fileName,
+ final String level, final boolean immediateFlush, final boolean
append, final boolean bufferedIo,
+ final int bufferSize, final String rollingPolicyClassName, final
String activeFileName,
+ final String fileNamePattern, final int minIndex, final int
maxIndex,
+ final TriggeringPolicy triggeringPolicy, final Configuration
configuration) {
+ final org.apache.logging.log4j.core.Layout<?> fileLayout =
LayoutAdapter.adapt(layout);
+ final boolean actualImmediateFlush = bufferedIo ? false :
immediateFlush;
+ final org.apache.logging.log4j.core.Filter fileFilter =
buildFilters(level, filter);
+ if (rollingPolicyClassName == null) {
+ LOGGER.error("Unable to create RollingFileAppender, no rolling
policy provided.");
+ return null;
+ }
+ final String actualFileName = activeFileName != null ? activeFileName
: fileName;
+ if (actualFileName == null) {
+ LOGGER.error("Unable to create RollingFileAppender, no file name
provided.");
+ return null;
+ }
+ if (fileNamePattern == null) {
+ LOGGER.error("Unable to create RollingFileAppender, no file name
pattern provided.");
+ return null;
+ }
+ final DefaultRolloverStrategy.Builder rolloverStrategyBuilder =
DefaultRolloverStrategy.newBuilder();
+ switch (rollingPolicyClassName) {
+ case FIXED_WINDOW_ROLLING_POLICY:
+
rolloverStrategyBuilder.withMin(Integer.toString(minIndex)).withMax(Integer.toString(maxIndex));
+ break;
+ case TIME_BASED_ROLLING_POLICY:
+ break;
+ default:
+ LOGGER.warn("Unsupported rolling policy: {}",
rollingPolicyClassName);
+ }
+ final TriggeringPolicy actualTriggeringPolicy;
+ if (triggeringPolicy != null) {
+ actualTriggeringPolicy = triggeringPolicy;
+ } else if (rollingPolicyClassName.equals(TIME_BASED_ROLLING_POLICY)) {
+ actualTriggeringPolicy =
TimeBasedTriggeringPolicy.newBuilder().build();
+ } else {
+ LOGGER.error("Unable to create RollingFileAppender, no triggering
policy provided.");
+ return null;
+ }
+ return AppenderWrapper.adapt(RollingFileAppender.newBuilder()
+ .withAppend(append)
+ .setBufferedIo(bufferedIo)
+ .setBufferSize(bufferedIo ? bufferSize : 0)
+ .setConfiguration(configuration)
+ .withFileName(actualFileName)
+ .withFilePattern(fileNamePattern)
+ .setFilter(fileFilter)
+ .setImmediateFlush(actualImmediateFlush)
+ .setLayout(fileLayout)
+ .setName(name)
+ .withPolicy(actualTriggeringPolicy)
+ .withStrategy(rolloverStrategyBuilder.build())
+ .build());
+ }
+}
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/CompositeTriggeringPolicyBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/CompositeTriggeringPolicyBuilder.java
new file mode 100644
index 0000000000..ece2a0e80a
--- /dev/null
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/CompositeTriggeringPolicyBuilder.java
@@ -0,0 +1,74 @@
+/*
+ * 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.builders.rolling;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import
org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.w3c.dom.Element;
+
+@Plugin(name = "org.apache.log4j.rolling.CompositeTriggeringPolicy", category
= CATEGORY)
+public class CompositeTriggeringPolicyBuilder extends
AbstractBuilder<TriggeringPolicy>
+ implements TriggeringPolicyBuilder {
+
+ private static final TriggeringPolicy[] EMPTY_TRIGGERING_POLICIES = new
TriggeringPolicy[0];
+ private static final String POLICY_TAG = "triggeringPolicy";
+
+ public CompositeTriggeringPolicyBuilder() {
+ super();
+ }
+
+ public CompositeTriggeringPolicyBuilder(String prefix, Properties props) {
+ super(prefix, props);
+ }
+
+ @Override
+ public CompositeTriggeringPolicy parse(Element element, XmlConfiguration
configuration) {
+ final List<TriggeringPolicy> policies = new ArrayList<>();
+ forEachElement(element.getChildNodes(), currentElement -> {
+ switch (currentElement.getTagName()) {
+ case POLICY_TAG:
+ final TriggeringPolicy policy =
configuration.parseTriggeringPolicy(currentElement);
+ if (policy != null) {
+ policies.add(policy);
+ }
+ break;
+ }
+ });
+ return createTriggeringPolicy(policies);
+ }
+
+ @Override
+ public CompositeTriggeringPolicy parse(PropertiesConfiguration
configuration) {
+ return createTriggeringPolicy(Collections.emptyList());
+ }
+
+ private CompositeTriggeringPolicy
createTriggeringPolicy(List<TriggeringPolicy> policies) {
+ return
CompositeTriggeringPolicy.createPolicy(policies.toArray(EMPTY_TRIGGERING_POLICIES));
+ }
+}
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/SizeBasedTriggeringPolicyBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/SizeBasedTriggeringPolicyBuilder.java
new file mode 100644
index 0000000000..3ab1402b82
--- /dev/null
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/SizeBasedTriggeringPolicyBuilder.java
@@ -0,0 +1,75 @@
+/*
+ * 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.builders.rolling;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import
org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.w3c.dom.Element;
+
+@Plugin(name = "org.apache.log4j.rolling.SizeBasedTriggeringPolicy", category
= CATEGORY)
+public class SizeBasedTriggeringPolicyBuilder extends
AbstractBuilder<TriggeringPolicy>
+ implements TriggeringPolicyBuilder {
+
+ private static final String MAX_SIZE_PARAM = "MaxFileSize";
+ private static final long DEFAULT_MAX_SIZE = 10 * 1024 * 1024;
+
+ public SizeBasedTriggeringPolicyBuilder() {
+ super();
+ }
+
+ public SizeBasedTriggeringPolicyBuilder(String prefix, Properties props) {
+ super(prefix, props);
+ }
+
+ @Override
+ public SizeBasedTriggeringPolicy parse(Element element, XmlConfiguration
configuration) {
+ final AtomicLong maxSize = new AtomicLong(DEFAULT_MAX_SIZE);
+ forEachElement(element.getChildNodes(), currentElement -> {
+ switch (currentElement.getTagName()) {
+ case PARAM_TAG:
+ switch (getNameAttributeKey(currentElement)) {
+ case MAX_SIZE_PARAM:
+ set(MAX_SIZE_PARAM, currentElement, maxSize);
+ break;
+ }
+ break;
+ }
+ });
+ return createTriggeringPolicy(maxSize.get());
+ }
+
+ @Override
+ public SizeBasedTriggeringPolicy parse(PropertiesConfiguration
configuration) {
+ final long maxSize = getLongProperty(MAX_SIZE_PARAM, DEFAULT_MAX_SIZE);
+ return createTriggeringPolicy(maxSize);
+ }
+
+ private SizeBasedTriggeringPolicy createTriggeringPolicy(long maxSize) {
+ return SizeBasedTriggeringPolicy.createPolicy(Long.toString(maxSize));
+ }
+}
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TimeBasedRollingPolicyBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TimeBasedRollingPolicyBuilder.java
new file mode 100644
index 0000000000..70f3ee3645
--- /dev/null
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TimeBasedRollingPolicyBuilder.java
@@ -0,0 +1,56 @@
+/*
+ * 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.builders.rolling;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+
+import java.util.Properties;
+
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import
org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.w3c.dom.Element;
+
+@Plugin(name = "org.apache.log4j.rolling.TimeBasedRollingPolicy", category =
CATEGORY)
+public class TimeBasedRollingPolicyBuilder extends
AbstractBuilder<TriggeringPolicy>
+ implements TriggeringPolicyBuilder {
+
+ public TimeBasedRollingPolicyBuilder(String prefix, Properties props) {
+ super(prefix, props);
+ }
+
+ public TimeBasedRollingPolicyBuilder() {
+ super();
+ }
+
+ @Override
+ public TimeBasedTriggeringPolicy parse(Element element, XmlConfiguration
configuration) {
+ return createTriggeringPolicy();
+ }
+
+ @Override
+ public TimeBasedTriggeringPolicy parse(PropertiesConfiguration
configuration) {
+ return createTriggeringPolicy();
+ }
+
+ private TimeBasedTriggeringPolicy createTriggeringPolicy() {
+ return TimeBasedTriggeringPolicy.newBuilder().build();
+ }
+}
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TriggeringPolicyBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TriggeringPolicyBuilder.java
new file mode 100644
index 0000000000..f7dfff12a9
--- /dev/null
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TriggeringPolicyBuilder.java
@@ -0,0 +1,24 @@
+/*
+ * 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.builders.rolling;
+
+import org.apache.log4j.builders.Parser;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+
+public interface TriggeringPolicyBuilder extends Parser<TriggeringPolicy> {
+ // NOP
+}
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
index 2378edfd6e..ebfa443568 100644
---
a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
@@ -43,6 +43,7 @@ import org.apache.log4j.spi.Filter;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Filter.Result;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
@@ -590,6 +591,14 @@ public class PropertiesConfiguration extends
Log4j1Configuration {
return filter;
}
+ public TriggeringPolicy parseTriggeringPolicy(final Properties props,
final String policyPrefix) {
+ final String policyClass = OptionConverter.findAndSubst(policyPrefix,
props);
+ if (policyClass == null) {
+ return null;
+ }
+ return manager.parse(policyClass, policyPrefix, props, this, null);
+ }
+
private static <T> T newInstanceOf(final String className, final String
type) {
try {
return LoaderUtil.newInstanceOf(className);
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
index 7c43c15c80..a24a3515a0 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
@@ -44,6 +44,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.appender.rolling.TriggeringPolicy;
import org.apache.logging.log4j.core.Filter.Result;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
@@ -655,6 +656,12 @@ public class XmlConfiguration extends Log4j1Configuration {
return null;
}
+ public TriggeringPolicy parseTriggeringPolicy(Element policyElement) {
+ String className = subst(policyElement.getAttribute(CLASS_ATTR));
+ LOGGER.debug("Parsing triggering policy of class: \"{}\"", className);
+ return manager.parseTriggeringPolicy(className, policyElement, this);
+ }
+
/**
* Used internally to parse a level element.
*/
diff --git
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationTest.java
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationTest.java
index 3524292dc8..34fdb03d5b 100644
---
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationTest.java
+++
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationTest.java
@@ -26,6 +26,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -77,6 +78,12 @@ public abstract class AbstractLog4j1ConfigurationTest {
abstract Configuration getConfiguration(String configResourcePrefix)
throws URISyntaxException, IOException;
+ protected InputStream getResourceAsStream(String configResource) throws
IOException {
+ final InputStream is =
getClass().getClassLoader().getResourceAsStream(configResource);
+ assertNotNull(is);
+ return is;
+ }
+
protected LoggerContext configure(String configResourcePrefix) throws
URISyntaxException, IOException {
Configurator.reconfigure(getConfiguration(configResourcePrefix));
return (LoggerContext)
org.apache.logging.log4j.LogManager.getContext(false);
@@ -538,4 +545,70 @@ public abstract class AbstractLog4j1ConfigurationTest {
assertEquals(1, legacyAppender.getEvents().size());
}
}
+
+ protected void testEnhancedRollingFileAppender(Configuration
configuration) {
+ Appender appender;
+ TriggeringPolicy policy;
+ RolloverStrategy strategy;
+ DefaultRolloverStrategy defaultRolloverStrategy;
+ // Time policy with default attributes
+ appender = configuration.getAppender("DEFAULT_TIME");
+ assertTrue("is RollingFileAppender", appender instanceof
RollingFileAppender);
+ final RollingFileAppender defaultTime = (RollingFileAppender) appender;
+ assertEquals("append", true, defaultTime.getManager().isAppend());
+ assertEquals("bufferSize", 8192,
defaultTime.getManager().getBufferSize());
+ assertEquals("immediateFlush", true, defaultTime.getImmediateFlush());
+ assertEquals("fileName",
"target/EnhancedRollingFileAppender/defaultTime.log",
defaultTime.getFileName());
+ assertEquals("filePattern",
"target/EnhancedRollingFileAppender/defaultTime.%d{yyyy-MM-dd}.log",
+ defaultTime.getFilePattern());
+ policy = defaultTime.getTriggeringPolicy();
+ assertTrue("is TimeBasedTriggeringPolicy", policy instanceof
TimeBasedTriggeringPolicy);
+ // Size policy with default attributes
+ appender = configuration.getAppender("DEFAULT_SIZE");
+ assertTrue("is RollingFileAppender", appender instanceof
RollingFileAppender);
+ final RollingFileAppender defaultSize = (RollingFileAppender) appender;
+ assertEquals("append", true, defaultSize.getManager().isAppend());
+ assertEquals("bufferSize", 8192,
defaultSize.getManager().getBufferSize());
+ assertEquals("immediateFlush", true, defaultSize.getImmediateFlush());
+ assertEquals("fileName",
"target/EnhancedRollingFileAppender/defaultSize.log",
defaultSize.getFileName());
+ assertEquals("filePattern",
"target/EnhancedRollingFileAppender/defaultSize.%i.log",
+ defaultSize.getFilePattern());
+ policy = defaultSize.getTriggeringPolicy();
+ assertTrue("is SizeBasedTriggeringPolicy", policy instanceof
SizeBasedTriggeringPolicy);
+ assertEquals(10 * 1024 * 1024L, ((SizeBasedTriggeringPolicy)
policy).getMaxFileSize());
+ strategy = defaultSize.getManager().getRolloverStrategy();
+ assertTrue("is DefaultRolloverStrategy", strategy instanceof
DefaultRolloverStrategy);
+ defaultRolloverStrategy = (DefaultRolloverStrategy) strategy;
+ assertEquals(1, defaultRolloverStrategy.getMinIndex());
+ assertEquals(7, defaultRolloverStrategy.getMaxIndex());
+ // Time policy with custom attributes
+ appender = configuration.getAppender("TIME");
+ assertTrue("is RollingFileAppender", appender instanceof
RollingFileAppender);
+ final RollingFileAppender time = (RollingFileAppender) appender;
+ assertEquals("append", false, time.getManager().isAppend());
+ assertEquals("bufferSize", 1000, time.getManager().getBufferSize());
+ assertEquals("immediateFlush", false, time.getImmediateFlush());
+ assertEquals("fileName",
"target/EnhancedRollingFileAppender/time.log", time.getFileName());
+ assertEquals("filePattern",
"target/EnhancedRollingFileAppender/time.%d{yyyy-MM-dd}.log",
+ time.getFilePattern());
+ policy = time.getTriggeringPolicy();
+ assertTrue("is TimeBasedTriggeringPolicy", policy instanceof
TimeBasedTriggeringPolicy);
+ // Size policy with custom attributes
+ appender = configuration.getAppender("SIZE");
+ assertTrue("is RollingFileAppender", appender instanceof
RollingFileAppender);
+ final RollingFileAppender size = (RollingFileAppender) appender;
+ assertEquals("append", false, size.getManager().isAppend());
+ assertEquals("bufferSize", 1000, size.getManager().getBufferSize());
+ assertEquals("immediateFlush", false, size.getImmediateFlush());
+ assertEquals("fileName",
"target/EnhancedRollingFileAppender/size.log", size.getFileName());
+ assertEquals("filePattern",
"target/EnhancedRollingFileAppender/size.%i.log", size.getFilePattern());
+ policy = size.getTriggeringPolicy();
+ assertTrue("is SizeBasedTriggeringPolicy", policy instanceof
SizeBasedTriggeringPolicy);
+ assertEquals(10_000_000L, ((SizeBasedTriggeringPolicy)
policy).getMaxFileSize());
+ strategy = size.getManager().getRolloverStrategy();
+ assertTrue("is DefaultRolloverStrategy", strategy instanceof
DefaultRolloverStrategy);
+ defaultRolloverStrategy = (DefaultRolloverStrategy) strategy;
+ assertEquals(11, defaultRolloverStrategy.getMinIndex());
+ assertEquals(20, defaultRolloverStrategy.getMaxIndex());
+ }
}
diff --git
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
index d07f33871d..219848abba 100644
---
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
+++
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
@@ -64,7 +64,7 @@ public class PropertiesConfigurationTest extends
AbstractLog4j1ConfigurationTest
@Override
Configuration getConfiguration(String configResourcePrefix) throws
URISyntaxException, IOException {
final String configResource = configResourcePrefix + SUFFIX;
- final InputStream inputStream =
ClassLoader.getSystemResourceAsStream(configResource);
+ final InputStream inputStream = getResourceAsStream(configResource);
final ConfigurationSource source = new
ConfigurationSource(inputStream);
final LoggerContext context = LoggerContext.getContext(false);
final Configuration configuration = new
PropertiesConfigurationFactory().getConfiguration(context, source);
@@ -317,4 +317,13 @@ public class PropertiesConfigurationTest extends
AbstractLog4j1ConfigurationTest
super.testGlobalThreshold();
}
+ @Test
+ public void testEnhancedRollingFileAppender() throws Exception {
+ try (final LoggerContext ctx =
configure("config-1.2/log4j-EnhancedRollingFileAppender")) {
+ final Configuration configuration = ctx.getConfiguration();
+ assertNotNull(configuration);
+ testEnhancedRollingFileAppender(configuration);
+ }
+ }
+
}
diff --git
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
index e1da067b79..bec639f202 100644
---
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
+++
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
@@ -18,6 +18,7 @@ package org.apache.log4j.config;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.File;
import java.io.IOException;
@@ -34,6 +35,11 @@ import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.xml.XmlConfigurationFactory;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import
org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
+import
org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
+import
org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.junit.Test;
@@ -48,7 +54,7 @@ public class XmlConfigurationTest extends
AbstractLog4j1ConfigurationTest {
@Override
Configuration getConfiguration(String configResourcePrefix) throws
URISyntaxException, IOException {
final String configResource = configResourcePrefix + SUFFIX;
- final InputStream inputStream =
ClassLoader.getSystemResourceAsStream(configResource);
+ final InputStream inputStream = getResourceAsStream(configResource);
final ConfigurationSource source = new
ConfigurationSource(inputStream);
final LoggerContext context = LoggerContext.getContext(false);
final Configuration configuration = new
XmlConfigurationFactory().getConfiguration(context, source);
@@ -178,4 +184,22 @@ public class XmlConfigurationTest extends
AbstractLog4j1ConfigurationTest {
super.testGlobalThreshold();
}
+ @Test
+ public void testEnhancedRollingFileAppender() throws Exception {
+ try (final LoggerContext ctx =
configure("config-1.2/log4j-EnhancedRollingFileAppender")) {
+ final Configuration configuration = ctx.getConfiguration();
+ assertNotNull(configuration);
+ testEnhancedRollingFileAppender(configuration);
+ // Only supported through XML configuration
+ final Appender appender = configuration.getAppender("MIXED");
+ assertTrue("is RollingFileAppender", appender instanceof
RollingFileAppender);
+ final TriggeringPolicy policy = ((RollingFileAppender)
appender).getTriggeringPolicy();
+ assertTrue("is CompositeTriggeringPolicy", policy instanceof
CompositeTriggeringPolicy);
+ final TriggeringPolicy[] policies = ((CompositeTriggeringPolicy)
policy).getTriggeringPolicies();
+ assertEquals(2, policies.length);
+ assertTrue("is TimeBasedTriggeringPolicy", policies[0] instanceof
TimeBasedTriggeringPolicy);
+ assertTrue("is SizeBasedTriggeringPolicy", policies[1] instanceof
SizeBasedTriggeringPolicy);
+ }
+ }
+
}
diff --git
a/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.properties
b/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.properties
new file mode 100644
index 0000000000..8e59ee43c6
--- /dev/null
+++
b/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.properties
@@ -0,0 +1,66 @@
+#
+# 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.
+#
+
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, DEFAULT_TIME, DEFAULT_SIZE, TIME, SIZE
+
+log4j.appender.DEFAULT_TIME = org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.DEFAULT_TIME.layout = org.apache.log4j.SimpleLayout
+log4j.appender.DEFAULT_TIME.File =
target/EnhancedRollingFileAppender/defaultTime.log
+log4j.appender.DEFAULT_TIME.rollingPolicy =
org.apache.log4j.rolling.TimeBasedRollingPolicy
+log4j.appender.DEFAULT_TIME.rollingPolicy.FileNamePattern =
target/EnhancedRollingFileAppender/defaultTime.%d{yyyy-MM-dd}.log
+
+log4j.appender.DEFAULT_SIZE = org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.DEFAULT_SIZE.File =
target/EnhancedRollingFileAppender/defaultSize.log
+log4j.appender.DEFAULT_SIZE.layout = org.apache.log4j.SimpleLayout
+log4j.appender.DEFAULT_SIZE.triggeringPolicy =
org.apache.log4j.rolling.SizeBasedTriggeringPolicy
+log4j.appender.DEFAULT_SIZE.rollingPolicy =
org.apache.log4j.rolling.FixedWindowRollingPolicy
+log4j.appender.DEFAULT_SIZE.rollingPolicy.FileNamePattern =
target/EnhancedRollingFileAppender/defaultSize.%i.log
+
+log4j.appender.TIME = org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.TIME.Append = false
+log4j.appender.TIME.BufferedIO = true
+log4j.appender.TIME.BufferSize = 1000
+log4j.appender.TIME.File = target/EnhancedRollingFileAppender/ignoredTime.log
+log4j.appender.TIME.ImmediateFlush = false
+log4j.appender.TIME.layout = org.apache.log4j.SimpleLayout
+log4j.appender.TIME.triggeringPolicy =
org.apache.log4j.rolling.TimeBasedRollingPolicy
+# It is explicitly not a TimeBasedRolling
+log4j.appender.TIME.rollingPolicy =
org.apache.log4j.rolling.FixedWindowRollingPolicy
+log4j.appender.TIME.rollingPolicy.ActiveFileName =
target/EnhancedRollingFileAppender/time.log
+log4j.appender.TIME.rollingPolicy.FileNamePattern =
target/EnhancedRollingFileAppender/time.%d{yyyy-MM-dd}.log
+
+log4j.appender.SIZE = org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.SIZE.Append = false
+log4j.appender.SIZE.BufferedIO = true
+log4j.appender.SIZE.BufferSize = 1000
+log4j.appender.SIZE.File = target/EnhancedRollingFileAppender/ignoredSize.log
+log4j.appender.SIZE.ImmediateFlush = false
+log4j.appender.SIZE.layout = org.apache.log4j.SimpleLayout
+log4j.appender.SIZE.FileName = target/EnhancedRollingFileAppender/size.log
+log4j.appender.SIZE.triggeringPolicy =
org.apache.log4j.rolling.SizeBasedTriggeringPolicy
+log4j.appender.SIZE.triggeringPolicy.MaxFileSize = 10000000
+log4j.appender.SIZE.rollingPolicy =
org.apache.log4j.rolling.FixedWindowRollingPolicy
+log4j.appender.SIZE.rollingPolicy.ActiveFileName =
target/EnhancedRollingFileAppender/size.log
+log4j.appender.SIZE.rollingPolicy.FileNamePattern =
target/EnhancedRollingFileAppender/size.%i.log
+log4j.appender.SIZE.rollingPolicy.MinIndex = 11
+log4j.appender.SIZE.rollingPolicy.MaxIndex = 20
+
diff --git
a/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.xml
b/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.xml
new file mode 100644
index 0000000000..a1d2395c9c
--- /dev/null
+++
b/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+
+ <appender name="DEFAULT_TIME"
class="org.apache.log4j.rolling.RollingFileAppender">
+ <param name="File"
value="target/EnhancedRollingFileAppender/defaultTime.log" />
+ <layout class="org.apache.log4j.SimpleLayout" />
+ <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
+ <param name="FileNamePattern"
value="target/EnhancedRollingFileAppender/defaultTime.%d{yyyy-MM-dd}.log" />
+ </rollingPolicy>
+ </appender>
+
+ <appender name="DEFAULT_SIZE"
class="org.apache.log4j.rolling.RollingFileAppender">
+ <param name="File"
value="target/EnhancedRollingFileAppender/defaultSize.log" />
+ <layout class="org.apache.log4j.SimpleLayout" />
+ <triggeringPolicy
class="org.apache.log4j.rolling.SizeBasedTriggeringPolicy" />
+ <rollingPolicy class="org.apache.log4j.rolling.FixedWindowRollingPolicy">
+ <param name="FileNamePattern"
value="target/EnhancedRollingFileAppender/defaultSize.%i.log" />
+ </rollingPolicy>
+ </appender>
+
+ <appender name="TIME" class="org.apache.log4j.rolling.RollingFileAppender">
+ <param name="Append" value="false" />
+ <param name="BufferedIO" value="true" />
+ <param name="BufferSize" value="1000" />
+ <param name="File"
value="target/EnhancedRollingFileAppender/ignoredTime.log" />
+ <param name="ImmediateFlush" value="false" />
+ <layout class="org.apache.log4j.SimpleLayout" />
+ <triggeringPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy"
/>
+ <rollingPolicy class="org.apache.log4j.rolling.FixedWindowRollingPolicy">
+ <param name="ActiveFileName"
value="target/EnhancedRollingFileAppender/time.log" />
+ <param name="FileNamePattern"
value="target/EnhancedRollingFileAppender/time.%d{yyyy-MM-dd}.log" />
+ </rollingPolicy>
+ </appender>
+
+ <appender name="SIZE" class="org.apache.log4j.rolling.RollingFileAppender">
+ <param name="Append" value="false" />
+ <param name="BufferedIO" value="true" />
+ <param name="BufferSize" value="1000" />
+ <param name="File"
value="target/EnhancedRollingFileAppender/ignoredSize.log" />
+ <param name="ImmediateFlush" value="false" />
+ <layout class="org.apache.log4j.SimpleLayout" />
+ <triggeringPolicy
class="org.apache.log4j.rolling.SizeBasedTriggeringPolicy">
+ <param name="MaxFileSize" value="10000000" />
+ </triggeringPolicy>
+ <rollingPolicy class="org.apache.log4j.rolling.FixedWindowRollingPolicy">
+ <param name="ActiveFileName"
value="target/EnhancedRollingFileAppender/size.log" />
+ <param name="FileNamePattern"
value="target/EnhancedRollingFileAppender/size.%i.log" />
+ <param name="MinIndex" value="11" />
+ <param name="MaxIndex" value="20" />
+ </rollingPolicy>
+ </appender>
+
+ <!-- This should not work in the original Apache Extras, since
TimeBasedRollingPolicy
+ triggers a rollover every second and **must** use itself as rolling
policy.
+ -->
+ <appender name="MIXED" class="org.apache.log4j.rolling.RollingFileAppender">
+ <param name="File" value="target/EnhancedRollingFileAppender/mixed.log" />
+ <layout class="org.apache.log4j.SimpleLayout" />
+ <triggeringPolicy
class="org.apache.log4j.rolling.CompositeTriggeringPolicy">
+ <triggeringPolicy
class="org.apache.log4j.rolling.TimeBasedRollingPolicy" />
+ <triggeringPolicy
class="org.apache.log4j.rolling.SizeBasedTriggeringPolicy" />
+ </triggeringPolicy>
+ <rollingPolicy class="org.apache.log4j.rolling.FixedWindowRollingPolicy">
+ <param name="FileNamePattern"
value="target/EnhancedRollingFileAppender/mixed.%d{yyyy-MM-dd}.%i.log" />
+ </rollingPolicy>
+ </appender>
+
+ <root>
+ <priority value="trace" />
+ <appender-ref ref="DEFAULT_TIME" />
+ <appender-ref ref="DEFAULT_SIZE" />
+ <appender-ref ref="TIME" />
+ <appender-ref ref="SIZE" />
+ <appender-ref ref="MIXED" />
+ </root>
+
+</log4j:configuration>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 0b770930c7..05f2a42645 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -138,6 +138,10 @@
<action issue="LOG4J2-3362" dev="pkarwasz" type="add">
Add support for Jakarta Mail API in the SMTP appender.
</action>
+ <action issue="LOG4J2-3483" dev="pkarwasz" type="add">
+ Add support for Apache Extras' RollingFileAppender in Log4j 1.x bridge.
+ </action>
+ <!-- UPDATES -->
<action issue="LOG4J2-3428" dev="ggregory" type="fix" due-to="LF-Lin">
Update 3rd party dependencies for 2.18.0.
</action>