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