/** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2009, QOS.ch. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */ package ch.qos.logback.classic; import java.util.Iterator; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.core.Appender; import ch.qos.logback.core.UnsynchronizedAppenderBase; import ch.qos.logback.core.spi.AppenderAttachable; import ch.qos.logback.core.spi.AppenderAttachableImpl; /** * This {@link Appender} logs {@link ILoggingEvent}s asynchronously. It acts * solely as an event dispatcher and must therefore be attached to one or more * child appenders in order to do useful logging. It is the user's * responsibility to close appenders, typically at the end of the application * lifecycle. *
* The appender buffers events in a {@link BlockingQueue} on the application * thread(s). The appenders {@link Dispatcher} thread takes events from the head * of the queue, and dispatches them to all the appenders that are attached to * this appender. With the method {@link #getQueueSize()} the number of events * currently stored in the event queue can be retrieved. *
* The appenders event queue is configured with a maximum capacity of * {@link #DEFAULT_QUEUE_CAPACITY 1000} (defined by the variable * {@link #setQueueCapacity(int) QueueCapacity}). If the queue is filled up, * then application threads are blocked from logging new events until the * dispatcher thread has had a chance to dispatch one or more events. When the * queue is no longer at its maximum configured capacity, application threads * are able to start logging events once more. Asynchronous logging therefore * becomes pseudo-synchronous when the appender is operating at or near the * capacity of its event buffer. This is not necessarily a bad thing. It's the * price a threaded application will have to pay sometimes. The appender is * designed to allow the application to keep on running, albeit taking slightly * more time to log events until the pressure on the appenders buffer eases. *
* Optimally tuning the size of the appenders event queue for maximum * application throughput depends upon several factors. Any or all of the * following factors are likely to cause pseudo-synchronous behavior to be * exhibited: *
* It's possible to attach separate instances of this appender to one another to * achieve multi-threaded dispatch. For example, assume a requirement for two * child appenders that each perform relatively expensive operations such as * messaging and file IO. For this case, one could set up a graph of appenders * such that the parent asynchronous appender, A, has two child asynchronous * appenders attached, B and C. Let's say B in turn has a child file I/O * appender attached, and C has a child messaging appender attached. This will * result in fast dispatch from A to both B and C via As dispatch thread. Bs * dispatch thread will be dedicated to logging to file I/O, and Cs dispatch * thread will be dedicated to logging via messaging. *
* Due to performance reasons the "expensive" caller data associated with an
* event is omitted while the event is prepared before being added to the event
* queue. By default only "cheap" data like the applications thread name and the
* MDC are copied. To
* configure the appender to copy the caller data as well, set the variable
* {@link #setIncludeCallerData(boolean) IncludeCallerData} to true
.
*
* Sample configuration: *
*
* When it fills up, {@link #append(LoggingEvent)} will block.
*
*
* The
* This operation is expensive (a stack trace is created). So don't use it
* if the caller data is not logged.
*
*
* The
* <appender name="ASYNC"
* class="ch.qos.logback.classic.AsyncAppender">
*
* @author Torsten Juergeleit
* @since 0.9.19
*/
public class AsyncAppender
* <param name="QueueCapacity" value="5000"/> <!--
* Default is 1000 -->
* <param name="IncludeCallerData" value="true"/> <!--
* Default is false -->
* <appender-ref ref="STDOUT"/>
* </appender>
* QueueCapacity
variable is set to 1000
by
* default.
*/
private int queueCapacity = DEFAULT_QUEUE_CAPACITY;
/**
* Before queuing a {@link LoggingEvent} the caller data is retrieved from the
* application thread.
* IncludeCallerData
variable is set to false
by
* default.
*/
private boolean includeCallerData = DEFAULT_INCLUDE_CALLER_DATA;
/** The appenders we are forwarding events to */
private final AppenderAttachableImplfalse
.
*
* @param includeCallerData
* if true
then caller data is calculated
*/
public void setIncludeCallerData(boolean includeCallerData) {
this.includeCallerData = includeCallerData;
}
/**
* Returns the number of {@link LoggingEvent}s currently stored in the
* appenders event queue.
*
* @return current queue size or -1
if the appender is not
* started
*/
public int getQueueSize() {
return (super.isStarted() ? queue.size() : -1);
}
@Override
public void start() {
if (!super.isStarted()) {
// Start all attached appenders
Iterator