1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.core.filter;
19
20 import java.util.Queue;
21 import java.util.concurrent.ConcurrentLinkedQueue;
22 import java.util.concurrent.DelayQueue;
23 import java.util.concurrent.Delayed;
24 import java.util.concurrent.TimeUnit;
25
26 import org.apache.logging.log4j.Level;
27 import org.apache.logging.log4j.Marker;
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.PluginBuilderAttribute;
34 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
35 import org.apache.logging.log4j.message.Message;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 @Plugin(name = "BurstFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
57 public final class BurstFilter extends AbstractFilter {
58
59 private static final long NANOS_IN_SECONDS = 1000000000;
60
61 private static final int DEFAULT_RATE = 10;
62
63 private static final int DEFAULT_RATE_MULTIPLE = 100;
64
65 private static final int HASH_SHIFT = 32;
66
67
68
69
70
71
72
73 private final Level level;
74
75 private final long burstInterval;
76
77 private final DelayQueue<LogDelay> history = new DelayQueue<>();
78
79 private final Queue<LogDelay> available = new ConcurrentLinkedQueue<>();
80
81 static LogDelay createLogDelay(final long expireTime) {
82 return new LogDelay(expireTime);
83 }
84
85 private BurstFilter(final Level level, final float rate, final long maxBurst, final Result onMatch,
86 final Result onMismatch) {
87 super(onMatch, onMismatch);
88 this.level = level;
89 this.burstInterval = (long) (NANOS_IN_SECONDS * (maxBurst / rate));
90 for (int i = 0; i < maxBurst; ++i) {
91 available.add(createLogDelay(0));
92 }
93 }
94
95 @Override
96 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
97 final Object... params) {
98 return filter(level);
99 }
100
101 @Override
102 public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
103 final Throwable t) {
104 return filter(level);
105 }
106
107 @Override
108 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
109 final Throwable t) {
110 return filter(level);
111 }
112
113 @Override
114 public Result filter(final LogEvent event) {
115 return filter(event.getLevel());
116 }
117
118 @Override
119 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
120 final Object p0) {
121 return filter(level);
122 }
123
124 @Override
125 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
126 final Object p0, final Object p1) {
127 return filter(level);
128 }
129
130 @Override
131 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
132 final Object p0, final Object p1, final Object p2) {
133 return filter(level);
134 }
135
136 @Override
137 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
138 final Object p0, final Object p1, final Object p2, final Object p3) {
139 return filter(level);
140 }
141
142 @Override
143 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
144 final Object p0, final Object p1, final Object p2, final Object p3,
145 final Object p4) {
146 return filter(level);
147 }
148
149 @Override
150 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
151 final Object p0, final Object p1, final Object p2, final Object p3,
152 final Object p4, final Object p5) {
153 return filter(level);
154 }
155
156 @Override
157 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
158 final Object p0, final Object p1, final Object p2, final Object p3,
159 final Object p4, final Object p5, final Object p6) {
160 return filter(level);
161 }
162
163 @Override
164 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
165 final Object p0, final Object p1, final Object p2, final Object p3,
166 final Object p4, final Object p5, final Object p6,
167 final Object p7) {
168 return filter(level);
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, final Object p2, final Object p3,
174 final Object p4, final Object p5, final Object p6,
175 final Object p7, final Object p8) {
176 return filter(level);
177 }
178
179 @Override
180 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
181 final Object p0, final Object p1, final Object p2, final Object p3,
182 final Object p4, final Object p5, final Object p6,
183 final Object p7, final Object p8, final Object p9) {
184 return filter(level);
185 }
186
187
188
189
190
191
192
193
194 private Result filter(final Level level) {
195 if (this.level.isMoreSpecificThan(level)) {
196 LogDelay delay = history.poll();
197 while (delay != null) {
198 available.add(delay);
199 delay = history.poll();
200 }
201 delay = available.poll();
202 if (delay != null) {
203 delay.setDelay(burstInterval);
204 history.add(delay);
205 return onMatch;
206 }
207 return onMismatch;
208 }
209 return onMatch;
210
211 }
212
213
214
215
216
217 public int getAvailable() {
218 return available.size();
219 }
220
221
222
223
224 public void clear() {
225 for (final LogDelay delay : history) {
226 history.remove(delay);
227 available.add(delay);
228 }
229 }
230
231 @Override
232 public String toString() {
233 return "level=" + level.toString() + ", interval=" + burstInterval + ", max=" + history.size();
234 }
235
236
237
238
239
240
241 private static class LogDelay implements Delayed {
242
243 LogDelay(final long expireTime) {
244 this.expireTime = expireTime;
245 }
246
247 private long expireTime;
248
249 public void setDelay(final long delay) {
250 this.expireTime = delay + System.nanoTime();
251 }
252
253 @Override
254 public long getDelay(final TimeUnit timeUnit) {
255 return timeUnit.convert(expireTime - System.nanoTime(), TimeUnit.NANOSECONDS);
256 }
257
258 @Override
259 public int compareTo(final Delayed delayed) {
260 final long diff = this.expireTime - ((LogDelay) delayed).expireTime;
261 return Long.signum(diff);
262 }
263
264 @Override
265 public boolean equals(final Object o) {
266 if (this == o) {
267 return true;
268 }
269 if (o == null || getClass() != o.getClass()) {
270 return false;
271 }
272
273 final LogDelay logDelay = (LogDelay) o;
274
275 if (expireTime != logDelay.expireTime) {
276 return false;
277 }
278
279 return true;
280 }
281
282 @Override
283 public int hashCode() {
284 return (int) (expireTime ^ (expireTime >>> HASH_SHIFT));
285 }
286 }
287
288 @PluginBuilderFactory
289 public static Builder newBuilder() {
290 return new Builder();
291 }
292
293 public static class Builder extends AbstractFilterBuilder<Builder> implements org.apache.logging.log4j.core.util.Builder<BurstFilter> {
294
295 @PluginBuilderAttribute
296 private Level level = Level.WARN;
297
298 @PluginBuilderAttribute
299 private float rate = DEFAULT_RATE;
300
301 @PluginBuilderAttribute
302 private long maxBurst;
303
304
305
306
307
308
309 public Builder setLevel(final Level level) {
310 this.level = level;
311 return this;
312 }
313
314
315
316
317
318
319 public Builder setRate(final float rate) {
320 this.rate = rate;
321 return this;
322 }
323
324
325
326
327
328
329
330 public Builder setMaxBurst(final long maxBurst) {
331 this.maxBurst = maxBurst;
332 return this;
333 }
334
335 @Override
336 public BurstFilter build() {
337 if (this.rate <= 0) {
338 this.rate = DEFAULT_RATE;
339 }
340 if (this.maxBurst <= 0) {
341 this.maxBurst = (long) (this.rate * DEFAULT_RATE_MULTIPLE);
342 }
343 return new BurstFilter(this.level, this.rate, this.maxBurst, this.getOnMatch(), this.getOnMismatch());
344 }
345 }
346 }