You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2022/03/29 14:05:43 UTC
[logging-log4j2] 23/25: Issues with multiple Log4j 1.x filters (#753)
This is an automated email from the ASF dual-hosted git repository.
pkarwasz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 3ff6b86ab225365321df7d2a6daae4fd32ac8e62
Author: ppkarwasz <pi...@karwasz.org>
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
Conflicts:
log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java
log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SocketAppenderBuilder.java
log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
log4j-1.2-api/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationTest.java
---
.../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 | 38 ++-----
.../builders/appender/AsyncAppenderBuilder.java | 39 +++----
.../builders/appender/ConsoleAppenderBuilder.java | 17 +--
.../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 | 26 +----
.../src/main/java/org/apache/log4j/spi/Filter.java | 12 --
.../org/apache/log4j/xml/XmlConfiguration.java | 48 ++++++--
.../log4j/builders/Log4j2ListAppenderBuilder.java | 98 +++++++++++++++++
.../config/AbstractLog4j1ConfigurationTest.java | 122 +++++++++++++++++++++
.../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 ++++++++++++++++
.../log4j/core/filter/CompositeFilterTest.java | 49 +++++++++
.../logging/log4j/core/filter/CompositeFilter.java | 4 +-
26 files changed, 611 insertions(+), 160 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 1353dae..3660a19 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
@@ -108,12 +108,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 1ae0369..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(new Filter[0]));
- } 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 4851125..5ce599e 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;
}
@@ -46,14 +85,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 04b439c..b73fff4 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
@@ -19,14 +19,9 @@ package org.apache.log4j.builders;
import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
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.AtomicReference;
import org.apache.log4j.bridge.FilterAdapter;
import org.apache.log4j.bridge.FilterWrapper;
@@ -34,7 +29,6 @@ import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.Filter;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.filter.CompositeFilter;
import org.apache.logging.log4j.core.filter.ThresholdFilter;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.Strings;
@@ -74,33 +68,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();
- } else {
- 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 4b8b17e..ca1aa80 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,45 +19,34 @@ 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;
import java.util.ArrayList;
import java.util.List;
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.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.FilterAdapter;
import org.apache.log4j.builders.AbstractBuilder;
import org.apache.log4j.builders.BooleanHolder;
import org.apache.log4j.builders.Holder;
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.plugins.Plugin;
import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Strings;
import org.w3c.dom.Element;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-
-import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
-import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
-import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
-import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
-import static org.apache.log4j.config.Log4j1Configuration.APPENDER_REF_TAG;
-import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
-
-
/**
* Build an Async Appender
*/
@@ -83,6 +72,7 @@ public class AsyncAppenderBuilder extends AbstractBuilder implements AppenderBui
Holder<Boolean> includeLocation = new BooleanHolder();
Holder<String> level = new Holder<>("trace");
Holder<Integer> bufferSize = new Holder<>(1024);
+ Holder<Filter> filter = new Holder<>();
forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
switch (currentElement.getTagName()) {
case APPENDER_REF_TAG:
@@ -91,6 +81,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:
@@ -110,14 +103,15 @@ public class AsyncAppenderBuilder extends AbstractBuilder implements AppenderBui
}
}
});
- return createAppender(name, level.get(), appenderRefs.get().toArray(new String[0]), blocking.get(),
- bufferSize.get(), includeLocation.get(), config);
+ return createAppender(name, level.get(), appenderRefs.get().toArray(Strings.EMPTY_ARRAY), blocking.get(),
+ 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);
@@ -131,13 +125,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];
@@ -145,8 +139,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 aa8056e..1214452 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
@@ -71,7 +71,7 @@ public class ConsoleAppenderBuilder extends AbstractBuilder implements AppenderB
String name = getNameAttribute(appenderElement);
Holder<String> target = new Holder<>(SYSTEM_OUT);
Holder<Layout> layout = new Holder<>();
- Holder<List<Filter>> filters = new Holder<>(new ArrayList<>());
+ Holder<Filter> filter = new Holder<>();
Holder<String> level = new Holder<>();
Holder<Boolean> follow = new BooleanHolder();
Holder<Boolean> immediateFlush = new BooleanHolder(true);
@@ -81,7 +81,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)) {
@@ -116,18 +116,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;
- current = 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 576ccab..78ade8c 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
@@ -82,7 +82,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 96d2f90..8ead958 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
@@ -77,7 +77,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 cac02ee..4398995 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
@@ -87,7 +87,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 3a74245..3ab8086 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
@@ -84,7 +84,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 9034f05..a2997e4 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
@@ -100,7 +100,7 @@ public class SocketAppenderBuilder extends AbstractBuilder implements AppenderBu
final Holder<Integer> port = new Holder<>(DEFAULT_PORT);
final Holder<Integer> reconnectDelay = new Holder<>(DEFAULT_RECONNECTION_DELAY);
final Holder<Layout> layout = new Holder<>();
- final Holder<List<Filter>> filters = new Holder<>(new ArrayList<>());
+ final Holder<Filter> filter = new Holder<>();
final Holder<String> level = new Holder<>();
final Holder<Boolean> immediateFlush = new BooleanHolder(true);
forEachElement(appenderElement.getChildNodes(), currentElement -> {
@@ -109,7 +109,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)) {
@@ -132,17 +132,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 fe6ee59..ffbdedf 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
@@ -85,7 +85,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 405bd4b..32a523d 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,7 +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.builders.BuilderManager;
+import org.apache.log4j.bridge.FilterAdapter;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.Filter;
@@ -44,22 +44,8 @@ import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.status.StatusConfiguration;
-import org.apache.logging.log4j.core.filter.AbstractFilterable;
import org.apache.logging.log4j.util.LoaderUtil;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.SortedMap;
-import java.util.StringTokenizer;
-import java.util.TreeMap;
-
/**
* Constructs a configuration based on Log4j 1 properties.
*/
@@ -570,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;
@@ -581,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 65b6a2c..1b05d57 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
@@ -21,6 +21,8 @@ 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.builders.Holder;
import org.apache.log4j.config.Log4j1Configuration;
import org.apache.log4j.config.PropertySetter;
import org.apache.log4j.helpers.OptionConverter;
@@ -375,7 +377,8 @@ public class XmlConfiguration extends Log4j1Configuration {
PropertySetter propSetter = new PropertySetter(appender);
appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
- forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+ final Holder<Filter> filterChain = new Holder<>();
+ forEachElement(appenderElement.getChildNodes(), currentElement -> {
// Parse appender parameters
switch (currentElement.getTagName()) {
case PARAM_TAG:
@@ -385,12 +388,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);
@@ -417,6 +415,10 @@ public class XmlConfiguration extends Log4j1Configuration {
}
}
});
+ final Filter head = filterChain.get();
+ if (head != null) {
+ appender.addFilter(head);
+ }
propSetter.activate();
return appender;
} catch (ConsumerException ex) {
@@ -502,12 +504,30 @@ public class XmlConfiguration extends Log4j1Configuration {
* @param filterElement The Filter Element.
* @return The Filter.
*/
+ public void addFilter(final Holder<Filter> ref, final Element filterElement) {
+ final Filter filter = parseFilters(filterElement);
+ final Filter newFilter = FilterAdapter.addFilter(ref.get(), filter);
+ ref.set(newFilter);
+ }
+
+ /**
+ * 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)) {
@@ -517,8 +537,20 @@ public class XmlConfiguration extends Log4j1Configuration {
}
});
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..ccef99b
--- /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.test.appender.ListAppender;
+import org.apache.logging.log4j.plugins.Plugin;
+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 Holder<Layout> layout = new Holder<>();
+ final Holder<Filter> filter = new Holder<>();
+ 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 21c9b7e..e4ac132 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");
@@ -378,4 +400,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.core.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 85d2859..21534f5 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
@@ -21,7 +21,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;
@@ -114,9 +113,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());
}
}
@@ -180,6 +179,7 @@ public class PropertiesConfigurationTest extends AbstractLog4j1ConfigurationTest
}
}
+
@Override
@Test
public void testConsoleEnhancedPatternLayout() throws Exception {
@@ -263,4 +263,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 6cacbf8..98ac3ba 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
@@ -186,4 +186,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-test/src/test/java/org/apache/logging/log4j/core/filter/CompositeFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/CompositeFilterTest.java
new file mode 100644
index 0000000..0a5698b
--- /dev/null
+++ b/log4j-core-test/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());
+ }
+}
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 4ac1a3f..5b870b4 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
@@ -63,9 +63,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);
}