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