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.Iterator;
21 import java.util.Queue;
22 import java.util.concurrent.ConcurrentLinkedQueue;
23 import java.util.concurrent.DelayQueue;
24 import java.util.concurrent.Delayed;
25 import java.util.concurrent.TimeUnit;
26
27 import org.apache.logging.log4j.Level;
28 import org.apache.logging.log4j.Marker;
29 import org.apache.logging.log4j.core.Filter;
30 import org.apache.logging.log4j.core.LogEvent;
31 import org.apache.logging.log4j.core.Logger;
32 import org.apache.logging.log4j.core.config.Node;
33 import org.apache.logging.log4j.core.config.plugins.Plugin;
34 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
35 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
36 import org.apache.logging.log4j.message.Message;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 @Plugin(name = "BurstFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
58 public final class BurstFilter extends AbstractFilter {
59
60 private static final long serialVersionUID = 1L;
61
62 private static final long NANOS_IN_SECONDS = 1000000000;
63
64 private static final int DEFAULT_RATE = 10;
65
66 private static final int DEFAULT_RATE_MULTIPLE = 100;
67
68 private static final int HASH_SHIFT = 32;
69
70
71
72
73
74
75
76 private final Level level;
77
78 private final long burstInterval;
79
80 private final DelayQueue<LogDelay> history = new DelayQueue<LogDelay>();
81
82 private final Queue<LogDelay> available = new ConcurrentLinkedQueue<LogDelay>();
83
84 private BurstFilter(final Level level, final float rate, final long maxBurst, final Result onMatch,
85 final Result onMismatch) {
86 super(onMatch, onMismatch);
87 this.level = level;
88 this.burstInterval = (long) (NANOS_IN_SECONDS * (maxBurst / rate));
89 for (int i = 0; i < maxBurst; ++i) {
90 available.add(new LogDelay());
91 }
92 }
93
94 @Override
95 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
96 final Object... params) {
97 return filter(level);
98 }
99
100 @Override
101 public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
102 final Throwable t) {
103 return filter(level);
104 }
105
106 @Override
107 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
108 final Throwable t) {
109 return filter(level);
110 }
111
112 @Override
113 public Result filter(final LogEvent event) {
114 return filter(event.getLevel());
115 }
116
117
118
119
120
121
122
123
124 private Result filter(final Level level) {
125 if (this.level.isMoreSpecificThan(level)) {
126 LogDelay delay = history.poll();
127 while (delay != null) {
128 available.add(delay);
129 delay = history.poll();
130 }
131 delay = available.poll();
132 if (delay != null) {
133 delay.setDelay(burstInterval);
134 history.add(delay);
135 return onMatch;
136 }
137 return onMismatch;
138 }
139 return onMatch;
140
141 }
142
143
144
145
146
147 public int getAvailable() {
148 return available.size();
149 }
150
151
152
153
154 public void clear() {
155 final Iterator<LogDelay> iter = history.iterator();
156 while (iter.hasNext()) {
157 final LogDelay delay = iter.next();
158 history.remove(delay);
159 available.add(delay);
160 }
161 }
162
163 @Override
164 public String toString() {
165 return "level=" + level.toString() + ", interval=" + burstInterval + ", max=" + history.size();
166 }
167
168
169
170
171 private class LogDelay implements Delayed {
172
173 private long expireTime;
174
175 public LogDelay() {
176 }
177
178 public void setDelay(final long delay) {
179 this.expireTime = delay + System.nanoTime();
180 }
181
182 @Override
183 public long getDelay(final TimeUnit timeUnit) {
184 return timeUnit.convert(expireTime - System.nanoTime(), TimeUnit.NANOSECONDS);
185 }
186
187 @Override
188 public int compareTo(final Delayed delayed) {
189 if (this.expireTime < ((LogDelay) delayed).expireTime) {
190 return -1;
191 } else if (this.expireTime > ((LogDelay) delayed).expireTime) {
192 return 1;
193 }
194 return 0;
195 }
196
197 @Override
198 public boolean equals(final Object o) {
199 if (this == o) {
200 return true;
201 }
202 if (o == null || getClass() != o.getClass()) {
203 return false;
204 }
205
206 final LogDelay logDelay = (LogDelay) o;
207
208 if (expireTime != logDelay.expireTime) {
209 return false;
210 }
211
212 return true;
213 }
214
215 @Override
216 public int hashCode() {
217 return (int) (expireTime ^ (expireTime >>> HASH_SHIFT));
218 }
219 }
220
221 @PluginBuilderFactory
222 public static Builder newBuilder() {
223 return new Builder();
224 }
225
226 public static class Builder implements org.apache.logging.log4j.core.util.Builder<BurstFilter> {
227
228 @PluginBuilderAttribute
229 private Level level = Level.WARN;
230
231 @PluginBuilderAttribute
232 private float rate = DEFAULT_RATE;
233
234 @PluginBuilderAttribute
235 private long maxBurst;
236
237 @PluginBuilderAttribute
238 private Result onMatch = Result.NEUTRAL;
239
240 @PluginBuilderAttribute
241 private Result onMismatch = Result.DENY;
242
243
244
245
246 public Builder setLevel(final Level level) {
247 this.level = level;
248 return this;
249 }
250
251
252
253
254 public Builder setRate(final float rate) {
255 this.rate = rate;
256 return this;
257 }
258
259
260
261
262
263 public Builder setMaxBurst(final long maxBurst) {
264 this.maxBurst = maxBurst;
265 return this;
266 }
267
268
269
270
271 public Builder setOnMatch(final Result onMatch) {
272 this.onMatch = onMatch;
273 return this;
274 }
275
276
277
278
279 public Builder setOnMismatch(final Result onMismatch) {
280 this.onMismatch = onMismatch;
281 return this;
282 }
283
284 @Override
285 public BurstFilter build() {
286 if (this.rate <= 0) {
287 this.rate = DEFAULT_RATE;
288 }
289 if (this.maxBurst <= 0) {
290 this.maxBurst = (long) (this.rate * DEFAULT_RATE_MULTIPLE);
291 }
292 return new BurstFilter(this.level, this.rate, this.maxBurst, this.onMatch, this.onMismatch);
293 }
294 }
295 }