1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.log4j;
21
22 import java.text.MessageFormat;
23 import java.util.ArrayList;
24 import java.util.Enumeration;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29
30 import org.apache.log4j.helpers.AppenderAttachableImpl;
31 import org.apache.log4j.spi.AppenderAttachable;
32 import org.apache.log4j.spi.LoggingEvent;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public class AsyncAppender extends AppenderSkeleton
57 implements AppenderAttachable {
58
59
60
61 public static final int DEFAULT_BUFFER_SIZE = 128;
62
63
64
65
66
67 private final List buffer = new ArrayList();
68
69
70
71
72 private final Map discardMap = new HashMap();
73
74
75
76
77 private int bufferSize = DEFAULT_BUFFER_SIZE;
78
79
80 AppenderAttachableImpl aai;
81
82
83
84
85 private final AppenderAttachableImpl appenders;
86
87
88
89
90 private final Thread dispatcher;
91
92
93
94
95 private boolean locationInfo = false;
96
97
98
99
100 private boolean blocking = true;
101
102
103
104
105 public AsyncAppender() {
106 appenders = new AppenderAttachableImpl();
107
108
109
110 aai = appenders;
111
112 dispatcher =
113 new Thread(new Dispatcher(this, buffer, discardMap, appenders));
114
115
116
117 dispatcher.setDaemon(true);
118
119
120
121 dispatcher.setName("AsyncAppender-Dispatcher-" + dispatcher.getName());
122 dispatcher.start();
123 }
124
125
126
127
128
129
130 public void addAppender(final Appender newAppender) {
131 synchronized (appenders) {
132 appenders.addAppender(newAppender);
133 }
134 }
135
136
137
138
139 public void append(final LoggingEvent event) {
140
141
142
143
144 if ((dispatcher == null) || !dispatcher.isAlive() || (bufferSize <= 0)) {
145 synchronized (appenders) {
146 appenders.appendLoopOnAppenders(event);
147 }
148
149 return;
150 }
151
152
153
154 event.getNDC();
155 event.getThreadName();
156
157 event.getMDCCopy();
158 if (locationInfo) {
159 event.getLocationInformation();
160 }
161 event.getRenderedMessage();
162 event.getThrowableStrRep();
163
164 synchronized (buffer) {
165 while (true) {
166 int previousSize = buffer.size();
167
168 if (previousSize < bufferSize) {
169 buffer.add(event);
170
171
172
173
174
175
176 if (previousSize == 0) {
177 buffer.notifyAll();
178 }
179
180 break;
181 }
182
183
184
185
186
187
188
189
190 boolean discard = true;
191 if (blocking
192 && !Thread.interrupted()
193 && Thread.currentThread() != dispatcher) {
194 try {
195 buffer.wait();
196 discard = false;
197 } catch (InterruptedException e) {
198
199
200
201
202 Thread.currentThread().interrupt();
203 }
204 }
205
206
207
208
209
210 if (discard) {
211 String loggerName = event.getLoggerName();
212 DiscardSummary summary = (DiscardSummary) discardMap.get(loggerName);
213
214 if (summary == null) {
215 summary = new DiscardSummary(event);
216 discardMap.put(loggerName, summary);
217 } else {
218 summary.add(event);
219 }
220
221 break;
222 }
223 }
224 }
225 }
226
227
228
229
230
231 public void close() {
232
233
234
235
236 synchronized (buffer) {
237 closed = true;
238 buffer.notifyAll();
239 }
240
241 try {
242 dispatcher.join();
243 } catch (InterruptedException e) {
244 Thread.currentThread().interrupt();
245 org.apache.log4j.helpers.LogLog.error(
246 "Got an InterruptedException while waiting for the "
247 + "dispatcher to finish.", e);
248 }
249
250
251
252
253 synchronized (appenders) {
254 Enumeration iter = appenders.getAllAppenders();
255
256 if (iter != null) {
257 while (iter.hasMoreElements()) {
258 Object next = iter.nextElement();
259
260 if (next instanceof Appender) {
261 ((Appender) next).close();
262 }
263 }
264 }
265 }
266 }
267
268
269
270
271
272 public Enumeration getAllAppenders() {
273 synchronized (appenders) {
274 return appenders.getAllAppenders();
275 }
276 }
277
278
279
280
281
282
283
284 public Appender getAppender(final String name) {
285 synchronized (appenders) {
286 return appenders.getAppender(name);
287 }
288 }
289
290
291
292
293
294
295
296 public boolean getLocationInfo() {
297 return locationInfo;
298 }
299
300
301
302
303
304
305 public boolean isAttached(final Appender appender) {
306 synchronized (appenders) {
307 return appenders.isAttached(appender);
308 }
309 }
310
311
312
313
314 public boolean requiresLayout() {
315 return false;
316 }
317
318
319
320
321 public void removeAllAppenders() {
322 synchronized (appenders) {
323 appenders.removeAllAppenders();
324 }
325 }
326
327
328
329
330
331 public void removeAppender(final Appender appender) {
332 synchronized (appenders) {
333 appenders.removeAppender(appender);
334 }
335 }
336
337
338
339
340
341 public void removeAppender(final String name) {
342 synchronized (appenders) {
343 appenders.removeAppender(name);
344 }
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360 public void setLocationInfo(final boolean flag) {
361 locationInfo = flag;
362 }
363
364
365
366
367
368
369
370
371
372 public void setBufferSize(final int size) {
373
374
375
376
377 if (size < 0) {
378 throw new java.lang.NegativeArraySizeException("size");
379 }
380
381 synchronized (buffer) {
382
383
384
385 bufferSize = (size < 1) ? 1 : size;
386 buffer.notifyAll();
387 }
388 }
389
390
391
392
393
394 public int getBufferSize() {
395 return bufferSize;
396 }
397
398
399
400
401
402
403
404
405 public void setBlocking(final boolean value) {
406 synchronized (buffer) {
407 blocking = value;
408 buffer.notifyAll();
409 }
410 }
411
412
413
414
415
416
417
418
419
420 public boolean getBlocking() {
421 return blocking;
422 }
423
424
425
426
427 private static final class DiscardSummary {
428
429
430
431 private LoggingEvent maxEvent;
432
433
434
435
436 private int count;
437
438
439
440
441
442
443 public DiscardSummary(final LoggingEvent event) {
444 maxEvent = event;
445 count = 1;
446 }
447
448
449
450
451
452
453 public void add(final LoggingEvent event) {
454 if (event.getLevel().toInt() > maxEvent.getLevel().toInt()) {
455 maxEvent = event;
456 }
457
458 count++;
459 }
460
461
462
463
464
465
466 public LoggingEvent createEvent() {
467 String msg =
468 MessageFormat.format(
469 "Discarded {0} messages due to full event buffer including: {1}",
470 new Object[] { new Integer(count), maxEvent.getMessage() });
471
472 return new LoggingEvent(
473 "org.apache.log4j.AsyncAppender.DONT_REPORT_LOCATION",
474 Logger.getLogger(maxEvent.getLoggerName()),
475 maxEvent.getLevel(),
476 msg,
477 null);
478 }
479 }
480
481
482
483
484 private static class Dispatcher implements Runnable {
485
486
487
488 private final AsyncAppender parent;
489
490
491
492
493 private final List buffer;
494
495
496
497
498 private final Map discardMap;
499
500
501
502
503 private final AppenderAttachableImpl appenders;
504
505
506
507
508
509
510
511
512
513 public Dispatcher(
514 final AsyncAppender parent, final List buffer, final Map discardMap,
515 final AppenderAttachableImpl appenders) {
516
517 this.parent = parent;
518 this.buffer = buffer;
519 this.appenders = appenders;
520 this.discardMap = discardMap;
521 }
522
523
524
525
526 public void run() {
527 boolean isActive = true;
528
529
530
531
532 try {
533
534
535
536 while (isActive) {
537 LoggingEvent[] events = null;
538
539
540
541
542
543 synchronized (buffer) {
544 int bufferSize = buffer.size();
545 isActive = !parent.closed;
546
547 while ((bufferSize == 0) && isActive) {
548 buffer.wait();
549 bufferSize = buffer.size();
550 isActive = !parent.closed;
551 }
552
553 if (bufferSize > 0) {
554 events = new LoggingEvent[bufferSize + discardMap.size()];
555 buffer.toArray(events);
556
557
558
559
560 int index = bufferSize;
561
562 for (
563 Iterator iter = discardMap.values().iterator();
564 iter.hasNext();) {
565 events[index++] = ((DiscardSummary) iter.next()).createEvent();
566 }
567
568
569
570
571 buffer.clear();
572 discardMap.clear();
573
574
575
576 buffer.notifyAll();
577 }
578 }
579
580
581
582
583 if (events != null) {
584 for (int i = 0; i < events.length; i++) {
585 synchronized (appenders) {
586 appenders.appendLoopOnAppenders(events[i]);
587 }
588 }
589 }
590 }
591 } catch (InterruptedException ex) {
592 Thread.currentThread().interrupt();
593 }
594 }
595 }
596 }