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 org.apache.logging.log4j.Level;
20  import org.apache.logging.log4j.ThreadContext;
21  import org.apache.logging.log4j.Marker;
22  import org.apache.logging.log4j.core.LogEvent;
23  import org.apache.logging.log4j.core.Logger;
24  import org.apache.logging.log4j.core.config.plugins.Plugin;
25  import org.apache.logging.log4j.core.config.plugins.PluginAttr;
26  import org.apache.logging.log4j.core.config.plugins.PluginElement;
27  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
28  import org.apache.logging.log4j.core.helpers.KeyValuePair;
29  import org.apache.logging.log4j.message.Message;
30  
31  import java.util.ArrayList;
32  import java.util.HashMap;
33  import java.util.Iterator;
34  import java.util.List;
35  import java.util.Locale;
36  import java.util.Map;
37  
38  /**
39   * Filter based on a value in the Thread Context Map (MDC).
40   */
41  @Plugin(name = "ThreadContextMapFilter", type = "Core", elementType = "filter", printObject = true)
42  public class ThreadContextMapFilter extends MapFilter {
43  
44      private final String key;
45      private final String value;
46  
47      private final boolean useMap;
48  
49      public ThreadContextMapFilter(Map<String, List<String>> pairs, boolean oper, Result onMatch, Result onMismatch) {
50          super(pairs, oper, onMatch, onMismatch);
51          if (pairs.size() == 1) {
52              Iterator<Map.Entry<String, List<String>>> iter = pairs.entrySet().iterator();
53              Map.Entry<String, List<String>> entry = iter.next();
54              if (entry.getValue().size() == 1) {
55                  this.key = entry.getKey();
56                  this.value = entry.getValue().get(0);
57                  this.useMap = false;
58              } else {
59                  this.key = null;
60                  this.value = null;
61                  this.useMap = true;
62              }
63          } else {
64              this.key = null;
65              this.value = null;
66              this.useMap = true;
67          }
68      }
69  
70      @Override
71      public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
72          return filter();
73      }
74  
75      @Override
76      public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
77          return filter();
78      }
79  
80      @Override
81      public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
82          return filter();
83      }
84  
85      private Result filter() {
86          boolean match = false;
87          if (useMap) {
88              for (Map.Entry<String, List<String>> entry : getMap().entrySet()) {
89                  String toMatch = ThreadContext.get(entry.getKey());
90                  if (toMatch != null) {
91                      match = entry.getValue().contains(toMatch);
92                  } else {
93                      match = false;
94                  }
95                  if ((!isAnd() && match) || (isAnd() && !match)) {
96                      break;
97                  }
98              }
99          } else {
100             match = key.equals(ThreadContext.get(key));
101         }
102         return match ? onMatch : onMismatch;
103     }
104 
105     @Override
106     public Result filter(LogEvent event) {
107         return super.filter(event.getContextMap()) ? onMatch : onMismatch;
108     }
109 
110     @PluginFactory
111     public static ThreadContextMapFilter createFilter(@PluginElement("pairs") KeyValuePair[] pairs,
112                                                       @PluginAttr("operator") String oper,
113                                                       @PluginAttr("onmatch") String match,
114                                                       @PluginAttr("onmismatch") String mismatch) {
115         if (pairs == null || pairs.length == 0) {
116             LOGGER.error("key and value pairs must be specified for the ThreadContextMapFilter");
117             return null;
118         }
119         Map<String, List<String>> map = new HashMap<String, List<String>>();
120         for (KeyValuePair pair : pairs) {
121             String key = pair.getKey();
122             if (key == null) {
123                 LOGGER.error("A null key is not valid in MapFilter");
124                 continue;
125             }
126             String value = pair.getValue();
127             if (value == null) {
128                 LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
129                 continue;
130             }
131             List<String> list = map.get(pair.getKey());
132             if (list != null) {
133                 list.add(value);
134             } else {
135                 list = new ArrayList<String>();
136                 list.add(value);
137                 map.put(pair.getKey(), list);
138             }
139         }
140         if (map.size() == 0) {
141             LOGGER.error("ThreadContextMapFilter is not configured with any valid key value pairs");
142             return null;
143         }
144         boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
145         Result onMatch = Result.toResult(match);
146         Result onMismatch = Result.toResult(mismatch);
147         return new ThreadContextMapFilter(map, isAnd, onMatch, onMismatch);
148     }
149 }