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 org.apache.logging.log4j.Level;
20 import org.apache.logging.log4j.Marker;
21 import org.apache.logging.log4j.core.LogEvent;
22 import org.apache.logging.log4j.core.Logger;
23 import org.apache.logging.log4j.core.config.plugins.Plugin;
24 import org.apache.logging.log4j.core.config.plugins.PluginAttr;
25 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
26 import org.apache.logging.log4j.message.Message;
27
28 import java.util.Iterator;
29 import java.util.Queue;
30 import java.util.concurrent.ConcurrentLinkedQueue;
31 import java.util.concurrent.DelayQueue;
32 import java.util.concurrent.Delayed;
33 import java.util.concurrent.TimeUnit;
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", type = "Core", elementType = "filter", printObject = true)
56 public final class BurstFilter extends FilterBase {
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(Level level, float rate, long maxBurst, Result onMatch, Result onMismatch) {
81 super(onMatch, onMismatch);
82 this.level = level;
83 this.burstInterval = (long) (NANOS_IN_SECONDS * (maxBurst / rate));
84 for (int i = 0; i < maxBurst; ++i) {
85 available.add(new LogDelay());
86 }
87 }
88
89 public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
90 return filter(level);
91 }
92
93 public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
94 return filter(level);
95 }
96
97 public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
98 return filter(level);
99 }
100
101 @Override
102 public Result filter(LogEvent event) {
103 return filter(event.getLevel());
104 }
105
106
107
108
109
110
111
112
113 private Result filter(Level level) {
114 if (this.level.isAtLeastAsSpecificAs(level)) {
115 LogDelay delay = history.poll();
116 while (delay != null) {
117 available.add(delay);
118 delay = history.poll();
119 }
120 delay = available.poll();
121 if (delay != null) {
122 delay.setDelay(burstInterval);
123 history.add(delay);
124 return onMatch;
125 }
126 return onMismatch;
127 }
128 return onMatch;
129
130 }
131
132
133
134
135
136 public int getAvailable() {
137 return available.size();
138 }
139
140
141
142
143 public void clear() {
144 Iterator<LogDelay> iter = history.iterator();
145 while (iter.hasNext()) {
146 LogDelay delay = iter.next();
147 history.remove(delay);
148 available.add(delay);
149 }
150 }
151
152 public String toString() {
153 return "level=" + level.toString() + ", interval=" + burstInterval + ", max=" + history.size();
154 }
155
156
157
158
159 private class LogDelay implements Delayed {
160
161 private long expireTime;
162
163 public LogDelay() {
164 }
165
166 public void setDelay(long delay) {
167 this.expireTime = delay + System.nanoTime();
168 }
169
170 public long getDelay(TimeUnit timeUnit) {
171 return timeUnit.convert(expireTime - System.nanoTime(), TimeUnit.NANOSECONDS);
172 }
173
174 public int compareTo(Delayed delayed) {
175 if (this.expireTime < ((LogDelay) delayed).expireTime) {
176 return -1;
177 } else if (this.expireTime > ((LogDelay) delayed).expireTime) {
178 return 1;
179 }
180 return 0;
181 }
182
183 @Override
184 public boolean equals(Object o) {
185 if (this == o) {
186 return true;
187 }
188 if (o == null || getClass() != o.getClass()) {
189 return false;
190 }
191
192 LogDelay logDelay = (LogDelay) o;
193
194 if (expireTime != logDelay.expireTime) {
195 return false;
196 }
197
198 return true;
199 }
200
201 @Override
202 public int hashCode() {
203 return (int) (expireTime ^ (expireTime >>> HASH_SHIFT));
204 }
205 }
206
207
208
209
210
211
212
213
214
215
216 @PluginFactory
217 public static BurstFilter createFilter(@PluginAttr("level") String level,
218 @PluginAttr("rate") String rate,
219 @PluginAttr("maxBurst") String maxBurst,
220 @PluginAttr("onmatch") String match,
221 @PluginAttr("onmismatch") String mismatch) {
222 Result onMatch = match == null ? null : Result.valueOf(match.toUpperCase());
223 Result onMismatch = mismatch == null ? null : Result.valueOf(mismatch.toUpperCase());
224 Level lvl = Level.toLevel(level, Level.WARN);
225 float eventRate = rate == null ? DEFAULT_RATE : Float.parseFloat(rate);
226 if (eventRate <= 0) {
227 eventRate = DEFAULT_RATE;
228 }
229 long max = maxBurst == null ? (long) (eventRate * DEFAULT_RATE_MULTIPLE) : Long.parseLong(maxBurst);
230 if (onMatch == null) {
231 onMatch = Result.NEUTRAL;
232 }
233 if (onMismatch == null) {
234 onMismatch = Result.DENY;
235 }
236 return new BurstFilter(lvl, eventRate, max, onMatch, onMismatch);
237 }
238 }