This is an automated email from the ASF dual-hosted git repository.
ggregory 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 d87a307 Issues with multiple Log4j 1.x filters (#753)
d87a307 is described below
commit d87a3073af1e87281e961c4bd5a9b733aa912488
Author: ppkarwasz <[email protected]>
AuthorDate: Sat Feb 19 17:05:20 2022 +0100
Issues with multiple Log4j 1.x filters (#753)
* Fix issues with multiple Log4j 1.x filters
This PR fixes a couple of issues concerning filters in the Log4j 1.x
bridge:
- there is an endless loop in `FilterAdapter#filter` that hangs the
program if more than one filter is configured,
- filters are executed multiple times per log message.
The second problem comes from chains of Log4j 1.x filters: a filter
chain is split into a `CompositeFilter` of `FilterAdapter`s (one for
each filter). Each `FilterAdapter` executes its own filter and all those
that come later in the chain.
In order to preserve the behavior of `FilterAdapter` the following
restrictions have been applied to the generated filters:
1. no chains of Log4j 1.x filters are generated by the configuration; a
list of Log4j 1.x filters is represented as a wrapped `CompositeFilter`
of `FilterAdapter`s,
2. the factories don't generate any `FilterWrapper`s of
`FilterAdapter`s nor `FilterAdapter`s of `FilterWrapper`s.
* Import and whitespace fixes
* More unused import fixes
* Adds regression test for CompositeFilter
---
.../java/org/apache/log4j/AppenderSkeleton.java | 5 +-
.../org/apache/log4j/PropertyConfigurator.java | 5 +-
.../org/apache/log4j/bridge/AppenderAdapter.java | 16 +--
.../org/apache/log4j/bridge/AppenderWrapper.java | 6 +-
.../org/apache/log4j/bridge/FilterAdapter.java | 43 ++++++-
.../org/apache/log4j/builders/AbstractBuilder.java | 31 ++----
.../builders/appender/AsyncAppenderBuilder.java | 20 +++-
.../builders/appender/ConsoleAppenderBuilder.java | 16 +--
.../appender/DailyRollingFileAppenderBuilder.java | 2 +-
.../builders/appender/FileAppenderBuilder.java | 2 +-
.../builders/appender/RewriteAppenderBuilder.java | 2 +-
.../appender/RollingFileAppenderBuilder.java | 2 +-
.../builders/appender/SocketAppenderBuilder.java | 16 +--
.../builders/appender/SyslogAppenderBuilder.java | 2 +-
.../log4j/config/PropertiesConfiguration.java | 11 +-
.../src/main/java/org/apache/log4j/spi/Filter.java | 12 --
.../org/apache/log4j/xml/XmlConfiguration.java | 55 +++++++--
.../log4j/builders/Log4j2ListAppenderBuilder.java | 98 ++++++++++++++++
.../config/AbstractLog4j1ConfigurationTest.java | 124 ++++++++++++++++++++-
.../log4j/config/PropertiesConfigurationTest.java | 12 +-
.../org/apache/log4j/config/StartsWithFilter.java | 38 +++++++
.../apache/log4j/config/XmlConfigurationTest.java | 6 +
.../resources/log4j-multipleFilters.properties | 69 ++++++++++++
.../src/test/resources/log4j-multipleFilters.xml | 92 +++++++++++++++
.../logging/log4j/core/filter/CompositeFilter.java | 4 +-
.../log4j/core/filter/CompositeFilterTest.java | 49 ++++++++
26 files changed, 613 insertions(+), 125 deletions(-)
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/AppenderSkeleton.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/AppenderSkeleton.java
index 5bdabc0..7fbd92a 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/AppenderSkeleton.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/AppenderSkeleton.java
@@ -106,12 +106,9 @@ public abstract class AppenderSkeleton implements
Appender, OptionHandler {
return ((threshold == null) || priority.isGreaterOrEqual(threshold));
}
- /**
- * This method is never going to be called in Log4j 2 so there isn't much
point in having any code in it.
- * @param event The LoggingEvent.
- */
@Override
public void doAppend(final LoggingEvent event) {
+ // Threshold checks and filtering is performed by the AppenderWrapper.
append(event);
}
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java
index d522d57..483096e 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java
@@ -30,6 +30,7 @@ import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
+import org.apache.log4j.bridge.FilterAdapter;
import org.apache.log4j.config.PropertiesConfiguration;
import org.apache.log4j.config.PropertySetter;
import org.apache.log4j.helpers.FileWatchdog;
@@ -520,6 +521,7 @@ public class PropertyConfigurator implements Configurator {
// sort filters by IDs, insantiate filters, set filter options,
// add filters to the appender
final Enumeration g = new SortedKeyEnumeration(filters);
+ Filter head = null;
while (g.hasMoreElements()) {
final String key = (String) g.nextElement();
final String clazz = properties.getProperty(key);
@@ -536,12 +538,13 @@ public class PropertyConfigurator implements Configurator
{
}
propSetter.activate();
LogLog.debug("Adding filter of type [" + filter.getClass()
+ "] to appender named [" + appender.getName() + "].");
- appender.addFilter(filter);
+ head = FilterAdapter.addFilter(head, filter);
}
} else {
LogLog.warn("Missing class definition for filter: [" + key +
"]");
}
}
+ appender.addFilter(head);
}
/**
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
index b2163c6..3334535 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
@@ -26,7 +26,6 @@ import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.core.filter.CompositeFilter;
/**
* Binds a Log4j 1.x Appender to Log4j 2.
@@ -42,20 +41,7 @@ public class AppenderAdapter {
*/
public AppenderAdapter(Appender appender) {
this.appender = appender;
- org.apache.logging.log4j.core.Filter appenderFilter = null;
- if (appender.getFilter() != null) {
- if (appender.getFilter().getNext() != null) {
- org.apache.log4j.spi.Filter filter = appender.getFilter();
- List<org.apache.logging.log4j.core.Filter> filters = new
ArrayList<>();
- while (filter != null) {
- filters.add(new FilterAdapter(filter));
- filter = filter.getNext();
- }
- appenderFilter =
CompositeFilter.createFilters(filters.toArray(Filter.EMPTY_ARRAY));
- } else {
- appenderFilter = new FilterAdapter(appender.getFilter());
- }
- }
+ final org.apache.logging.log4j.core.Filter appenderFilter =
FilterAdapter.convertFilter(appender.getFilter());
this.adapter = new Adapter(appender.getName(), appenderFilter, null,
true, null);
}
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
index d26c878..3d28fd7 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
@@ -55,11 +55,7 @@ public class AppenderWrapper implements Appender {
@Override
public void addFilter(Filter newFilter) {
if (appender instanceof AbstractFilterable) {
- if (newFilter instanceof FilterWrapper) {
- ((AbstractFilterable) appender).addFilter(((FilterWrapper)
newFilter).getFilter());
- } else {
- ((AbstractFilterable) appender).addFilter(new
FilterAdapter(newFilter));
- }
+ ((AbstractFilterable)
appender).addFilter(FilterAdapter.convertFilter(newFilter));
} else {
LOGGER.warn("Unable to add filter to appender {}, it does not
support filters", appender.getName());
}
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/FilterAdapter.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/FilterAdapter.java
index adab346..e10478c 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/FilterAdapter.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/FilterAdapter.java
@@ -20,6 +20,7 @@ import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.filter.AbstractFilter;
+import org.apache.logging.log4j.core.filter.CompositeFilter;
/**
* Binds a Log4j 1.x Filter with Log4j 2.
@@ -28,6 +29,44 @@ public class FilterAdapter extends AbstractFilter {
private final Filter filter;
+ /**
+ * Converts a Log4j 1.x filter into a Log4j 2.x filter.
+ *
+ * @param filter
+ * a Log4j 1.x filter
+ * @return a Log4j 2.x filter
+ */
+ public static org.apache.logging.log4j.core.Filter convertFilter(Filter
filter) {
+ if (filter instanceof FilterWrapper && filter.getNext() == null) {
+ return ((FilterWrapper) filter).getFilter();
+ } else if (filter != null) {
+ return new FilterAdapter(filter);
+ }
+ return null;
+ }
+
+ /**
+ * Appends one filter to another using Log4j 2.x concatenation utilities.
+ * @param first
+ * @param second
+ * @return
+ */
+ public static Filter addFilter(Filter first, Filter second) {
+ if (first == null) {
+ return second;
+ }
+ if (second == null) {
+ return first;
+ }
+ final CompositeFilter composite;
+ if (first instanceof FilterWrapper && ((FilterWrapper)
first).getFilter() instanceof CompositeFilter) {
+ composite = (CompositeFilter) ((FilterWrapper) first).getFilter();
+ } else {
+ composite = CompositeFilter.createFilters(new
org.apache.logging.log4j.core.Filter[] {convertFilter(first)});
+ }
+ return new FilterWrapper(composite.addFilter(convertFilter(second)));
+ }
+
public FilterAdapter(Filter filter) {
this.filter = filter;
}
@@ -37,14 +76,14 @@ public class FilterAdapter extends AbstractFilter {
LoggingEvent loggingEvent = new LogEventAdapter(event);
Filter next = filter;
while (next != null) {
- switch (filter.decide(loggingEvent)) {
+ switch (next.decide(loggingEvent)) {
case Filter.ACCEPT:
return Result.ACCEPT;
case Filter.DENY:
return Result.DENY;
default:
}
- next = filter.getNext();
+ next = next.getNext();
}
return Result.NEUTRAL;
}
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 6ed0304..cefb2bd 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
@@ -74,32 +74,17 @@ public abstract class AbstractBuilder implements Builder {
props.entrySet().forEach(e ->
this.properties.put(toBeanKey(e.getKey().toString()), e.getValue()));
}
- protected org.apache.logging.log4j.core.Filter buildFilters(final String
level, final Filter filter) {
- if (level != null && filter != null) {
- final List<org.apache.logging.log4j.core.Filter> filterList = new
ArrayList<>();
+ protected static org.apache.logging.log4j.core.Filter buildFilters(final
String level, final Filter filter) {
+ Filter head = null;
+ if (level != null) {
final org.apache.logging.log4j.core.Filter thresholdFilter =
ThresholdFilter.createFilter(OptionConverter.convertLevel(level, Level.TRACE),
org.apache.logging.log4j.core.Filter.Result.NEUTRAL,
org.apache.logging.log4j.core.Filter.Result.DENY);
- filterList.add(thresholdFilter);
- Filter f = filter;
- while (f != null) {
- if (filter instanceof FilterWrapper) {
- filterList.add(((FilterWrapper) f).getFilter());
- } else {
- filterList.add(new FilterAdapter(f));
- }
- f = f.getNext();
- }
- return
CompositeFilter.createFilters(filterList.toArray(org.apache.logging.log4j.core.Filter.EMPTY_ARRAY));
- } else if (level != null) {
- return
ThresholdFilter.createFilter(OptionConverter.convertLevel(level, Level.TRACE),
org.apache.logging.log4j.core.Filter.Result.NEUTRAL,
- org.apache.logging.log4j.core.Filter.Result.DENY);
- } else if (filter != null) {
- if (filter instanceof FilterWrapper) {
- return ((FilterWrapper) filter).getFilter();
- }
- return new FilterAdapter(filter);
+ head = new FilterWrapper(thresholdFilter);
+ }
+ if (filter != null) {
+ head = FilterAdapter.addFilter(head, filter);
}
- return null;
+ return FilterAdapter.convertFilter(head);
}
private String capitalize(final String value) {
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java
index d70a55d..87f602c 100644
---
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java
@@ -19,6 +19,7 @@ package org.apache.log4j.builders.appender;
import static org.apache.log4j.builders.BuilderManager.CATEGORY;
import static org.apache.log4j.config.Log4j1Configuration.APPENDER_REF_TAG;
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.PARAM_TAG;
import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
@@ -31,13 +32,16 @@ import java.util.concurrent.atomic.AtomicReference;
import org.apache.log4j.Appender;
import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.FilterAdapter;
import org.apache.log4j.builders.AbstractBuilder;
import org.apache.log4j.config.Log4j1Configuration;
import org.apache.log4j.config.PropertiesConfiguration;
import org.apache.log4j.helpers.OptionConverter;
+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.AsyncAppender;
+import org.apache.logging.log4j.core.appender.AsyncAppender.Builder;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.status.StatusLogger;
@@ -70,6 +74,7 @@ public class AsyncAppenderBuilder extends AbstractBuilder
implements AppenderBui
final AtomicBoolean includeLocation = new AtomicBoolean();
final AtomicReference<String> level = new AtomicReference<>("trace");
final AtomicInteger bufferSize = new AtomicInteger(1024);
+ final AtomicReference<Filter> filter = new AtomicReference<>();
forEachElement(appenderElement.getChildNodes(), currentElement -> {
switch (currentElement.getTagName()) {
case APPENDER_REF_TAG:
@@ -78,6 +83,9 @@ public class AsyncAppenderBuilder extends AbstractBuilder
implements AppenderBui
appenderRefs.get().add(appender.getName());
}
break;
+ case FILTER_TAG:
+ config.addFilter(filter, currentElement);
+ break;
case PARAM_TAG: {
switch (getNameAttributeKey(currentElement)) {
case BUFFER_SIZE_PARAM:
@@ -98,13 +106,14 @@ public class AsyncAppenderBuilder extends AbstractBuilder
implements AppenderBui
}
});
return createAppender(name, level.get(),
appenderRefs.get().toArray(Strings.EMPTY_ARRAY), blocking.get(),
- bufferSize.get(), includeLocation.get(), config);
+ bufferSize.get(), includeLocation.get(), filter.get(), config);
}
@Override
public Appender parseAppender(final String name, final String
appenderPrefix, final String layoutPrefix,
final String filterPrefix, final Properties props, final
PropertiesConfiguration configuration) {
final String appenderRef = getProperty(APPENDER_REF_TAG);
+ final Filter filter = configuration.parseAppenderFilters(props,
filterPrefix, name);
final boolean blocking = getBooleanProperty(BLOCKING_PARAM);
final boolean includeLocation =
getBooleanProperty(INCLUDE_LOCATION_PARAM);
final String level = getProperty(THRESHOLD_PARAM);
@@ -118,13 +127,13 @@ public class AsyncAppenderBuilder extends AbstractBuilder
implements AppenderBui
LOGGER.warn("Cannot locate Appender {}", appenderRef);
return null;
}
- return createAppender(name, level, new String[] {appenderRef},
blocking, bufferSize, includeLocation,
+ return createAppender(name, level, new String[]{appenderRef},
blocking, bufferSize, includeLocation, filter,
configuration);
}
private <T extends Log4j1Configuration> Appender createAppender(final
String name, final String level,
final String[] appenderRefs, final boolean blocking, final int
bufferSize, final boolean includeLocation,
- final T configuration) {
+ final Filter filter, final T configuration) {
final org.apache.logging.log4j.Level logLevel =
OptionConverter.convertLevel(level,
org.apache.logging.log4j.Level.TRACE);
final AppenderRef[] refs = new AppenderRef[appenderRefs.length];
@@ -132,8 +141,9 @@ public class AsyncAppenderBuilder extends AbstractBuilder
implements AppenderBui
for (final String appenderRef : appenderRefs) {
refs[index++] = AppenderRef.createAppenderRef(appenderRef,
logLevel, null);
}
- return new AppenderWrapper(AsyncAppender.newBuilder()
- .setName(name)
+ Builder builder = AsyncAppender.newBuilder();
+ builder.setFilter(FilterAdapter.convertFilter(filter));
+ return new AppenderWrapper(builder.setName(name)
.setAppenderRefs(refs)
.setBlocking(blocking)
.setBufferSize(bufferSize)
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
index 0abee05..e745416 100644
---
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
@@ -70,7 +70,7 @@ public class ConsoleAppenderBuilder extends AbstractBuilder
implements AppenderB
final String name = getNameAttribute(appenderElement);
final AtomicReference<String> target = new
AtomicReference<>(SYSTEM_OUT);
final AtomicReference<Layout> layout = new AtomicReference<>();
- final AtomicReference<List<Filter>> filters = new
AtomicReference<>(new ArrayList<>());
+ final AtomicReference<Filter> filter = new AtomicReference<>();
final AtomicReference<String> level = new AtomicReference<>();
final AtomicBoolean follow = new AtomicBoolean();
final AtomicBoolean immediateFlush = new AtomicBoolean(true);
@@ -80,7 +80,7 @@ public class ConsoleAppenderBuilder extends AbstractBuilder
implements AppenderB
layout.set(config.parseLayout(currentElement));
break;
case FILTER_TAG:
- filters.get().add(config.parseFilters(currentElement));
+ config.addFilter(filter, currentElement);
break;
case PARAM_TAG: {
switch (getNameAttributeKey(currentElement)) {
@@ -115,17 +115,7 @@ public class ConsoleAppenderBuilder extends
AbstractBuilder implements AppenderB
}
}
});
- Filter head = null;
- Filter current = null;
- for (final Filter f : filters.get()) {
- if (head == null) {
- head = f;
- } else {
- current.next = f;
- }
- current = f;
- }
- return createAppender(name, layout.get(), head, level.get(),
target.get(), immediateFlush.get(), follow.get(), config);
+ return createAppender(name, layout.get(), filter.get(), level.get(),
target.get(), immediateFlush.get(), follow.get(), config);
}
@Override
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
index ae43088..7c0575b 100644
---
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
@@ -85,7 +85,7 @@ public class DailyRollingFileAppenderBuilder extends
AbstractBuilder implements
layout.set(config.parseLayout(currentElement));
break;
case FILTER_TAG:
- filter.set(config.parseFilters(currentElement));
+ config.addFilter(filter, currentElement);
break;
case PARAM_TAG:
switch (getNameAttributeKey(currentElement)) {
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
index 8903cb6..e461324 100644
---
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
@@ -76,7 +76,7 @@ public class FileAppenderBuilder extends AbstractBuilder
implements AppenderBuil
layout.set(config.parseLayout(currentElement));
break;
case FILTER_TAG:
- filter.set(config.parseFilters(currentElement));
+ config.addFilter(filter, currentElement);
break;
case PARAM_TAG:
switch (getNameAttributeKey(currentElement)) {
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RewriteAppenderBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RewriteAppenderBuilder.java
index 0cc8557..28102be 100644
---
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RewriteAppenderBuilder.java
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RewriteAppenderBuilder.java
@@ -86,7 +86,7 @@ public class RewriteAppenderBuilder extends AbstractBuilder
implements AppenderB
}
break;
case FILTER_TAG:
- filter.set(config.parseFilters(currentElement));
+ config.addFilter(filter, currentElement);
break;
case PARAM_TAG:
if
(getNameAttributeKey(currentElement).equalsIgnoreCase(THRESHOLD_PARAM)) {
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
index 604747e..4c168d9 100644
---
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
@@ -85,7 +85,7 @@ public class RollingFileAppenderBuilder extends
AbstractBuilder implements Appen
layout.set(config.parseLayout(currentElement));
break;
case FILTER_TAG:
- filter.set(config.parseFilters(currentElement));
+ config.addFilter(filter, currentElement);
break;
case PARAM_TAG:
switch (getNameAttributeKey(currentElement)) {
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SocketAppenderBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SocketAppenderBuilder.java
index 82c74ae..a48a08a 100644
---
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SocketAppenderBuilder.java
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SocketAppenderBuilder.java
@@ -101,7 +101,7 @@ public class SocketAppenderBuilder extends AbstractBuilder
implements AppenderBu
final AtomicInteger port = new AtomicInteger(DEFAULT_PORT);
final AtomicInteger reconnectDelay = new
AtomicInteger(DEFAULT_RECONNECTION_DELAY);
final AtomicReference<Layout> layout = new AtomicReference<>();
- final AtomicReference<List<Filter>> filters = new
AtomicReference<>(new ArrayList<>());
+ final AtomicReference<Filter> filter = new AtomicReference<>();
final AtomicReference<String> level = new AtomicReference<>();
final AtomicBoolean immediateFlush = new AtomicBoolean(true);
forEachElement(appenderElement.getChildNodes(), currentElement -> {
@@ -110,7 +110,7 @@ public class SocketAppenderBuilder extends AbstractBuilder
implements AppenderBu
layout.set(config.parseLayout(currentElement));
break;
case FILTER_TAG:
- filters.get().add(config.parseFilters(currentElement));
+ config.addFilter(filter, currentElement);
break;
case PARAM_TAG:
switch (getNameAttributeKey(currentElement)) {
@@ -133,17 +133,7 @@ public class SocketAppenderBuilder extends AbstractBuilder
implements AppenderBu
break;
}
});
- Filter head = null;
- Filter current = null;
- for (final Filter f : filters.get()) {
- if (head == null) {
- head = f;
- } else {
- current.next = f;
- }
- current = f;
- }
- return createAppender(name, host.get(), port.get(), layout.get(),
head, level.get(), immediateFlush.get(), reconnectDelay.get(), config);
+ return createAppender(name, host.get(), port.get(), layout.get(),
filter.get(), level.get(), immediateFlush.get(), reconnectDelay.get(), config);
}
@Override
diff --git
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
index 83fe788..7d7947c 100644
---
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
+++
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
@@ -84,7 +84,7 @@ public class SyslogAppenderBuilder extends AbstractBuilder
implements AppenderBu
layout.set(config.parseLayout(currentElement));
break;
case FILTER_TAG:
- filter.set(config.parseFilters(currentElement));
+ config.addFilter(filter, currentElement);
break;
case PARAM_TAG:
switch (getNameAttributeKey(currentElement)) {
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 0b77118..06b8854 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
@@ -35,6 +35,7 @@ import org.apache.log4j.LogManager;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.bridge.AppenderAdapter;
import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.FilterAdapter;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.Filter;
@@ -555,7 +556,6 @@ public class PropertiesConfiguration extends
Log4j1Configuration {
}
Filter head = null;
- Filter next = null;
for (final Map.Entry<String, List<NameValue>> entry :
filters.entrySet()) {
final String clazz = props.getProperty(entry.getKey());
Filter filter = null;
@@ -566,14 +566,7 @@ public class PropertiesConfiguration extends
Log4j1Configuration {
filter = buildFilter(clazz, appenderName,
entry.getValue());
}
}
- if (filter != null) {
- if (head == null) {
- head = filter;
- } else {
- next.setNext(filter);
- }
- next = filter;
- }
+ head = FilterAdapter.addFilter(head, filter);
}
return head;
}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Filter.java
b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Filter.java
index 17a15d6..91917ab 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Filter.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Filter.java
@@ -16,8 +16,6 @@
*/
package org.apache.log4j.spi;
-import org.apache.log4j.bridge.FilterAdapter;
-
/**
* @since 0.9.0
*/
@@ -32,16 +30,6 @@ public abstract class Filter {
}
isCorePresent = temp;
}
-
- // TODO Unused?
- private final FilterAdapter adapter;
-
- /**
- * Constructs a new instance.
- */
- public Filter() {
- this.adapter = isCorePresent ? new FilterAdapter(this) : null;
- }
/**
* The log event must be dropped immediately without consulting
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 cdf4e14..3821188 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
@@ -22,6 +22,7 @@ import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import javax.xml.parsers.DocumentBuilder;
@@ -33,6 +34,7 @@ import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.bridge.AppenderAdapter;
import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.FilterAdapter;
import org.apache.log4j.config.Log4j1Configuration;
import org.apache.log4j.config.PropertySetter;
import org.apache.log4j.helpers.OptionConverter;
@@ -371,6 +373,7 @@ public class XmlConfiguration extends Log4j1Configuration {
PropertySetter propSetter = new PropertySetter(appender);
appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
+ final AtomicReference<Filter> filterChain = new
AtomicReference<>();
forEachElement(appenderElement.getChildNodes(), currentElement -> {
// Parse appender parameters
switch (currentElement.getTagName()) {
@@ -381,12 +384,7 @@ public class XmlConfiguration extends Log4j1Configuration {
appender.setLayout(parseLayout(currentElement));
break;
case FILTER_TAG:
- Filter filter = parseFilters(currentElement);
- if (filter != null) {
- LOGGER.debug("Adding filter of type [{}] to
appender named [{}]",
- filter.getClass(), appender.getName());
- appender.addFilter(filter);
- }
+ addFilter(filterChain, currentElement);
break;
case ERROR_HANDLER_TAG:
parseErrorHandler(currentElement, appender);
@@ -413,6 +411,10 @@ public class XmlConfiguration extends Log4j1Configuration {
}
}
});
+ final Filter head = filterChain.get();
+ if (head != null) {
+ appender.addFilter(head);
+ }
propSetter.activate();
return appender;
} catch (ConsumerException ex) {
@@ -494,23 +496,52 @@ public class XmlConfiguration extends Log4j1Configuration
{
/**
* Used internally to parse a filter element.
*/
+ public void addFilter(final AtomicReference<Filter> ref, final Element
filterElement) {
+ final Filter value = parseFilters(filterElement);
+ ref.accumulateAndGet(value, FilterAdapter::addFilter);
+ }
+
+ /**
+ * Used internally to parse a filter element.
+ */
public Filter parseFilters(Element filterElement) {
String className = subst(filterElement.getAttribute(CLASS_ATTR));
LOGGER.debug("Class name: [" + className + ']');
Filter filter = manager.parseFilter(className, filterElement, this);
if (filter == null) {
+ filter = buildFilter(className, filterElement);
+ }
+ return filter;
+ }
+
+ private Filter buildFilter(final String className, final Element
filterElement) {
+ try {
+ Filter filter = LoaderUtil.newInstanceOf(className);
PropertySetter propSetter = new PropertySetter(filter);
+
forEachElement(filterElement.getChildNodes(), currentElement -> {
- String tagName = currentElement.getTagName();
- if (tagName.equals(PARAM_TAG)) {
- setParameter(currentElement, propSetter);
- } else {
- quietParseUnrecognizedElement(filter, currentElement,
props);
+ // Parse appender parameters
+ switch (currentElement.getTagName()) {
+ case PARAM_TAG :
+ setParameter(currentElement, propSetter);
+ break;
}
});
propSetter.activate();
+ return filter;
+ } catch (ConsumerException ex) {
+ Throwable t = ex.getCause();
+ if (t instanceof InterruptedException || t instanceof
InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ LOGGER.error("Could not create an Filter. Reported error
follows.", t);
+ } catch (Exception oops) {
+ if (oops instanceof InterruptedException || oops instanceof
InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ LOGGER.error("Could not create an Filter. Reported error
follows.", oops);
}
- return filter;
+ return null;
}
/**
diff --git
a/log4j-1.2-api/src/test/java/org/apache/log4j/builders/Log4j2ListAppenderBuilder.java
b/log4j-1.2-api/src/test/java/org/apache/log4j/builders/Log4j2ListAppenderBuilder.java
new file mode 100644
index 0000000..825a083
--- /dev/null
+++
b/log4j-1.2-api/src/test/java/org/apache/log4j/builders/Log4j2ListAppenderBuilder.java
@@ -0,0 +1,98 @@
+/*
+ * 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;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+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.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+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.bridge.LayoutWrapper;
+import org.apache.log4j.builders.appender.AppenderBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.w3c.dom.Element;
+
+/**
+ * Builder for the native Log4j 2.x list appender to be used in the tests.
+ */
+@Plugin(name = "org.apache.logging.log4j.test.appender.ListAppender", category
= CATEGORY)
+public class Log4j2ListAppenderBuilder extends AbstractBuilder implements
AppenderBuilder {
+
+ public Log4j2ListAppenderBuilder() {
+ }
+
+ public Log4j2ListAppenderBuilder(final String prefix, final Properties
props) {
+ super(prefix, props);
+ }
+
+ @Override
+ public Appender parseAppender(Element element, XmlConfiguration
configuration) {
+ final String name = getNameAttribute(element);
+ final AtomicReference<Layout> layout = new AtomicReference<>();
+ final AtomicReference<Filter> filter = new AtomicReference<>();
+ forEachElement(element.getChildNodes(), currentElement -> {
+ switch (currentElement.getTagName()) {
+ case LAYOUT_TAG :
+ layout.set(configuration.parseLayout(currentElement));
+ break;
+ case FILTER_TAG :
+ configuration.addFilter(filter, currentElement);
+ break;
+ default :
+ }
+ });
+ return createAppender(name, layout.get(), filter.get());
+ }
+
+ @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);
+ return createAppender(name, layout, filter);
+ }
+
+ private Appender createAppender(String name, Layout layout, Filter filter)
{
+ final org.apache.logging.log4j.core.Layout<?> log4j2Layout;
+ if (layout instanceof LayoutWrapper) {
+ log4j2Layout = ((LayoutWrapper) layout).getLayout();
+ } else {
+ log4j2Layout = layout != null ? new LayoutAdapter(layout) : null;
+ }
+ return new AppenderWrapper(
+ ListAppender.newBuilder()
+ .setName(name)
+ .setLayout(log4j2Layout)
+ .setFilter(AbstractBuilder.buildFilters(null, filter))
+ .build());
+ }
+}
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 bb3e0e3..675c287 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
@@ -17,7 +17,9 @@
package org.apache.log4j.config;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
@@ -33,9 +35,16 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
+import org.apache.log4j.ListAppender;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.bridge.FilterAdapter;
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.bridge.AppenderAdapter.Adapter;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.appender.ConsoleAppender.Target;
import org.apache.logging.log4j.core.appender.FileAppender;
@@ -49,15 +58,28 @@ 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.Configurator;
import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.filter.CompositeFilter;
+import org.apache.logging.log4j.core.filter.Filterable;
import org.apache.logging.log4j.core.layout.HtmlLayout;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
public abstract class AbstractLog4j1ConfigurationTest {
+ @Rule
+ public TemporaryFolder tempFolder =
TemporaryFolder.builder().assureDeletion().build();
+
abstract Configuration getConfiguration(String configResourcePrefix)
throws URISyntaxException, IOException;
+ private LoggerContext configure(String configResourcePrefix) throws
URISyntaxException, IOException {
+ Configurator.reconfigure(getConfiguration(configResourcePrefix));
+ return (LoggerContext)
org.apache.logging.log4j.LogManager.getContext(false);
+ }
+
public void testConsoleCapitalization() throws Exception {
final Configuration config =
getConfiguration("config-1.2/log4j-capitalization");
final Appender capitalized = config.getAppender("ConsoleCapitalized");
@@ -307,7 +329,7 @@ public abstract class AbstractLog4j1ConfigurationTest {
final Field appendField =
FileOutputStream.class.getDeclaredField("append");
appendField.setAccessible(true);
return (Boolean) appendField.get(os);
- } catch (NoSuchFieldError e) {
+ } catch (NoSuchFieldError | NoSuchFieldException e) {
// Java 11
final Field appendField =
FileDescriptor.class.getDeclaredField("append");
appendField.setAccessible(true);
@@ -385,4 +407,104 @@ public abstract class AbstractLog4j1ConfigurationTest {
config.start();
config.stop();
}
+
+ /**
+ * Checks a hierarchy of filters.
+ *
+ * @param filter
+ * @return the number of filters
+ */
+ private int checkFilters(final org.apache.logging.log4j.core.Filter
filter) {
+ int count = 0;
+ if (filter instanceof CompositeFilter) {
+ for (final org.apache.logging.log4j.core.Filter part :
((CompositeFilter) filter).getFiltersArray()) {
+ count += checkFilters(part);
+ }
+ } else if (filter instanceof FilterAdapter) {
+ // Don't create adapters from wrappers
+ assertFalse("found FilterAdapter of a FilterWrapper",
((FilterAdapter) filter).getFilter() instanceof FilterWrapper);
+ count += checkFilters(((FilterAdapter) filter).getFilter());
+ } else {
+ count++;
+ }
+ return count;
+ }
+
+ /**
+ * Checks a hierarchy of filters.
+ *
+ * @param filter
+ * @return the number of filters
+ */
+ private int checkFilters(final org.apache.log4j.spi.Filter filter) {
+ int count = 0;
+ if (filter instanceof FilterWrapper) {
+ // Don't create wrappers from adapters
+ assertFalse("found FilterWrapper of a FilterAdapter",
((FilterWrapper) filter).getFilter() instanceof FilterAdapter);
+ count += checkFilters(((FilterWrapper) filter).getFilter());
+ } else {
+ count++;
+ }
+ // We prefer a:
+ // CompositeFilter of native Log4j 2.x filters
+ // over a:
+ // FilterAdapter of a chain of FilterWrappers.
+ assertNull("found chain of Log4j 1.x filters", filter.getNext());
+ return count;
+ }
+
+ public void testMultipleFilters() throws Exception {
+ final File folder = tempFolder.newFolder();
+ System.setProperty("test.tmpDir", folder.getCanonicalPath());
+ try (LoggerContext loggerContext = configure("log4j-multipleFilters"))
{
+ final Configuration configuration =
loggerContext.getConfiguration();
+ assertNotNull(configuration);
+ // Check only number of filters.
+ final Filterable console = configuration.getAppender("CONSOLE");
+ assertNotNull(console);
+ assertEquals(4, checkFilters(console.getFilter()));
+ final Filterable file = configuration.getAppender("FILE");
+ assertNotNull(file);
+ assertEquals(4, checkFilters(file.getFilter()));
+ final Filterable rfa = configuration.getAppender("RFA");
+ assertNotNull(rfa);
+ assertEquals(4, checkFilters(rfa.getFilter()));
+ final Filterable drfa = configuration.getAppender("DRFA");
+ assertNotNull(drfa);
+ assertEquals(4, checkFilters(drfa.getFilter()));
+ // List appenders
+ final Appender appender = configuration.getAppender("LIST");
+ assertNotNull(appender);
+ assertEquals(3, checkFilters(((Filterable)appender).getFilter()));
+ final ListAppender legacyAppender = (ListAppender) ((Adapter)
appender).getAppender();
+ final org.apache.logging.log4j.test.appender.ListAppender
nativeAppender = configuration.getAppender("LIST2");
+ assertEquals(3,
checkFilters(((Filterable)nativeAppender).getFilter()));
+ final Logger logger =
LogManager.getLogger(PropertiesConfigurationTest.class);
+ int expected = 0;
+ // message blocked by Threshold
+ logger.trace("NEUTRAL message");
+ assertEquals(expected, legacyAppender.getEvents().size());
+ assertEquals(expected, nativeAppender.getEvents().size());
+ // message blocked by DenyAll filter
+ logger.warn("NEUTRAL message");
+ assertEquals(expected, legacyAppender.getEvents().size());
+ assertEquals(expected, nativeAppender.getEvents().size());
+ // message accepted by level filter
+ logger.info("NEUTRAL message");
+ expected++;
+ assertEquals(expected, legacyAppender.getEvents().size());
+ assertEquals(expected, nativeAppender.getEvents().size());
+ // message accepted by "StartsWith" filter
+ logger.warn("ACCEPT message");
+ expected++;
+ assertEquals(expected, legacyAppender.getEvents().size());
+ assertEquals(expected, nativeAppender.getEvents().size());
+ // message blocked by "StartsWith" filter
+ logger.info("DENY message");
+ assertEquals(expected, legacyAppender.getEvents().size());
+ assertEquals(expected, nativeAppender.getEvents().size());
+ } finally {
+ System.clearProperty("test.tmpDir");
+ }
+ }
}
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 ad8b8d1..06288f7 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
@@ -32,7 +32,6 @@ import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.bridge.AppenderAdapter;
import org.apache.log4j.bridge.FilterAdapter;
-import org.apache.log4j.bridge.FilterWrapper;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
@@ -118,9 +117,9 @@ public class PropertiesConfigurationTest extends
AbstractLog4j1ConfigurationTest
final Filterable filterable = (Filterable) appender;
final CompositeFilter filter = (CompositeFilter)
filterable.getFilter();
final org.apache.logging.log4j.core.Filter[] filters =
filter.getFiltersArray();
- final LevelRangeFilter customFilterReal = (LevelRangeFilter)
((FilterWrapper) ((FilterAdapter) filters[0]).getFilter()).getFilter();
+ final LevelRangeFilter customFilterReal = (LevelRangeFilter)
filters[0];
assertEquals(Level.ALL, customFilterReal.getMinLevel());
- final LevelRangeFilter defaultFilter = (LevelRangeFilter)
((FilterWrapper) ((FilterAdapter) filters[1]).getFilter()).getFilter();
+ final LevelRangeFilter defaultFilter = (LevelRangeFilter)
filters[1];
assertEquals(Level.TRACE, defaultFilter.getMinLevel());
}
}
@@ -184,6 +183,7 @@ public class PropertiesConfigurationTest extends
AbstractLog4j1ConfigurationTest
}
}
+
@Override
@Test
public void testConsoleEnhancedPatternLayout() throws Exception {
@@ -267,4 +267,10 @@ public class PropertiesConfigurationTest extends
AbstractLog4j1ConfigurationTest
public void testDefaultValues() throws Exception {
super.testDefaultValues();
}
+
+ @Override
+ @Test
+ public void testMultipleFilters() throws Exception {
+ super.testMultipleFilters();
+ }
}
diff --git
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/StartsWithFilter.java
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/StartsWithFilter.java
new file mode 100644
index 0000000..db16d84
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/StartsWithFilter.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.log4j.spi.Filter;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * A Filter used in tests.
+ */
+public class StartsWithFilter extends Filter {
+
+ @Override
+ public int decide(LoggingEvent event) {
+ String message = String.valueOf(event.getMessage());
+ if (message.startsWith("DENY")) {
+ return DENY;
+ } else if (message.startsWith("ACCEPT")) {
+ return ACCEPT;
+ }
+ return NEUTRAL;
+ }
+
+}
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 d5d07cf..219880e 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
@@ -166,4 +166,10 @@ public class XmlConfigurationTest extends
AbstractLog4j1ConfigurationTest {
super.testDefaultValues();
}
+ @Override
+ @Test
+ public void testMultipleFilters() throws Exception {
+ super.testMultipleFilters();
+ }
+
}
diff --git a/log4j-1.2-api/src/test/resources/log4j-multipleFilters.properties
b/log4j-1.2-api/src/test/resources/log4j-multipleFilters.properties
new file mode 100644
index 0000000..177d60c
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j-multipleFilters.properties
@@ -0,0 +1,69 @@
+#
+# 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.appender.LIST=org.apache.log4j.ListAppender
+log4j.appender.LIST.Threshold=DEBUG
+log4j.appender.LIST.filter.1=org.apache.log4j.config.StartsWithFilter
+log4j.appender.LIST.filter.2=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.LIST.filter.2.LevelToMatch=INFO
+log4j.appender.LIST.filter.2.AcceptOnMatch=true
+log4j.appender.LIST.filter.3=org.apache.log4j.varia.DenyAllFilter
+
+log4j.appender.LIST2=org.apache.logging.log4j.test.appender.ListAppender
+log4j.appender.LIST2.Threshold=DEBUG
+log4j.appender.LIST2.filter.1=org.apache.log4j.config.StartsWithFilter
+log4j.appender.LIST2.filter.2=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.LIST2.filter.2.LevelToMatch=INFO
+log4j.appender.LIST2.filter.2.AcceptOnMatch=true
+log4j.appender.LIST2.filter.3=org.apache.log4j.varia.DenyAllFilter
+
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.Threshold=DEBUG
+log4j.appender.CONSOLE.filter.1=org.apache.log4j.config.StartsWithFilter
+log4j.appender.CONSOLE.filter.2=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.CONSOLE.filter.2.LevelToMatch=INFO
+log4j.appender.CONSOLE.filter.2.AcceptOnMatch=true
+log4j.appender.CONSOLE.filter.3=org.apache.log4j.varia.DenyAllFilter
+
+log4j.appender.FILE=org.apache.log4j.FileAppender
+log4j.appender.FILE.Threshold=DEBUG
+log4j.appender.FILE.File=${test.tmpDir}/file-appender.log
+log4j.appender.FILE.filter.1=org.apache.log4j.config.StartsWithFilter
+log4j.appender.FILE.filter.2=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.FILE.filter.2.LevelToMatch=INFO
+log4j.appender.FILE.filter.2.AcceptOnMatch=true
+log4j.appender.FILE.filter.3=org.apache.log4j.varia.DenyAllFilter
+
+log4j.appender.RFA=org.apache.log4j.RollingFileAppender
+log4j.appender.RFA.Threshold=DEBUG
+log4j.appender.RFA.File=${test.tmpDir}/rolling-file-appender.log
+log4j.appender.RFA.filter.1=org.apache.log4j.config.StartsWithFilter
+log4j.appender.RFA.filter.2=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.RFA.filter.2.LevelToMatch=INFO
+log4j.appender.RFA.filter.2.AcceptOnMatch=true
+log4j.appender.RFA.filter.3=org.apache.log4j.varia.DenyAllFilter
+
+log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.DRFA.Threshold=DEBUG
+log4j.appender.DRFA.File=${test.tmpDir}/daily-rolling-file-appender.log
+log4j.appender.DRFA.filter.1=org.apache.log4j.config.StartsWithFilter
+log4j.appender.DRFA.filter.2=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.DRFA.filter.2.LevelToMatch=INFO
+log4j.appender.DRFA.filter.2.AcceptOnMatch=true
+log4j.appender.DRFA.filter.3=org.apache.log4j.varia.DenyAllFilter
+
+log4j.rootLogger=TRACE, LIST, LIST2, CONSOLE, FILE, RFA, DRFA
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j-multipleFilters.xml
b/log4j-1.2-api/src/test/resources/log4j-multipleFilters.xml
new file mode 100644
index 0000000..ea256e7
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j-multipleFilters.xml
@@ -0,0 +1,92 @@
+<?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="LIST" class="org.apache.log4j.ListAppender">
+ <param name="Threshold" value="DEBUG" />
+ <filter class="org.apache.log4j.config.StartsWithFilter" />
+ <filter class="org.apache.log4j.varia.LevelMatchFilter">
+ <param name="LevelToMatch" value="INFO" />
+ <param name="AcceptOnMatch" value="true" />
+ </filter>
+ <filter class="org.apache.log4j.varia.DenyAllFilter" />
+ </appender>
+
+ <appender name="LIST2"
class="org.apache.logging.log4j.test.appender.ListAppender">
+ <param name="Threshold" value="DEBUG" />
+ <filter class="org.apache.log4j.config.StartsWithFilter" />
+ <filter class="org.apache.log4j.varia.LevelMatchFilter">
+ <param name="LevelToMatch" value="INFO" />
+ <param name="AcceptOnMatch" value="true" />
+ </filter>
+ <filter class="org.apache.log4j.varia.DenyAllFilter" />
+ </appender>
+
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <param name="Threshold" value="DEBUG" />
+ <filter class="org.apache.log4j.config.StartsWithFilter" />
+ <filter class="org.apache.log4j.varia.LevelMatchFilter">
+ <param name="LevelToMatch" value="INFO" />
+ <param name="AcceptOnMatch" value="true" />
+ </filter>
+ <filter class="org.apache.log4j.varia.DenyAllFilter" />
+ </appender>
+
+ <appender name="FILE" class="org.apache.log4j.FileAppender">
+ <param name="Threshold" value="DEBUG" />
+ <param name="File" value="${test.tmpDir}/file-appender.log" />
+ <filter class="org.apache.log4j.config.StartsWithFilter" />
+ <filter class="org.apache.log4j.varia.LevelMatchFilter">
+ <param name="LevelToMatch" value="INFO" />
+ <param name="AcceptOnMatch" value="true" />
+ </filter>
+ <filter class="org.apache.log4j.varia.DenyAllFilter" />
+ </appender>
+
+ <appender name="RFA" class="org.apache.log4j.RollingFileAppender">
+ <param name="Threshold" value="DEBUG" />
+ <param name="File" value="${test.tmpDir}/rolling-file-appender.log" />
+ <filter class="org.apache.log4j.config.StartsWithFilter" />
+ <filter class="org.apache.log4j.varia.LevelMatchFilter">
+ <param name="LevelToMatch" value="INFO" />
+ <param name="AcceptOnMatch" value="true" />
+ </filter>
+ <filter class="org.apache.log4j.varia.DenyAllFilter" />
+ </appender>
+
+ <appender name="DRFA" class="org.apache.log4j.DailyRollingFileAppender">
+ <param name="Threshold" value="DEBUG" />
+ <param name="File" value="${test.tmpDir}/daily-rolling-file-appender.log"
/>
+ <filter class="org.apache.log4j.config.StartsWithFilter" />
+ <filter class="org.apache.log4j.varia.LevelMatchFilter">
+ <param name="LevelToMatch" value="INFO" />
+ <param name="AcceptOnMatch" value="true" />
+ </filter>
+ <filter class="org.apache.log4j.varia.DenyAllFilter" />
+ </appender>
+
+ <root>
+ <priority value="TRACE" />
+ <appender-ref ref="LIST" />
+ <appender-ref ref="LIST2" />
+ <appender-ref ref="CONSOLE" />
+ <appender-ref ref="FILE" />
+ <appender-ref ref="RFA" />
+ <appender-ref ref="DRFA" />
+ </root>
+</log4j:configuration>
diff --git
a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/CompositeFilter.java
b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/CompositeFilter.java
index 6286876..43a8c0d 100644
---
a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/CompositeFilter.java
+++
b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/CompositeFilter.java
@@ -62,9 +62,9 @@ public final class CompositeFilter extends AbstractLifeCycle
implements Iterable
if (filter instanceof CompositeFilter) {
final int size = this.filters.length + ((CompositeFilter)
filter).size();
final Filter[] copy = Arrays.copyOf(this.filters, size);
- final int index = this.filters.length;
+ int index = this.filters.length;
for (final Filter currentFilter : ((CompositeFilter)
filter).filters) {
- copy[index] = currentFilter;
+ copy[index++] = currentFilter;
}
return new CompositeFilter(copy);
}
diff --git
a/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/CompositeFilterTest.java
b/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/CompositeFilterTest.java
new file mode 100644
index 0000000..0a5698b
--- /dev/null
+++
b/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/CompositeFilterTest.java
@@ -0,0 +1,49 @@
+/* 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.logging.log4j.core.filter;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Filter.Result;
+import org.junit.jupiter.api.Test;
+
+public class CompositeFilterTest {
+
+ @Test
+ public void testConcatenation() {
+ final Filter a =
DenyAllFilter.newBuilder().setOnMatch(Result.ACCEPT).build();
+ final Filter b =
DenyAllFilter.newBuilder().setOnMatch(Result.NEUTRAL).build();
+ final Filter c =
DenyAllFilter.newBuilder().setOnMatch(Result.DENY).build();
+ // The three values need to be distinguishable
+ assertNotEquals(a, b);
+ assertNotEquals(a, c);
+ assertNotEquals(b, c);
+ final Filter[] expected = new Filter[] {a, b, c};
+ final CompositeFilter singleA = CompositeFilter.createFilters(new
Filter[] {a});
+ final CompositeFilter singleB = CompositeFilter.createFilters(new
Filter[] {b});
+ final CompositeFilter singleC = CompositeFilter.createFilters(new
Filter[] {c});
+ // Concatenating one at a time
+ final CompositeFilter concat1 = singleA.addFilter(b).addFilter(c);
+ assertArrayEquals(expected, concat1.getFiltersArray());
+ // In reverse order
+ final CompositeFilter concat2 =
singleA.addFilter(singleB.addFilter(singleC));
+ assertArrayEquals(expected, concat2.getFiltersArray());
+ }
+}