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 @PluginFactory
198 public static ThreadContextMapFilter createFilter(
199 @PluginElement("Pairs") final KeyValuePair[] pairs,
200 @PluginAttribute("operator") final String oper,
201 @PluginAttribute("onMatch") final Result match,
202 @PluginAttribute("onMismatch") final Result mismatch) {
203 if (pairs == null || pairs.length == 0) {
204 LOGGER.error("key and value pairs must be specified for the ThreadContextMapFilter");
205 return null;
206 }
207 final Map<String, List<String>> map = new HashMap<>();
208 for (final KeyValuePair pair : pairs) {
209 final String key = pair.getKey();
210 if (key == null) {
211 LOGGER.error("A null key is not valid in MapFilter");
212 continue;
213 }
214 final String value = pair.getValue();
215 if (value == null) {
216 LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
217 continue;
218 }
219 List<String> list = map.get(pair.getKey());
220 if (list != null) {
221 list.add(value);
222 } else {
223 list = new ArrayList<>();
224 list.add(value);
225 map.put(pair.getKey(), list);
226 }
227 }
228 if (map.isEmpty()) {
229 LOGGER.error("ThreadContextMapFilter is not configured with any valid key value pairs");
230 return null;
231 }
232 final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
233 return new ThreadContextMapFilter(map, isAnd, match, mismatch);
234 }
235 }