FileDocCategorySizeDatePackage
AsyncAppender.javaAPI DocApache log4j 1.2.1515398Sat Aug 25 00:09:42 BST 2007org.apache.log4j

AsyncAppender

public class AsyncAppender extends AppenderSkeleton implements AppenderAttachable
The AsyncAppender lets users log events asynchronously.

The AsyncAppender will collect the events sent to it and then dispatch them to all the appenders that are attached to it. You can attach multiple appenders to an AsyncAppender.

The AsyncAppender uses a separate thread to serve the events in its buffer.

Important note: The AsyncAppender can only be script configured using the {@link org.apache.log4j.xml.DOMConfigurator}.

author
Ceki Gülcü
author
Curt Arnold
since
0.9.1

Fields Summary
public static final int
DEFAULT_BUFFER_SIZE
The default buffer size is set to 128 events.
private final List
buffer
Event buffer, also used as monitor to protect itself and discardMap from simulatenous modifications.
private final Map
discardMap
Map of DiscardSummary objects keyed by logger name.
private int
bufferSize
Buffer size.
AppenderAttachableImpl
aai
Nested appenders.
private final AppenderAttachableImpl
appenders
Nested appenders.
private final Thread
dispatcher
Dispatcher.
private boolean
locationInfo
Should location info be included in dispatched messages.
private boolean
blocking
Does appender block when buffer is full.
Constructors Summary
public AsyncAppender()
Create new instance.


        
    
    appenders = new AppenderAttachableImpl();

    //
    //   only set for compatibility
    aai = appenders;

    dispatcher =
      new Thread(new Dispatcher(this, buffer, discardMap, appenders));

    // It is the user's responsibility to close appenders before
    // exiting.
    dispatcher.setDaemon(true);

    // set the dispatcher priority to lowest possible value
    //        dispatcher.setPriority(Thread.MIN_PRIORITY);
    dispatcher.setName("Dispatcher-" + dispatcher.getName());
    dispatcher.start();
  
Methods Summary
public voidaddAppender(org.apache.log4j.Appender newAppender)
Add appender.

param
newAppender appender to add, may not be null.

    synchronized (appenders) {
      appenders.addAppender(newAppender);
    }
  
public voidappend(org.apache.log4j.spi.LoggingEvent event)
{@inheritDoc}

    //
    //   if dispatcher thread has died then
    //      append subsequent events synchronously
    //   See bug 23021
    if ((dispatcher == null) || !dispatcher.isAlive() || (bufferSize <= 0)) {
      synchronized (appenders) {
        appenders.appendLoopOnAppenders(event);
      }

      return;
    }

    // Set the NDC and thread name for the calling thread as these
    // LoggingEvent fields were not set at event creation time.
    event.getNDC();
    event.getThreadName();
    // Get a copy of this thread's MDC.
    event.getMDCCopy();
    if (locationInfo) {
      event.getLocationInformation();
    }

    synchronized (buffer) {
      while (true) {
        int previousSize = buffer.size();

        if (previousSize < bufferSize) {
          buffer.add(event);

          //
          //   if buffer had been empty
          //       signal all threads waiting on buffer
          //       to check their conditions.
          //
          if (previousSize == 0) {
            buffer.notifyAll();
          }

          break;
        }

        //
        //   Following code is only reachable if buffer is full
        //
        //
        //   if blocking and thread is not already interrupted
        //      and not the dispatcher then
        //      wait for a buffer notification
        boolean discard = true;
        if (blocking
                && !Thread.interrupted()
                && Thread.currentThread() != dispatcher) {
          try {
            buffer.wait();
            discard = false;
          } catch (InterruptedException e) {
            //
            //  reset interrupt status so
            //    calling code can see interrupt on
            //    their next wait or sleep.
            Thread.currentThread().interrupt();
          }
        }

        //
        //   if blocking is false or thread has been interrupted
        //   add event to discard map.
        //
        if (discard) {
          String loggerName = event.getLoggerName();
          DiscardSummary summary = (DiscardSummary) discardMap.get(loggerName);

          if (summary == null) {
            summary = new DiscardSummary(event);
            discardMap.put(loggerName, summary);
          } else {
            summary.add(event);
          }

          break;
        }
      }
    }
  
public voidclose()
Close this AsyncAppender by interrupting the dispatcher thread which will process all pending events before exiting.

    /**
     * Set closed flag and notify all threads to check their conditions.
     * Should result in dispatcher terminating.
     */
    synchronized (buffer) {
      closed = true;
      buffer.notifyAll();
    }

    try {
      dispatcher.join();
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      org.apache.log4j.helpers.LogLog.error(
        "Got an InterruptedException while waiting for the "
        + "dispatcher to finish.", e);
    }

    //
    //    close all attached appenders.
    //
    synchronized (appenders) {
      Enumeration iter = appenders.getAllAppenders();

      if (iter != null) {
        while (iter.hasMoreElements()) {
          Object next = iter.nextElement();

          if (next instanceof Appender) {
            ((Appender) next).close();
          }
        }
      }
    }
  
public java.util.EnumerationgetAllAppenders()
Get iterator over attached appenders.

return
iterator or null if no attached appenders.

    synchronized (appenders) {
      return appenders.getAllAppenders();
    }
  
public org.apache.log4j.AppendergetAppender(java.lang.String name)
Get appender by name.

param
name name, may not be null.
return
matching appender or null.

    synchronized (appenders) {
      return appenders.getAppender(name);
    }
  
public booleangetBlocking()
Gets whether appender should block calling thread when buffer is full. If false, messages will be counted by logger and a summary message appended after the contents of the buffer have been appended.

return
true if calling thread will be blocked when buffer is full.

    return blocking;
  
public intgetBufferSize()
Gets the current buffer size.

return
the current value of the BufferSize option.

    return bufferSize;
  
public booleangetLocationInfo()
Gets whether the location of the logging request call should be captured.

return
the current value of the LocationInfo option.

    return locationInfo;
  
public booleanisAttached(org.apache.log4j.Appender appender)
Determines if specified appender is attached.

param
appender appender.
return
true if attached.

    synchronized (appenders) {
      return appenders.isAttached(appender);
    }
  
public voidremoveAllAppenders()
Removes and closes all attached appenders.

    synchronized (appenders) {
      appenders.removeAllAppenders();
    }
  
public voidremoveAppender(org.apache.log4j.Appender appender)
Removes an appender.

param
appender appender to remove.

    synchronized (appenders) {
      appenders.removeAppender(appender);
    }
  
public voidremoveAppender(java.lang.String name)
Remove appender by name.

param
name name.

    synchronized (appenders) {
      appenders.removeAppender(name);
    }
  
public booleanrequiresLayout()
{@inheritDoc}

    return false;
  
public voidsetBlocking(boolean value)
Sets whether appender should wait if there is no space available in the event buffer or immediately return.

param
value true if appender should wait until available space in buffer.

    synchronized (buffer) {
      blocking = value;
      buffer.notifyAll();
    }
  
public voidsetBufferSize(int size)
Sets the number of messages allowed in the event buffer before the calling thread is blocked (if blocking is true) or until messages are summarized and discarded. Changing the size will not affect messages already in the buffer.

param
size buffer size, must be positive.

    //
    //   log4j 1.2 would throw exception if size was negative
    //      and deadlock if size was zero.
    //
    if (size < 0) {
      throw new java.lang.NegativeArraySizeException("size");
    }

    synchronized (buffer) {
      //
      //   don't let size be zero.
      //
      bufferSize = (size < 1) ? 1 : size;
      buffer.notifyAll();
    }
  
public voidsetLocationInfo(boolean flag)
The LocationInfo option takes a boolean value. By default, it is set to false which means there will be no effort to extract the location information related to the event. As a result, the event that will be ultimately logged will likely to contain the wrong location information (if present in the log format).

Location information extraction is comparatively very slow and should be avoided unless performance is not a concern.

param
flag true if location information should be extracted.

    locationInfo = flag;