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