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.HashMap;
20 import java.util.Map;
21 import java.util.Objects;
22
23 import org.apache.logging.log4j.Level;
24 import org.apache.logging.log4j.Marker;
25 import org.apache.logging.log4j.ThreadContext;
26 import org.apache.logging.log4j.core.Filter;
27 import org.apache.logging.log4j.core.LogEvent;
28 import org.apache.logging.log4j.core.Logger;
29 import org.apache.logging.log4j.core.config.Node;
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.ContextDataInjector;
35 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
36 import org.apache.logging.log4j.core.util.KeyValuePair;
37 import org.apache.logging.log4j.message.Message;
38 import org.apache.logging.log4j.util.PerformanceSensitive;
39 import org.apache.logging.log4j.util.ReadOnlyStringMap;
40
41
42
43
44
45
46 @Plugin(name = "DynamicThresholdFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
47 @PerformanceSensitive("allocation")
48 public final class DynamicThresholdFilter extends AbstractFilter {
49
50
51
52
53
54
55
56
57
58
59 @PluginFactory
60 public static DynamicThresholdFilter createFilter(
61 @PluginAttribute("key") final String key,
62 @PluginElement("Pairs") final KeyValuePair[] pairs,
63 @PluginAttribute("defaultThreshold") final Level defaultThreshold,
64 @PluginAttribute("onMatch") final Result onMatch,
65 @PluginAttribute("onMismatch") final Result onMismatch) {
66 final Map<String, Level> map = new HashMap<>();
67 for (final KeyValuePair pair : pairs) {
68 map.put(pair.getKey(), Level.toLevel(pair.getValue()));
69 }
70 final Level level = defaultThreshold == null ? Level.ERROR : defaultThreshold;
71 return new DynamicThresholdFilter(key, map, level, onMatch, onMismatch);
72 }
73
74 private Level defaultThreshold = Level.ERROR;
75 private final String key;
76 private final ContextDataInjector injector = ContextDataInjectorFactory.createInjector();
77 private Map<String, Level> levelMap = new HashMap<>();
78
79 private DynamicThresholdFilter(final String key, final Map<String, Level> pairs, final Level defaultLevel,
80 final Result onMatch, final Result onMismatch) {
81 super(onMatch, onMismatch);
82 Objects.requireNonNull(key, "key cannot be null");
83 this.key = key;
84 this.levelMap = pairs;
85 this.defaultThreshold = defaultLevel;
86 }
87
88 @Override
89 public boolean equals(final Object obj) {
90 if (this == obj) {
91 return true;
92 }
93 if (!super.equalsImpl(obj)) {
94 return false;
95 }
96 if (getClass() != obj.getClass()) {
97 return false;
98 }
99 final DynamicThresholdFilter other = (DynamicThresholdFilter) obj;
100 if (defaultThreshold == null) {
101 if (other.defaultThreshold != null) {
102 return false;
103 }
104 } else if (!defaultThreshold.equals(other.defaultThreshold)) {
105 return false;
106 }
107 if (key == null) {
108 if (other.key != null) {
109 return false;
110 }
111 } else if (!key.equals(other.key)) {
112 return false;
113 }
114 if (levelMap == null) {
115 if (other.levelMap != null) {
116 return false;
117 }
118 } else if (!levelMap.equals(other.levelMap)) {
119 return false;
120 }
121 return true;
122 }
123
124 private Result filter(final Level level, final ReadOnlyStringMap contextMap) {
125 final String value = contextMap.getValue(key);
126 if (value != null) {
127 Level ctxLevel = levelMap.get(value);
128 if (ctxLevel == null) {
129 ctxLevel = defaultThreshold;
130 }
131 return level.isMoreSpecificThan(ctxLevel) ? onMatch : onMismatch;
132 }
133 return Result.NEUTRAL;
134
135 }
136
137 @Override
138 public Result filter(final LogEvent event) {
139 return filter(event.getLevel(), event.getContextData());
140 }
141
142 @Override
143 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
144 final Throwable t) {
145 return filter(level, currentContextData());
146 }
147
148 @Override
149 public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
150 final Throwable t) {
151 return filter(level, currentContextData());
152 }
153
154 @Override
155 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
156 final Object... params) {
157 return filter(level, currentContextData());
158 }
159
160 private ReadOnlyStringMap currentContextData() {
161 return injector.rawContextData();
162 }
163
164 @Override
165 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
166 final Object p0) {
167 return filter(level, currentContextData());
168 }
169
170 @Override
171 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
172 final Object p0, final Object p1) {
173 return filter(level, currentContextData());
174 }
175
176 @Override
177 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
178 final Object p0, final Object p1, final Object p2) {
179 return filter(level, currentContextData());
180 }
181
182 @Override
183 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
184 final Object p0, final Object p1, final Object p2, final Object p3) {
185 return filter(level, currentContextData());
186 }
187
188 @Override
189 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
190 final Object p0, final Object p1, final Object p2, final Object p3,
191 final Object p4) {
192 return filter(level, currentContextData());
193 }
194
195 @Override
196 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
197 final Object p0, final Object p1, final Object p2, final Object p3,
198 final Object p4, final Object p5) {
199 return filter(level, currentContextData());
200 }
201
202 @Override
203 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
204 final Object p0, final Object p1, final Object p2, final Object p3,
205 final Object p4, final Object p5, final Object p6) {
206 return filter(level, currentContextData());
207 }
208
209 @Override
210 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
211 final Object p0, final Object p1, final Object p2, final Object p3,
212 final Object p4, final Object p5, final Object p6,
213 final Object p7) {
214 return filter(level, currentContextData());
215 }
216
217 @Override
218 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
219 final Object p0, final Object p1, final Object p2, final Object p3,
220 final Object p4, final Object p5, final Object p6,
221 final Object p7, final Object p8) {
222 return filter(level, currentContextData());
223 }
224
225 @Override
226 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
227 final Object p0, final Object p1, final Object p2, final Object p3,
228 final Object p4, final Object p5, final Object p6,
229 final Object p7, final Object p8, final Object p9) {
230 return filter(level, currentContextData());
231 }
232
233 public String getKey() {
234 return this.key;
235 }
236
237 public Map<String, Level> getLevelMap() {
238 return levelMap;
239 }
240
241 @Override
242 public int hashCode() {
243 final int prime = 31;
244 int result = super.hashCodeImpl();
245 result = prime * result + ((defaultThreshold == null) ? 0 : defaultThreshold.hashCode());
246 result = prime * result + ((key == null) ? 0 : key.hashCode());
247 result = prime * result + ((levelMap == null) ? 0 : levelMap.hashCode());
248 return result;
249 }
250
251 @Override
252 public String toString() {
253 final StringBuilder sb = new StringBuilder();
254 sb.append("key=").append(key);
255 sb.append(", default=").append(defaultThreshold);
256 if (levelMap.size() > 0) {
257 sb.append('{');
258 boolean first = true;
259 for (final Map.Entry<String, Level> entry : levelMap.entrySet()) {
260 if (!first) {
261 sb.append(", ");
262 first = false;
263 }
264 sb.append(entry.getKey()).append('=').append(entry.getValue());
265 }
266 sb.append('}');
267 }
268 return sb.toString();
269 }
270 }