View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.filter;
18  
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Objects;
24  
25  import org.apache.logging.log4j.Level;
26  import org.apache.logging.log4j.Marker;
27  import org.apache.logging.log4j.core.Filter;
28  import org.apache.logging.log4j.core.LogEvent;
29  import org.apache.logging.log4j.core.Logger;
30  import org.apache.logging.log4j.core.config.Node;
31  import org.apache.logging.log4j.core.config.plugins.Plugin;
32  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
33  import org.apache.logging.log4j.core.config.plugins.PluginElement;
34  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
35  import org.apache.logging.log4j.core.util.KeyValuePair;
36  import org.apache.logging.log4j.message.MapMessage;
37  import org.apache.logging.log4j.message.Message;
38  import org.apache.logging.log4j.util.ReadOnlyStringMap;
39  
40  /**
41   * A Filter that operates on a Map.
42   */
43  @Plugin(name = "MapFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
44  public class MapFilter extends AbstractFilter {
45  
46      private final Map<String, List<String>> map;
47  
48      private final boolean isAnd;
49  
50      protected MapFilter(final Map<String, List<String>> map, final boolean oper, final Result onMatch,
51                          final Result onMismatch) {
52          super(onMatch, onMismatch);
53          Objects.requireNonNull(map, "map cannot be null");
54          this.isAnd = oper;
55          this.map = map;
56      }
57  
58      @Override
59      public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
60                           final Throwable t) {
61          if (msg instanceof MapMessage) {
62              return filter(((MapMessage) msg).getData()) ? onMatch : onMismatch;
63          }
64          return Result.NEUTRAL;
65      }
66  
67      @Override
68      public Result filter(final LogEvent event) {
69          final Message msg = event.getMessage();
70          if (msg instanceof MapMessage) {
71              return filter(((MapMessage) msg).getData()) ? onMatch : onMismatch;
72          }
73          return Result.NEUTRAL;
74      }
75  
76      protected boolean filter(final Map<String, String> data) {
77          boolean match = false;
78          for (final Map.Entry<String, List<String>> entry : map.entrySet()) {
79              final String toMatch = data.get(entry.getKey());
80              match = toMatch != null && entry.getValue().contains(toMatch);
81              if ((!isAnd && match) || (isAnd && !match)) {
82                  break;
83              }
84          }
85          return match;
86      }
87  
88      protected boolean filter(final ReadOnlyStringMap data) {
89          boolean match = false;
90          for (final Map.Entry<String, List<String>> entry : map.entrySet()) {
91              final String toMatch = data.getValue(entry.getKey());
92              match = toMatch != null && entry.getValue().contains(toMatch);
93              if ((!isAnd && match) || (isAnd && !match)) {
94                  break;
95              }
96          }
97          return match;
98      }
99  
100     @Override
101     public String toString() {
102         final StringBuilder sb = new StringBuilder();
103         sb.append("isAnd=").append(isAnd);
104         if (map.size() > 0) {
105             sb.append(", {");
106             boolean first = true;
107             for (final Map.Entry<String, List<String>> entry : map.entrySet()) {
108                 if (!first) {
109                     sb.append(", ");
110                 }
111                 first = false;
112                 final List<String> list = entry.getValue();
113                 final String value = list.size() > 1 ? list.get(0) : list.toString();
114                 sb.append(entry.getKey()).append('=').append(value);
115             }
116             sb.append('}');
117         }
118         return sb.toString();
119     }
120 
121     protected boolean isAnd() {
122         return isAnd;
123     }
124 
125     protected Map<String, List<String>> getMap() {
126         return map;
127     }
128 
129     @PluginFactory
130     public static MapFilter createFilter(
131             @PluginElement("Pairs") final KeyValuePair[] pairs,
132             @PluginAttribute("operator") final String oper,
133             @PluginAttribute("onMatch") final Result match,
134             @PluginAttribute("onMismatch") final Result mismatch) {
135         if (pairs == null || pairs.length == 0) {
136             LOGGER.error("keys and values must be specified for the MapFilter");
137             return null;
138         }
139         final Map<String, List<String>> map = new HashMap<>();
140         for (final KeyValuePair pair : pairs) {
141             final String key = pair.getKey();
142             if (key == null) {
143                 LOGGER.error("A null key is not valid in MapFilter");
144                 continue;
145             }
146             final String value = pair.getValue();
147             if (value == null) {
148                 LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
149                 continue;
150             }
151             List<String> list = map.get(pair.getKey());
152             if (list != null) {
153                 list.add(value);
154             } else {
155                 list = new ArrayList<>();
156                 list.add(value);
157                 map.put(pair.getKey(), list);
158             }
159         }
160         if (map.isEmpty()) {
161             LOGGER.error("MapFilter is not configured with any valid key value pairs");
162             return null;
163         }
164         final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
165         return new MapFilter(map, isAnd, match, mismatch);
166     }
167 }