You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2012/09/30 01:35:58 UTC

svn commit: r1391925 - in /logging/log4j/log4j2/trunk: core/src/main/java/org/apache/logging/log4j/core/filter/ core/src/test/java/org/apache/logging/log4j/core/filter/ core/src/test/resources/ src/changes/ src/site/xdoc/manual/

Author: rgoers
Date: Sat Sep 29 23:35:58 2012
New Revision: 1391925

URL: http://svn.apache.org/viewvc?rev=1391925&view=rev
Log:
Fix LOG4J2-92 - Converted DynamicThresholdFilter to use KeyValuePair. Fixed bugs in the Map-based filters to allow declaration of multiple values for a key to match the documentation.

Added:
    logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-dynamicfilter.xml
    logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-mapfilter.xml
      - copied, changed from r1391705, logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-config.xml
Removed:
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/ValueLevelPair.java
Modified:
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/MapFilter.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilterTest.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/MapFilterTest.java
    logging/log4j/log4j2/trunk/src/changes/changes.xml
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/filters.xml

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java?rev=1391925&r1=1391924&r2=1391925&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java Sat Sep 29 23:35:58 2012
@@ -25,6 +25,7 @@ import org.apache.logging.log4j.core.con
 import org.apache.logging.log4j.core.config.plugins.PluginAttr;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.helpers.KeyValuePair;
 import org.apache.logging.log4j.message.Message;
 
 import java.util.HashMap;
@@ -87,6 +88,10 @@ public final class DynamicThresholdFilte
 
     }
 
+    public Map<String, Level> getLevelMap() {
+        return levelMap;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -118,15 +123,15 @@ public final class DynamicThresholdFilte
      */
     @PluginFactory
     public static DynamicThresholdFilter createFilter(@PluginAttr("key") String key,
-                                                      @PluginElement("pairs") ValueLevelPair[] pairs,
+                                                      @PluginElement("pairs") KeyValuePair[] pairs,
                                                       @PluginAttr("defaultThreshold") String level,
                                                       @PluginAttr("onmatch") String match,
                                                       @PluginAttr("onmismatch") String mismatch) {
         Result onMatch = match == null ? null : Result.valueOf(match.toUpperCase());
         Result onMismatch = mismatch == null ? null : Result.valueOf(mismatch.toUpperCase());
         Map<String, Level> map = new HashMap<String, Level>();
-        for (ValueLevelPair pair : pairs) {
-            map.put(pair.getKey(), pair.getLevel());
+        for (KeyValuePair pair : pairs) {
+            map.put(pair.getKey(), Level.toLevel(pair.getValue().toUpperCase()));
         }
         Level l = Level.toLevel(level, Level.ERROR);
         return new DynamicThresholdFilter(key, map, l, onMatch, onMismatch);

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/MapFilter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/MapFilter.java?rev=1391925&r1=1391924&r2=1391925&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/MapFilter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/MapFilter.java Sat Sep 29 23:35:58 2012
@@ -22,12 +22,15 @@ import org.apache.logging.log4j.core.Log
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.config.plugins.PluginAttr;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
 import org.apache.logging.log4j.core.helpers.KeyValuePair;
 import org.apache.logging.log4j.message.MapMessage;
 import org.apache.logging.log4j.message.Message;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -35,11 +38,11 @@ import java.util.Map;
  */
 @Plugin(name = "MapFilter", type = "Core", elementType = "filter", printObject = true)
 public class MapFilter extends FilterBase {
-    private final Map<String, String> map;
+    private final Map<String, List<String>> map;
 
     private final boolean isAnd;
 
-    protected MapFilter(Map<String, String> map, boolean oper, Result onMatch, Result onMismatch) {
+    protected MapFilter(Map<String, List<String>> map, boolean oper, Result onMatch, Result onMismatch) {
         super(onMatch, onMismatch);
         if (map == null) {
             throw new NullPointerException("key cannot be null");
@@ -51,7 +54,7 @@ public class MapFilter extends FilterBas
     @Override
     public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
         if (msg instanceof MapMessage) {
-            return filter((MapMessage) msg);
+            return filter(((MapMessage) msg).getData()) ? onMatch : onMismatch;
         }
         return Result.NEUTRAL;
     }
@@ -60,21 +63,25 @@ public class MapFilter extends FilterBas
     public Result filter(LogEvent event) {
         Message msg = event.getMessage();
         if (msg instanceof MapMessage) {
-            return filter((MapMessage) msg);
+            return filter(((MapMessage) msg).getData()) ? onMatch : onMismatch;
         }
         return Result.NEUTRAL;
     }
 
-    protected Result filter(MapMessage msg) {
+    protected boolean filter(Map<String, String> data) {
         boolean match = false;
-        for (String key : map.keySet()) {
-            String data = msg.getData().get(key);
-            match = map.get(key).equals(data);
+        for (Map.Entry<String, List<String>> entry : map.entrySet()) {
+            String toMatch = data.get(entry.getKey());
+            if (toMatch != null) {
+                match = entry.getValue().contains(toMatch);
+            } else {
+                match = false;
+            }
             if ((!isAnd && match) || (isAnd && !match)) {
                 break;
             }
         }
-        return match ? onMatch : onMismatch;
+        return match;
     }
 
     @Override
@@ -84,12 +91,14 @@ public class MapFilter extends FilterBas
         if (map.size() > 0) {
             sb.append(", {");
             boolean first = true;
-            for (Map.Entry<String, String> entry : map.entrySet()) {
+            for (Map.Entry<String, List<String>> entry : map.entrySet()) {
                 if (!first) {
                     sb.append(", ");
                 }
                 first = false;
-                sb.append(entry.getKey()).append("=").append(entry.getValue());
+                List<String> list = entry.getValue();
+                String value = list.size() > 1 ? list.get(0) : list.toString();
+                sb.append(entry.getKey()).append("=").append(value);
             }
             sb.append("}");
         }
@@ -100,20 +109,20 @@ public class MapFilter extends FilterBas
         return isAnd;
     }
 
-    protected Map<String, String> getMap() {
+    protected Map<String, List<String>> getMap() {
         return map;
     }
 
     @PluginFactory
-    public static MapFilter createFilter(@PluginAttr("pairs") KeyValuePair[] pairs,
-                                                    @PluginAttr("operator") String oper,
-                                                    @PluginAttr("onmatch") String match,
-                                                    @PluginAttr("onmismatch") String mismatch) {
+    public static MapFilter createFilter(@PluginElement("pairs") KeyValuePair[] pairs,
+                                         @PluginAttr("operator") String oper,
+                                         @PluginAttr("onmatch") String match,
+                                         @PluginAttr("onmismatch") String mismatch) {
         if (pairs == null || pairs.length == 0) {
             LOGGER.error("keys and values must be specified for the MapFilter");
             return null;
         }
-        Map<String, String> map = new HashMap<String, String>();
+        Map<String, List<String>> map = new HashMap<String, List<String>>();
         for (KeyValuePair pair : pairs) {
             String key = pair.getKey();
             if (key == null) {
@@ -125,7 +134,14 @@ public class MapFilter extends FilterBas
                 LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
                 continue;
             }
-            map.put(pair.getKey(), pair.getValue());
+            List<String> list = map.get(pair.getKey());
+            if (list != null) {
+                list.add(value);
+            } else {
+                list = new ArrayList<String>();
+                list.add(value);
+                map.put(pair.getKey(), list);
+            }
         }
         if (map.size() == 0) {
             LOGGER.error("MapFilter is not configured with any valid key value pairs");

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java?rev=1391925&r1=1391924&r2=1391925&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java Sat Sep 29 23:35:58 2012
@@ -24,11 +24,12 @@ import org.apache.logging.log4j.core.con
 import org.apache.logging.log4j.core.config.plugins.PluginAttr;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
 import org.apache.logging.log4j.core.helpers.KeyValuePair;
-import org.apache.logging.log4j.message.MapMessage;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.StructuredDataMessage;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -37,7 +38,7 @@ import java.util.Map;
 @Plugin(name = "StructuredDataFilter", type = "Core", elementType = "filter", printObject = true)
 public final class StructuredDataFilter extends MapFilter {
 
-    private StructuredDataFilter(Map<String, String> map, boolean oper, Result onMatch, Result onMismatch) {
+    private StructuredDataFilter(Map<String, List<String>> map, boolean oper, Result onMatch, Result onMismatch) {
         super(map, oper, onMatch, onMismatch);
     }
 
@@ -55,29 +56,17 @@ public final class StructuredDataFilter 
         if (msg instanceof StructuredDataMessage) {
             return filter((StructuredDataMessage) msg);
         }
-        return Result.NEUTRAL;
+        return super.filter(event);
     }
 
-    @Override
-    protected Result filter(MapMessage message) {
-        if (!(message instanceof StructuredDataMessage)) {
-            return super.filter(message);
-        }
-        StructuredDataMessage msg = (StructuredDataMessage) message;
+    protected Result filter(StructuredDataMessage message) {
         boolean match = false;
-        Map<String, String> map = getMap();
-        for (String key : map.keySet()) {
-            if (key.equalsIgnoreCase("id")) {
-                match = map.get(key).equals(msg.getId().toString());
-            } else if (key.equalsIgnoreCase("id.name")) {
-                match = map.get(key).equals(msg.getId().getName());
-            } else if (key.equalsIgnoreCase("type")) {
-                match = map.get(key).equals(msg.getType());
-            } else if (key.equalsIgnoreCase("message")) {
-                match = map.get(key).equals(msg.getFormattedMessage().toString());
+        for (Map.Entry<String, List<String>> entry : getMap().entrySet()) {
+            String toMatch = getValue(message, entry.getKey());
+            if (toMatch != null) {
+                match = entry.getValue().contains(toMatch);
             } else {
-                String data = msg.getData().get(key).toString();
-                match = map.get(key).equals(data);
+                match = false;
             }
             if ((!isAnd() && match) || (isAnd() && !match)) {
                 break;
@@ -86,23 +75,18 @@ public final class StructuredDataFilter 
         return match ? onMatch : onMismatch;
     }
 
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("isAnd=").append(isAnd());
-        if (getMap().size() > 0) {
-            sb.append(", {");
-            boolean first = true;
-            for (Map.Entry<String, String> entry : getMap().entrySet()) {
-                if (!first) {
-                    sb.append(", ");
-                }
-                first = false;
-                sb.append(entry.getKey()).append("=").append(entry.getValue());
-            }
-            sb.append("}");
+    private String getValue(StructuredDataMessage data, String key) {
+        if (key.equalsIgnoreCase("id")) {
+            return data.getId().toString();
+        } else if (key.equalsIgnoreCase("id.name")) {
+            return data.getId().getName();
+        } else if (key.equalsIgnoreCase("type")) {
+            return data.getType();
+        } else if (key.equalsIgnoreCase("message")) {
+            return data.getFormattedMessage();
+        } else {
+            return data.getData().get(key);
         }
-        return sb.toString();
     }
 
     /**
@@ -122,19 +106,26 @@ public final class StructuredDataFilter 
             LOGGER.error("keys and values must be specified for the StructuredDataFilter");
             return null;
         }
-        Map<String, String> map = new HashMap<String, String>();
+        Map<String, List<String>> map = new HashMap<String, List<String>>();
         for (KeyValuePair pair : pairs) {
             String key = pair.getKey();
             if (key == null) {
-                LOGGER.error("A null key is not valid in StructuredDataFilter");
+                LOGGER.error("A null key is not valid in MapFilter");
                 continue;
             }
             String value = pair.getValue();
             if (value == null) {
-                LOGGER.error("A null value for key " + key + " is not allowed in StructuredDataFilter");
+                LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
                 continue;
             }
-            map.put(pair.getKey(), pair.getValue());
+            List<String> list = map.get(pair.getKey());
+            if (list != null) {
+                list.add(value);
+            } else {
+                list = new ArrayList<String>();
+                list.add(value);
+                map.put(pair.getKey(), list);
+            }
         }
         if (map.size() == 0) {
             LOGGER.error("StructuredDataFilter is not configured with any valid key value pairs");

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java?rev=1391925&r1=1391924&r2=1391925&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java Sat Sep 29 23:35:58 2012
@@ -28,37 +28,38 @@ import org.apache.logging.log4j.core.con
 import org.apache.logging.log4j.core.helpers.KeyValuePair;
 import org.apache.logging.log4j.message.Message;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 /**
  * Filter based on a value in the Thread Context Map (MDC).
  */
 @Plugin(name = "ThreadContextMapFilter", type = "Core", elementType = "filter", printObject = true)
-public class ThreadContextMapFilter extends FilterBase {
-    private final Map<String, String> map;
+public class ThreadContextMapFilter extends MapFilter {
 
     private final String key;
     private final String value;
 
-    private final boolean isAnd;
-
     private final boolean useMap;
 
-    public ThreadContextMapFilter(Map<String, String> pairs, boolean oper, Result onMatch, Result onMismatch) {
-        super(onMatch, onMismatch);
+    public ThreadContextMapFilter(Map<String, List<String>> pairs, boolean oper, Result onMatch, Result onMismatch) {
+        super(pairs, oper, onMatch, onMismatch);
         if (pairs.size() == 1) {
-            Iterator<Map.Entry<String, String>> iter = pairs.entrySet().iterator();
-            Map.Entry<String, String> entry = iter.next();
-            this.key = entry.getKey();
-            this.value = entry.getValue();
-            this.map = null;
-            this.isAnd = false;
-            this.useMap = false;
+            Iterator<Map.Entry<String, List<String>>> iter = pairs.entrySet().iterator();
+            Map.Entry<String, List<String>> entry = iter.next();
+            if (entry.getValue().size() == 1) {
+                this.key = entry.getKey();
+                this.value = entry.getValue().get(0);
+                this.useMap = false;
+            } else {
+                this.key = null;
+                this.value = null;
+                this.useMap = true;
+            }
         } else {
-            this.map = pairs;
-            this.isAnd = oper;
             this.key = null;
             this.value = null;
             this.useMap = true;
@@ -83,9 +84,14 @@ public class ThreadContextMapFilter exte
     private Result filter() {
         boolean match = false;
         if (useMap) {
-            for (String key : map.keySet()) {
-                match = map.get(key).equals(ThreadContext.get(key));
-                if ((!isAnd && match) || (isAnd && !match)) {
+            for (Map.Entry<String, List<String>> entry : getMap().entrySet()) {
+                String toMatch = ThreadContext.get(entry.getKey());
+                if (toMatch != null) {
+                    match = entry.getValue().contains(toMatch);
+                } else {
+                    match = false;
+                }
+                if ((!isAnd() && match) || (isAnd() && !match)) {
                     break;
                 }
             }
@@ -97,38 +103,7 @@ public class ThreadContextMapFilter exte
 
     @Override
     public Result filter(LogEvent event) {
-        Map<String, String> ctx = event.getContextMap();
-        boolean match = false;
-        for (String key : map.keySet()) {
-            match = map.get(key).equals(ctx.get(key));
-            if ((!isAnd && match) || (isAnd && !match)) {
-                break;
-            }
-        }
-        return match ? onMatch : onMismatch;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("isAnd=").append(isAnd);
-        if (useMap) {
-            if (map.size() > 0) {
-                sb.append(", {");
-               boolean first = true;
-                for (Map.Entry<String, String> entry : map.entrySet()) {
-                    if (!first) {
-                        sb.append(", ");
-                    }
-                    first = false;
-                    sb.append(entry.getKey()).append("=").append(entry.getValue());
-                }
-                sb.append("}");
-          }
-        } else {
-            sb.append(", {").append(key).append("=").append(value).append("}");
-        }
-        return sb.toString();
+        return super.filter(event.getContextMap()) ? onMatch : onMismatch;
     }
 
     @PluginFactory
@@ -140,19 +115,26 @@ public class ThreadContextMapFilter exte
             LOGGER.error("key and value pairs must be specified for the ThreadContextMapFilter");
             return null;
         }
-        Map<String, String> map = new HashMap<String, String>();
+        Map<String, List<String>> map = new HashMap<String, List<String>>();
         for (KeyValuePair pair : pairs) {
             String key = pair.getKey();
             if (key == null) {
-                LOGGER.error("A null key is not valid in ThreadContextMapFilter");
+                LOGGER.error("A null key is not valid in MapFilter");
                 continue;
             }
             String value = pair.getValue();
             if (value == null) {
-                LOGGER.error("A null value for key " + key + " is not allowed in ThreadContextMapFilter");
+                LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
                 continue;
             }
-            map.put(pair.getKey(), pair.getValue());
+            List<String> list = map.get(pair.getKey());
+            if (list != null) {
+                list.add(value);
+            } else {
+                list = new ArrayList<String>();
+                list.add(value);
+                map.put(pair.getKey(), list);
+            }
         }
         if (map.size() == 0) {
             LOGGER.error("ThreadContextMapFilter is not configured with any valid key value pairs");

Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilterTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilterTest.java?rev=1391925&r1=1391924&r2=1391925&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilterTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilterTest.java Sat Sep 29 23:35:58 2012
@@ -17,26 +17,45 @@
 package org.apache.logging.log4j.core.filter;
 
 import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.core.helpers.KeyValuePair;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.junit.After;
 import org.junit.Test;
 
+import java.util.Map;
+
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
 
 /**
  *
  */
 public class DynamicThresholdFilterTest {
 
+    @After
+    public void cleanup() {
+        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+        ctx.reconfigure();
+        StatusLogger.getLogger().reset();
+    }
+
     @Test
     public void testFilter() {
         ThreadContext.put("userid", "testuser");
         ThreadContext.put("organization", "apache");
-        ValueLevelPair[] pairs = new ValueLevelPair[] { new ValueLevelPair("testuser", Level.DEBUG),
-                                                         new ValueLevelPair("JohnDoe", Level.WARN)};
+        KeyValuePair[] pairs = new KeyValuePair[] { new KeyValuePair("testuser", "DEBUG"),
+                                                    new KeyValuePair("JohnDoe", "warn")};
         DynamicThresholdFilter filter = DynamicThresholdFilter.createFilter("userid", pairs, "ERROR", null, null);
         filter.start();
         assertTrue(filter.isStarted());
@@ -51,4 +70,20 @@ public class DynamicThresholdFilterTest 
         assertTrue(filter.filter(event) == Filter.Result.NEUTRAL);
         ThreadContext.clear();
     }
+
+    @Test
+    public void testConfig() {
+        LoggerContext ctx = Configurator.initialize("Test1", null, "target/test-classes/log4j2-dynamicFilter.xml");
+        Configuration config = ctx.getConfiguration();
+        Filter filter = config.getFilter();
+        assertNotNull("No DynamicThresholdFilter", filter);
+        assertTrue("Not a DynamicThresholdFilter", filter instanceof DynamicThresholdFilter);
+        DynamicThresholdFilter dynamic = (DynamicThresholdFilter) filter;
+        String key = dynamic.getKey();
+        assertNotNull("Key is null", key);
+        assertTrue("Incorrect key value", key.equals("loginId"));
+        Map<String, Level> map = dynamic.getLevelMap();
+        assertNotNull("Map is null", map);
+        assertTrue("Incorrect number of map elements", map.size() == 1);
+    }
 }

Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/MapFilterTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/MapFilterTest.java?rev=1391925&r1=1391924&r2=1391925&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/MapFilterTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/MapFilterTest.java Sat Sep 29 23:35:58 2012
@@ -17,12 +17,28 @@
 package org.apache.logging.log4j.core.filter;
 
 import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.Configurator;
 import org.apache.logging.log4j.core.helpers.KeyValuePair;
 import org.apache.logging.log4j.message.MapMessage;
-import org.apache.logging.log4j.message.StructuredDataMessage;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 /**
@@ -30,6 +46,12 @@ import static org.junit.Assert.assertTru
  */
 public class MapFilterTest {
 
+    @After
+    public void cleanup() {
+        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+        ctx.reconfigure();
+        StatusLogger.getLogger().reset();
+    }
 
     @Test
     public void testFilter() {
@@ -42,9 +64,9 @@ public class MapFilterTest {
         msg.put("FromAccount", "211000");
         msg.put("Amount", "1000.00");
         assertTrue(filter.isStarted());
-        assertTrue(filter.filter(null, Level.DEBUG, null, msg, (Throwable)null) == Filter.Result.NEUTRAL);
+        assertTrue(filter.filter(null, Level.DEBUG, null, msg, null) == Filter.Result.NEUTRAL);
         msg.put("ToAccount", "111111");
-        assertTrue(filter.filter(null, Level.ERROR, null, msg, (Throwable)null) == Filter.Result.DENY);
+        assertTrue(filter.filter(null, Level.ERROR, null, msg, null) == Filter.Result.DENY);
         filter = MapFilter.createFilter(pairs, "or", null, null);
         filter.start();
         msg = new MapMessage();
@@ -52,8 +74,37 @@ public class MapFilterTest {
         msg.put("FromAccount", "211000");
         msg.put("Amount", "1000.00");
         assertTrue(filter.isStarted());
-        assertTrue(filter.filter(null, Level.DEBUG, null, msg, (Throwable)null) == Filter.Result.NEUTRAL);
+        assertTrue(filter.filter(null, Level.DEBUG, null, msg, null) == Filter.Result.NEUTRAL);
         msg.put("ToAccount", "111111");
-        assertTrue(filter.filter(null, Level.ERROR, null, msg, (Throwable)null) == Filter.Result.NEUTRAL);
+        assertTrue(filter.filter(null, Level.ERROR, null, msg, null) == Filter.Result.NEUTRAL);
+    }
+
+    @Test
+    public void testConfig() {
+        LoggerContext ctx = Configurator.initialize("Test1", null, "target/test-classes/log4j2-mapfilter.xml");
+        Configuration config = ctx.getConfiguration();
+        Filter filter = config.getFilter();
+        assertNotNull("No MapFilter", filter);
+        assertTrue("Not a MapFilter", filter instanceof  MapFilter);
+        MapFilter mapFilter = (MapFilter) filter;
+        assertFalse("Should not be And filter", mapFilter.isAnd());
+        Map<String, List<String>> map = mapFilter.getMap();
+        assertNotNull("No Map", map == null);
+        assertTrue("No elements in Map", map.size() != 0);
+        assertTrue("Incorrect number of elements in Map", map.size() == 1);
+        assertTrue("Map does not contain key eventId", map.containsKey("eventId"));
+        assertTrue("List does not contain 2 elements", map.get("eventId").size() == 2);
+        Logger logger = LogManager.getLogger(MapFilterTest.class);
+        Map<String, String> eventMap = new HashMap<String, String>();
+        eventMap.put("eventId", "Login");
+        logger.debug(new MapMessage(eventMap));
+        Map<String,Appender> appenders = config.getAppenders();
+        Appender app = appenders.get("LIST");
+        assertNotNull("No List appender", app);
+        List<String> msgs = ((ListAppender) app).getMessages();
+        assertNotNull("No messages", msgs);
+        assertTrue("No messages", msgs.size() > 0);
+
+
     }
 }

Added: logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-dynamicfilter.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-dynamicfilter.xml?rev=1391925&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-dynamicfilter.xml (added)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-dynamicfilter.xml Sat Sep 29 23:35:58 2012
@@ -0,0 +1,33 @@
+<?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.
+
+-->
+<configuration name="ConfigTest" status="error" packages="org.apache.logging.log4j.test">
+  <DynamicThresholdFilter key="loginId" defaultThreshold="ERROR" onMatch="ACCEPT" onMismatch="NEUTRAL">
+    <KeyValuePair key="User1" value="DEBUG"/>
+  </DynamicThresholdFilter>
+  <appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m%n"/>
+    </Console>
+  </appenders>
+  <loggers>
+    <root level="error">
+      <appender-ref ref="STDOUT"/>
+    </root>
+  </loggers>
+</configuration>
\ No newline at end of file

Copied: logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-mapfilter.xml (from r1391705, logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-config.xml)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-mapfilter.xml?p2=logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-mapfilter.xml&p1=logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-config.xml&r1=1391705&r2=1391925&rev=1391925&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-config.xml (original)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j2-mapfilter.xml Sat Sep 29 23:35:58 2012
@@ -16,21 +16,19 @@
  limitations under the License.
 
 -->
-<configuration name="ConfigTest" status="error" packages="org.apache.logging.log4j.test"
-    monitorInterval="5">
+<configuration name="ConfigTest" status="error" packages="org.apache.logging.log4j.test">
+  <MapFilter onMatch="ACCEPT" onMismatch="NEUTRAL" operator="or">
+    <KeyValuePair key="eventId" value="Login"/>
+    <KeyValuePair key="eventId" value="Logout"/>
+  </MapFilter>
   <appenders>
-    <Console name="STDOUT">
+    <List name="LIST">
       <PatternLayout pattern="%m%n"/>
-    </Console>
-    <List name="List">
     </List>
   </appenders>
   <loggers>
-    <logger name="org.apache.test" level="trace" additivity="false">
-      <appender-ref ref="List"/>
-    </logger>
     <root level="error">
-      <appender-ref ref="STDOUT"/>
+      <appender-ref ref="LIST"/>
     </root>
   </loggers>
 </configuration>
\ No newline at end of file

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1391925&r1=1391924&r2=1391925&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Sat Sep 29 23:35:58 2012
@@ -23,6 +23,10 @@
 
   <body>
     <release version="2.0-beta2" date="TBD" description="Bug fixes and enhancements">
+      <action issue="LOG4J2-92" dev="rgoers" type="fix">
+        Converted DynamicThresholdFilter to use KeyValuePair. Fixed bugs in the Map-based filters
+        to allow declaration of multiple values for a key to match the documentation.
+      </action>
       <action issue="LOG4J2-88" dev="rgoers" type="fix">
         Many logging methods in AbstractLogger were set to an incorrect logging level. catching was
         using the THROWING marker and was set to debug instead of error.

Modified: logging/log4j/log4j2/trunk/src/site/xdoc/manual/filters.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/xdoc/manual/filters.xml?rev=1391925&r1=1391924&r2=1391925&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/xdoc/manual/filters.xml (original)
+++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/filters.xml Sat Sep 29 23:35:58 2012
@@ -238,7 +238,9 @@
             <tr>
               <td>keyValuePair</td>
               <td>KeyValuePair[]</td>
-              <td>One or more KeyValuePair elements that define the key in the map and the value to match on.</td>
+              <td>One or more KeyValuePair elements that define the key in the map and the value to match on. If the
+              same key is specified more than once then the check for that key will automatically be an "or" since
+              a Map can only contain a single value.</td>
             </tr>
             <tr>
               <td>operator</td>
@@ -474,7 +476,9 @@
               <td>KeyValuePair[]</td>
               <td>One or more KeyValuePair elements that define the key in the map and the value to match on. "id",
                 "id.name", "type", and "message" should be used to match on the StructuredDataId, the name
-                portion of the StructuredDataId, the type, and the formatted message respectively.
+                portion of the StructuredDataId, the type, and the formatted message respectively. If the
+                same key is specified more than once then the check for that key will automatically be an "or" since
+                a Map can only contain a single value.
               </td>
             </tr>
             <tr>
@@ -537,7 +541,9 @@
             <tr>
               <td>keyValuePair</td>
               <td>KeyValuePair[]</td>
-              <td>One or more KeyValuePair elements that define the key in the map and the value to match on.</td>
+              <td>One or more KeyValuePair elements that define the key in the map and the value to match on. If the
+                same key is specified more than once then the check for that key will automatically be an "or" since
+                a Map can only contain a single value.</td>
             </tr>
             <tr>
               <td>operator</td>