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.Iterator;
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.LogEvent;
29 import org.apache.logging.log4j.core.Logger;
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.PluginFactory;
33 import org.apache.logging.log4j.message.Message;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 @Plugin(name = "BurstFilter", category = "Core", elementType = "filter", printObject = true)
56 public final class BurstFilter extends AbstractFilter {
57
58 private static final long NANOS_IN_SECONDS = 1000000000;
59
60 private static final int DEFAULT_RATE = 10;
61
62 private static final int DEFAULT_RATE_MULTIPLE = 100;
63
64 private static final int HASH_SHIFT = 32;
65
66
67
68
69
70
71
72 private final Level level;
73
74 private final long burstInterval;
75
76 private final DelayQueue<LogDelay> history = new DelayQueue<LogDelay>();
77
78 private final Queue<LogDelay> available = new ConcurrentLinkedQueue<LogDelay>();
79
80 private BurstFilter(final Level level, final float rate, final long maxBurst, final Result onMatch,
81 final Result onMismatch) {
82 super(onMatch, onMismatch);
83 this.level = level;
84 this.burstInterval = (long) (NANOS_IN_SECONDS * (maxBurst / rate));
85 for (int i = 0; i < maxBurst; ++i) {
86 available.add(new LogDelay());
87 }
88 }
89
90 @Override
91 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
92 final Object... params) {
93 return filter(level);
94 }
95
96 @Override
97 public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
98 final Throwable t) {
99 return filter(level);
100 }
101
102 @Override
103 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
104 final Throwable t) {
105 return filter(level);
106 }
107
108 @Override
109 public Result filter(final LogEvent event) {
110 return filter(event.getLevel());
111 }
112
113
114
115
116
117
118
119
120 private Result filter(final Level level) {
121 if (this.level.isMoreSpecificThan(level)) {
122 LogDelay delay = history.poll();
123 while (delay != null) {
124 available.add(delay);
125 delay = history.poll();
126 }
127 delay = available.poll();
128 if (delay != null) {
129 delay.setDelay(burstInterval);
130 history.add(delay);
131 return onMatch;
132 }
133 return onMismatch;
134 }
135 return onMatch;
136
137 }
138
139
140
141
142
143 public int getAvailable() {
144 return available.size();
145 }
146
147
148
149
150 public void clear() {
151 final Iterator<LogDelay> iter = history.iterator();
152 while (iter.hasNext()) {
153 final LogDelay delay = iter.next();
154 history.remove(delay);
155 available.add(delay);
156 }
157 }
158
159 @Override
160 public String toString() {
161 return "level=" + level.toString() + ", interval=" + burstInterval + ", max=" + history.size();
162 }
163
164
165
166
167 private class LogDelay implements Delayed {
168
169 private long expireTime;
170
171 public LogDelay() {
172 }
173
174 public void setDelay(final long delay) {
175 this.expireTime = delay + System.nanoTime();
176 }
177
178 @Override
179 public long getDelay(final TimeUnit timeUnit) {
180 return timeUnit.convert(expireTime - System.nanoTime(), TimeUnit.NANOSECONDS);
181 }
182
183 @Override
184 public int compareTo(final Delayed delayed) {
185 if (this.expireTime < ((LogDelay) delayed).expireTime) {
186 return -1;
187 } else if (this.expireTime > ((LogDelay) delayed).expireTime) {
188 return 1;
189 }
190 return 0;
191 }
192
193 @Override
194 public boolean equals(final Object o) {
195 if (this == o) {
196 return true;
197 }
198 if (o == null || getClass() != o.getClass()) {
199 return false;
200 }
201
202 final LogDelay logDelay = (LogDelay) o;
203
204 if (expireTime != logDelay.expireTime) {
205 return false;
206 }
207
208 return true;
209 }
210
211 @Override
212 public int hashCode() {
213 return (int) (expireTime ^ (expireTime >>> HASH_SHIFT));
214 }
215 }
216
217
218
219
220
221
222
223
224
225
226 @PluginFactory
227 public static BurstFilter createFilter(
228 @PluginAttribute("level") final Level level,
229 @PluginAttribute("rate") final Float rate,
230 @PluginAttribute("maxBurst") final Long maxBurst,
231 @PluginAttribute("onMatch") final Result match,
232 @PluginAttribute("onMismatch") final Result mismatch) {
233 final Result onMatch = match == null ? Result.NEUTRAL : match;
234 final Result onMismatch = mismatch == null ? Result.DENY : mismatch;
235 final Level actualLevel = level == null ? Level.WARN : level;
236 float eventRate = rate == null ? DEFAULT_RATE : rate;
237 if (eventRate <= 0) {
238 eventRate = DEFAULT_RATE;
239 }
240 final long max = maxBurst == null ? (long) (eventRate * DEFAULT_RATE_MULTIPLE) : maxBurst;
241 return new BurstFilter(actualLevel, eventRate, max, onMatch, onMismatch);
242 }
243 }