1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.core.ContextDataInjector;
28 import org.apache.logging.log4j.core.Filter;
29 import org.apache.logging.log4j.core.LogEvent;
30 import org.apache.logging.log4j.core.Logger;
31 import org.apache.logging.log4j.core.config.Node;
32 import org.apache.logging.log4j.core.config.plugins.Plugin;
33 import org.apache.logging.log4j.core.config.plugins.PluginAliases;
34 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
35 import org.apache.logging.log4j.core.config.plugins.PluginElement;
36 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
37 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
38 import org.apache.logging.log4j.core.util.KeyValuePair;
39 import org.apache.logging.log4j.message.Message;
40 import org.apache.logging.log4j.util.IndexedReadOnlyStringMap;
41 import org.apache.logging.log4j.util.PerformanceSensitive;
42 import org.apache.logging.log4j.util.ReadOnlyStringMap;
43
44
45
46
47 @Plugin(name = "ThreadContextMapFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
48 @PluginAliases("ContextMapFilter")
49 @PerformanceSensitive("allocation")
50 public class ThreadContextMapFilter extends MapFilter {
51
52 private final ContextDataInjector injector = ContextDataInjectorFactory.createInjector();
53 private final String key;
54 private final String value;
55
56 private final boolean useMap;
57
58 public ThreadContextMapFilter(final Map<String, List<String>> pairs, final boolean oper, final Result onMatch,
59 final Result onMismatch) {
60 super(pairs, oper, onMatch, onMismatch);
61 if (pairs.size() == 1) {
62 final Iterator<Map.Entry<String, List<String>>> iter = pairs.entrySet().iterator();
63 final Map.Entry<String, List<String>> entry = iter.next();
64 if (entry.getValue().size() == 1) {
65 this.key = entry.getKey();
66 this.value = entry.getValue().get(0);
67 this.useMap = false;
68 } else {
69 this.key = null;
70 this.value = null;
71 this.useMap = true;
72 }
73 } else {
74 this.key = null;
75 this.value = null;
76 this.useMap = true;
77 }
78 }
79
80 @Override
81 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
82 final Object... params) {
83 return filter();
84 }
85
86 @Override
87 public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
88 final Throwable t) {
89 return filter();
90 }
91
92 @Override
93 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
94 final Throwable t) {
95 return filter();
96 }
97
98 private Result filter() {
99 boolean match = false;
100 if (useMap) {
101 ReadOnlyStringMap currentContextData = null;
102 final IndexedReadOnlyStringMap map = getStringMap();
103 for (int i = 0; i < map.size(); i++) {
104 if (currentContextData == null) {
105 currentContextData = currentContextData();
106 }
107 final String toMatch = currentContextData.getValue(map.getKeyAt(i));
108 match = toMatch != null && ((List<String>) map.getValueAt(i)).contains(toMatch);
109 if ((!isAnd() && match) || (isAnd() && !match)) {
110 break;
111 }
112 }
113 } else {
114 match = value.equals(currentContextData().getValue(key));
115 }
116 return match ? onMatch : onMismatch;
117 }
118
119 private ReadOnlyStringMap currentContextData() {
120 return injector.rawContextData();
121 }
122
123 @Override
124 public Result filter(final LogEvent event) {
125 return super.filter(event.getContextData()) ? onMatch : onMismatch;
126 }
127
128 @Override
129 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
130 final Object p0) {
131 return filter();
132 }
133
134 @Override
135 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
136 final Object p0, final Object p1) {
137 return filter();
138 }
139
140 @Override
141 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
142 final Object p0, final Object p1, final Object p2) {
143 return filter();
144 }
145
146 @Override
147 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
148 final Object p0, final Object p1, final Object p2, final Object p3) {
149 return filter();
150 }
151
152 @Override
153 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
154 final Object p0, final Object p1, final Object p2, final Object p3,
155 final Object p4) {
156 return filter();
157 }
158
159 @Override
160 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
161 final Object p0, final Object p1, final Object p2, final Object p3,
162 final Object p4, final Object p5) {
163 return filter();
164 }
165
166 @Override
167 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
168 final Object p0, final Object p1, final Object p2, final Object p3,
169 final Object p4, final Object p5, final Object p6) {
170 return filter();
171 }
172
173 @Override
174 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
175 final Object p0, final Object p1, final Object p2, final Object p3,
176 final Object p4, final Object p5, final Object p6,
177 final Object p7) {
178 return filter();
179 }
180
181 @Override
182 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
183 final Object p0, final Object p1, final Object p2, final Object p3,
184 final Object p4, final Object p5, final Object p6,
185 final Object p7, final Object p8) {
186 return filter();
187 }
188
189 @Override
190 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
191 final Object p0, final Object p1, final Object p2, final Object p3,
192 final Object p4, final Object p5, final Object p6,
193 final Object p7, final Object p8, final Object p9) {
194 return filter();
195 }
196
197
198 @PluginFactory
199 public static ThreadContextMapFilter createFilter(
200 @PluginElement("Pairs") final KeyValuePair[] pairs,
201 @PluginAttribute("operator") final String oper,
202 @PluginAttribute("onMatch") final Result match,
203 @PluginAttribute("onMismatch") final Result mismatch) {
204 if (pairs == null || pairs.length == 0) {
205 LOGGER.error("key and value pairs must be specified for the ThreadContextMapFilter");
206 return null;
207 }
208 final Map<String, List<String>> map = new HashMap<>();
209 for (final KeyValuePair pair : pairs) {
210 final String key = pair.getKey();
211 if (key == null) {
212 LOGGER.error("A null key is not valid in MapFilter");
213 continue;
214 }
215 final String value = pair.getValue();
216 if (value == null) {
217 LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
218 continue;
219 }
220 List<String> list = map.get(pair.getKey());
221 if (list != null) {
222 list.add(value);
223 } else {
224 list = new ArrayList<>();
225 list.add(value);
226 map.put(pair.getKey(), list);
227 }
228 }
229 if (map.isEmpty()) {
230 LOGGER.error("ThreadContextMapFilter is not configured with any valid key value pairs");
231 return null;
232 }
233 final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
234 return new ThreadContextMapFilter(map, isAnd, match, mismatch);
235 }
236 }