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