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.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.apache.logging.log4j.Level;
26  import org.apache.logging.log4j.Marker;
27  import org.apache.logging.log4j.ThreadContext;
28  import org.apache.logging.log4j.core.LogEvent;
29  import org.apache.logging.log4j.core.Logger;
30  import org.apache.logging.log4j.core.config.plugins.Plugin;
31  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
32  import org.apache.logging.log4j.core.config.plugins.PluginElement;
33  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
34  import org.apache.logging.log4j.core.helpers.KeyValuePair;
35  import org.apache.logging.log4j.message.Message;
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(
115             @PluginElement("Pairs") final KeyValuePair[] pairs,
116             @PluginAttribute("operator") final String oper,
117             @PluginAttribute("onMatch") final String match,
118             @PluginAttribute("onMismatch") final String mismatch) {
119         if (pairs == null || pairs.length == 0) {
120             LOGGER.error("key and value pairs must be specified for the ThreadContextMapFilter");
121             return null;
122         }
123         final Map<String, List<String>> map = new HashMap<String, List<String>>();
124         for (final KeyValuePair pair : pairs) {
125             final String key = pair.getKey();
126             if (key == null) {
127                 LOGGER.error("A null key is not valid in MapFilter");
128                 continue;
129             }
130             final String value = pair.getValue();
131             if (value == null) {
132                 LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
133                 continue;
134             }
135             List<String> list = map.get(pair.getKey());
136             if (list != null) {
137                 list.add(value);
138             } else {
139                 list = new ArrayList<String>();
140                 list.add(value);
141                 map.put(pair.getKey(), list);
142             }
143         }
144         if (map.size() == 0) {
145             LOGGER.error("ThreadContextMapFilter is not configured with any valid key value pairs");
146             return null;
147         }
148         final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
149         final Result onMatch = Result.toResult(match);
150         final Result onMismatch = Result.toResult(mismatch);
151         return new ThreadContextMapFilter(map, isAnd, onMatch, onMismatch);
152     }
153 }