You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2013/04/01 05:51:23 UTC

svn commit: r1463078 [1/4] - in /logging/log4j/log4j2/trunk: ./ core/src/main/java/org/apache/logging/log4j/core/ core/src/main/java/org/apache/logging/log4j/core/appender/ core/src/main/java/org/apache/logging/log4j/core/config/ core/src/main/java/org...

Author: rgoers
Date: Mon Apr  1 03:51:21 2013
New Revision: 1463078

URL: http://svn.apache.org/r1463078
Log:
LOG4J2-163, LOG4J2-164, LOG4J2-151. LOG4J2-153. LOG4J2-157 - Add Asynchronous Loggers

Added:
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/AsynchAppenderNoLocationTest.java
    logging/log4j/log4j2/trunk/core/src/test/resources/log4j-asynch-no-location.xml
    logging/log4j/log4j2/trunk/log4j-async/
    logging/log4j/log4j2/trunk/log4j-async/pom.xml
    logging/log4j/log4j2/trunk/log4j-async/src/
    logging/log4j/log4j2/trunk/log4j-async/src/main/
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLogger.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLoggerContext.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLoggerContextSelector.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/CachedClock.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/Clock.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/ClockFactory.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/CoarseCachedClock.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/RingBufferLogEvent.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/RingBufferLogEventHandler.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/RingBufferLogEventTranslator.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/SystemClock.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/appender/
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/appender/FastFileAppender.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/appender/FastFileManager.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/appender/FastRollingFileAppender.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/appender/FastRollingFileManager.java
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/config/
    logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/config/AsyncLoggerConfig.java
    logging/log4j/log4j2/trunk/log4j-async/src/site/
    logging/log4j/log4j2/trunk/log4j-async/src/site/site.xml
    logging/log4j/log4j2/trunk/log4j-async/src/site/xdoc/
    logging/log4j/log4j2/trunk/log4j-async/src/site/xdoc/index.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/AsyncLoggerContextSelectorTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/AsyncLoggerContextTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/AsyncLoggerLocationTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/AsyncLoggerTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/CachedClockTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/ClockFactoryTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/SystemClockTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/appender/
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/appender/FastFileAppenderLocationTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/appender/FastFileAppenderTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/appender/FastRollingFileAppenderLocationTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/appender/FastRollingFileAppenderTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/config/
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/config/AsyncLoggerConfigTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/perftest/
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/perftest/IPerfTestRunner.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/perftest/MTPerfTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/perftest/PerfTest.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/perftest/PerfTestDriver.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/perftest/PerfTestResultFormatter.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/perftest/RunLog4j1.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/perftest/RunLog4j2.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/java/org/apache/logging/log4j/async/perftest/RunLogback.java
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/AsyncLoggerConfigTest.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/AsyncLoggerLocationTest.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/AsyncLoggerTest.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/FastFileAppenderLocationTest.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/FastFileAppenderTest.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/FastRollingFileAppenderLocationTest.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/FastRollingFileAppenderTest.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/log4j.dtd
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf-log4j12-async.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf-log4j12.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf-logback-async.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf-logback.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf1syncFastFile.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf1syncFile.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf2syncRollFastFile.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf2syncRollFile.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf3PlainNoLoc.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf4PlainLocation.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf5AsyncApndNoLoc.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf6AsyncApndLoc.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf7MixedNoLoc.xml
    logging/log4j/log4j2/trunk/log4j-async/src/test/resources/perf8MixedLoc.xml
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/async.xml
Modified:
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/Logger.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/AsynchAppender.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/DateLookupTest.java
    logging/log4j/log4j2/trunk/core/src/test/resources/log4j-asynch.xml
    logging/log4j/log4j2/trunk/flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java
    logging/log4j/log4j2/trunk/pom.xml
    logging/log4j/log4j2/trunk/src/changes/changes.xml
    logging/log4j/log4j2/trunk/src/site/site.xml
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/appenders.xml

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LogEvent.java?rev=1463078&r1=1463077&r2=1463078&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LogEvent.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LogEvent.java Mon Apr  1 03:51:21 2013
@@ -104,4 +104,47 @@ public interface LogEvent extends Serial
      */
     String getFQCN();
 
+    /**
+     * Returns whether the source of the logging request is required downstream.
+     * Asynchronous Loggers and Appenders use this flag to determine whether
+     * to take a {@code StackTrace} snapshot or not before handing off this
+     * event to another thread.
+     * @return {@code true} if the source of the logging request is required 
+     *          downstream, {@code false} otherwise.
+     * @see #getSource()
+     */
+    // see also LOG4J2-153
+    boolean isIncludeLocation();
+
+    /**
+     * Sets whether the source of the logging request is required downstream.
+     * Asynchronous Loggers and Appenders use this flag to determine whether
+     * to take a {@code StackTrace} snapshot or not before handing off this
+     * event to another thread.
+     * @param locationRequired {@code true} if the source of the logging request 
+     *           is required downstream, {@code false} otherwise.
+     * @see #getSource()
+     */
+    void setIncludeLocation(boolean locationRequired);
+    
+    /**
+     * Returns {@code true} if this event is the last one in a batch, 
+     * {@code false} otherwise. Used by asynchronous Loggers and Appenders to
+     * signal to buffered downstream components when to flush to disk, as a
+     * more efficient alternative to the {@code immediateFlush=true} 
+     * configuration.
+     * @return whether this event is the last one in a batch.
+     */
+    // see also LOG4J2-164
+    boolean isEndOfBatch();
+    
+    /**
+     * Sets whether this event is the last one in a batch.
+     * Used by asynchronous Loggers and Appenders to signal to buffered 
+     * downstream components when to flush to disk, as a more efficient 
+     * alternative to the {@code immediateFlush=true} configuration.
+     * @param endOfBatch {@code true} if this event is the last one in a batch, 
+     * {@code false} otherwise.
+     */
+    void setEndOfBatch(boolean endOfBatch);
 }

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/Logger.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/Logger.java?rev=1463078&r1=1463077&r2=1463078&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/Logger.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/Logger.java Mon Apr  1 03:51:21 2013
@@ -234,8 +234,9 @@ public class Logger extends AbstractLogg
      * The binding between a Logger and its configuration.
      */
     protected class PrivateConfig {
-        private final LoggerConfig loggerConfig;
-        private final Configuration config;
+        // config fields are public to make them visible to Logger subclasses
+        public final LoggerConfig loggerConfig;
+        public final Configuration config;
         private final Level level;
         private final int intLevel;
         private final Logger logger;
@@ -264,7 +265,8 @@ public class Logger extends AbstractLogg
             this.logger = pc.logger;
         }
 
-        protected void logEvent(final LogEvent event) {
+        // LOG4J2-151: changed visibility to public
+        public void logEvent(LogEvent event) {
             config.getConfigurationMonitor().checkConfiguration();
             loggerConfig.log(event);
         }

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java?rev=1463078&r1=1463077&r2=1463078&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java Mon Apr  1 03:51:21 2013
@@ -326,8 +326,8 @@ public class LoggerContext implements or
         }
     }
 
-
-    private Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) {
+    // LOG4J2-151: changed visibility from private to protected
+    protected Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) {
         return new Logger(ctx, name, messageFactory);
     }
 

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/AsynchAppender.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/AsynchAppender.java?rev=1463078&r1=1463077&r2=1463078&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/AsynchAppender.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/AsynchAppender.java Mon Apr  1 03:51:21 2013
@@ -56,18 +56,21 @@ public final class AsynchAppender<T exte
     private final Configuration config;
     private final AppenderRef[] appenderRefs;
     private final String errorRef;
+    private final boolean includeLocation;
     private AppenderControl errorAppender;
     private AsynchThread thread;
 
     private AsynchAppender(final String name, final Filter filter, final AppenderRef[] appenderRefs,
                            final String errorRef, final int queueSize, final boolean blocking,
-                           final boolean handleExceptions, final Configuration config) {
+                           final boolean handleExceptions, final Configuration config,
+                           final boolean includeLocation) {
         super(name, filter, null, handleExceptions);
         this.queue = new ArrayBlockingQueue<Serializable>(queueSize);
         this.blocking = blocking;
         this.config = config;
         this.appenderRefs = appenderRefs;
         this.errorRef = errorRef;
+        this.includeLocation = includeLocation;
     }
 
     @Override
@@ -123,13 +126,14 @@ public final class AsynchAppender<T exte
             boolean appendSuccessful = false;
             if (blocking){
                 try {
-                    queue.put(Log4jLogEvent.serialize((Log4jLogEvent) event)); // wait for free slots in the queue
+                    // wait for free slots in the queue
+                    queue.put(Log4jLogEvent.serialize((Log4jLogEvent) event, includeLocation));
                     appendSuccessful = true;
                 } catch (InterruptedException e) {
                     LOGGER.warn("Interrupted while waiting for a free slots in the LogEvent-queue at the AsynchAppender {}", getName());
                 }
             } else {
-                appendSuccessful = queue.offer(Log4jLogEvent.serialize((Log4jLogEvent) event));
+                appendSuccessful = queue.offer(Log4jLogEvent.serialize((Log4jLogEvent) event, includeLocation));
                 if (!appendSuccessful) {
                     error("Appender " + getName() + " is unable to write primary appenders. queue is full");
                 }
@@ -147,6 +151,7 @@ public final class AsynchAppender<T exte
      * @param blocking True if the Appender should wait when the queue is full. The default is true.
      * @param size The size of the event queue. The default is 128.
      * @param name The name of the Appender.
+     * @param includeLocation whether to include location information. The default is false.
      * @param filter The Filter or null.
      * @param config The Configuration.
      * @param suppress "true" if exceptions should be hidden from the application, "false" otherwise.
@@ -156,14 +161,15 @@ public final class AsynchAppender<T exte
      */
     @PluginFactory
     public static <S extends Serializable> AsynchAppender<S> createAppender(
-                                                @PluginElement("appender-ref") final AppenderRef[] appenderRefs,
-                                                @PluginAttr("error-ref") final String errorRef,
-                                                @PluginAttr("blocking") final String blocking,
-                                                @PluginAttr("bufferSize") final String size,
-                                                @PluginAttr("name") final String name,
-                                                @PluginElement("filter") final Filter filter,
-                                                @PluginConfiguration final Configuration config,
-                                                @PluginAttr("suppressExceptions") final String suppress) {
+                @PluginElement("appender-ref") final AppenderRef[] appenderRefs,
+                @PluginAttr("error-ref") final String errorRef,
+                @PluginAttr("blocking") final String blocking,
+                @PluginAttr("bufferSize") final String size,
+                @PluginAttr("name") final String name,
+                @PluginAttr("includeLocation") final String includeLocation,
+                @PluginElement("filter") final Filter filter,
+                @PluginConfiguration final Configuration config,
+                @PluginAttr("suppressExceptions") final String suppress) {
         if (name == null) {
             LOGGER.error("No name provided for AsynchAppender");
             return null;
@@ -174,11 +180,13 @@ public final class AsynchAppender<T exte
 
         final boolean isBlocking = blocking == null ? true : Boolean.valueOf(blocking);
         final int queueSize = size == null ? DEFAULT_QUEUE_SIZE : Integer.parseInt(size);
+        final boolean isIncludeLocation = includeLocation == null ? false :
+                Boolean.parseBoolean(includeLocation);
 
         final boolean handleExceptions = suppress == null ? true : Boolean.valueOf(suppress);
 
-        return new AsynchAppender<S>(name, filter, appenderRefs, errorRef, queueSize, isBlocking, handleExceptions,
-                                  config);
+        return new AsynchAppender<S>(name, filter, appenderRefs, errorRef, 
+                queueSize, isBlocking, handleExceptions, config, isIncludeLocation);
     }
 
     /**
@@ -210,8 +218,9 @@ public final class AsynchAppender<T exte
                     continue;
                 }
                 final Log4jLogEvent event = Log4jLogEvent.deserialize(s);
+                event.setEndOfBatch(queue.isEmpty());
                 boolean success = false;
-                for (final AppenderControl control : appenders) {
+                for (final AppenderControl<?> control : appenders) {
                     try {
                         control.callAppender(event);
                         success = true;
@@ -233,7 +242,8 @@ public final class AsynchAppender<T exte
                     Serializable s = queue.take();
                     if (s instanceof Log4jLogEvent) {
                         final Log4jLogEvent event = Log4jLogEvent.deserialize(s);
-                        for (final AppenderControl control : appenders) {
+                        event.setEndOfBatch(queue.isEmpty());
+                        for (final AppenderControl<?> control : appenders) {
                             control.callAppender(event);
                         }
                     }

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java?rev=1463078&r1=1463077&r2=1463078&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java Mon Apr  1 03:51:21 2013
@@ -25,9 +25,11 @@ import org.apache.logging.log4j.core.Fil
 import org.apache.logging.log4j.core.LifeCycle;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
 import org.apache.logging.log4j.core.filter.AbstractFilterable;
+import org.apache.logging.log4j.core.helpers.Constants;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.impl.LogEventFactory;
+import org.apache.logging.log4j.core.lookup.StrSubstitutor;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.config.plugins.PluginAttr;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
@@ -38,6 +40,7 @@ import org.apache.logging.log4j.message.
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -61,13 +64,13 @@ public class LoggerConfig extends Abstra
     private LogEventFactory logEventFactory;
     private Level level;
     private boolean additive = true;
+    private boolean includeLocation = true;
     private LoggerConfig parent;
     private final AtomicInteger counter = new AtomicInteger();
     private boolean shutdown = false;
     private final Map<Property, Boolean> properties;
     private final Configuration config;
 
-
     /**
      * Default constructor.
      */
@@ -81,11 +84,13 @@ public class LoggerConfig extends Abstra
 
     /**
      * Constructor that sets the name, level and additive values.
+     * 
      * @param name The Logger name.
      * @param level The Level.
      * @param additive true if the Logger is additive, false otherwise.
      */
-    public LoggerConfig(final String name, final Level level, final boolean additive) {
+    public LoggerConfig(final String name, final Level level,
+            final boolean additive) {
         this.logEventFactory = this;
         this.name = name;
         this.level = level;
@@ -94,14 +99,18 @@ public class LoggerConfig extends Abstra
         this.config = null;
     }
 
-    protected LoggerConfig(final String name, final List<AppenderRef> appenders, final Filter filter, final Level level,
-                           final boolean additive, final Property[] properties, final Configuration config) {
+    protected LoggerConfig(final String name,
+            final List<AppenderRef> appenders, final Filter filter,
+            final Level level, final boolean additive,
+            final Property[] properties, final Configuration config,
+            final boolean includeLocation) {
         super(filter);
         this.logEventFactory = this;
         this.name = name;
         this.appenderRefs = appenders;
         this.level = level;
         this.additive = additive;
+        this.includeLocation = includeLocation;
         this.config = config;
         if (properties != null && properties.length > 0) {
             this.properties = new HashMap<Property, Boolean>(properties.length);
@@ -121,6 +130,7 @@ public class LoggerConfig extends Abstra
 
     /**
      * Returns the name of the LoggerConfig.
+     * 
      * @return the name of the LoggerConfig.
      */
     public String getName() {
@@ -129,6 +139,7 @@ public class LoggerConfig extends Abstra
 
     /**
      * Sets the parent of this LoggerConfig.
+     * 
      * @param parent the parent LoggerConfig.
      */
     public void setParent(final LoggerConfig parent) {
@@ -137,6 +148,7 @@ public class LoggerConfig extends Abstra
 
     /**
      * Returns the parent of this LoggerConfig.
+     * 
      * @return the LoggerConfig that is the parent of this one.
      */
     public LoggerConfig getParent() {
@@ -145,16 +157,20 @@ public class LoggerConfig extends Abstra
 
     /**
      * Adds an Appender to the LoggerConfig.
+     * 
      * @param appender The Appender to add.
      * @param level The Level to use.
      * @param filter A Filter for the Appender reference.
      */
-    public void addAppender(final Appender appender, final Level level, final Filter filter) {
-        appenders.put(appender.getName(), new AppenderControl(appender, level, filter));
+    public void addAppender(final Appender appender, final Level level,
+            final Filter filter) {
+        appenders.put(appender.getName(), new AppenderControl(appender, level,
+                filter));
     }
 
     /**
      * Removes the Appender with the specific name.
+     * 
      * @param name The name of the Appender.
      */
     public void removeAppender(final String name) {
@@ -166,11 +182,14 @@ public class LoggerConfig extends Abstra
 
     /**
      * Returns all Appenders as a Map.
-     * @return a Map with the Appender name as the key and the Appender as the value.
+     * 
+     * @return a Map with the Appender name as the key and the Appender as the
+     *         value.
      */
     public Map<String, Appender<?>> getAppenders() {
         final Map<String, Appender<?>> map = new HashMap<String, Appender<?>>();
-        for (final Map.Entry<String, AppenderControl<?>> entry : appenders.entrySet()) {
+        for (final Map.Entry<String, AppenderControl<?>> entry : appenders
+                .entrySet()) {
             map.put(entry.getKey(), entry.getValue().getAppender());
         }
         return map;
@@ -202,6 +221,7 @@ public class LoggerConfig extends Abstra
 
     /**
      * Returns the Appender references.
+     * 
      * @return a List of all the Appender names attached to this LoggerConfig.
      */
     public List<AppenderRef> getAppenderRefs() {
@@ -210,6 +230,7 @@ public class LoggerConfig extends Abstra
 
     /**
      * Sets the logging Level.
+     * 
      * @param level The logging Level.
      */
     public void setLevel(final Level level) {
@@ -218,6 +239,7 @@ public class LoggerConfig extends Abstra
 
     /**
      * Returns the logging Level.
+     * 
      * @return the logging Level.
      */
     public Level getLevel() {
@@ -226,6 +248,7 @@ public class LoggerConfig extends Abstra
 
     /**
      * Returns the LogEventFactory.
+     * 
      * @return the LogEventFactory.
      */
     public LogEventFactory getLogEventFactory() {
@@ -233,7 +256,9 @@ public class LoggerConfig extends Abstra
     }
 
     /**
-     * Sets the LogEventFactory. Usually the LogEventFactory will be this LoggerConfig.
+     * Sets the LogEventFactory. Usually the LogEventFactory will be this
+     * LoggerConfig.
+     * 
      * @param logEventFactory the LogEventFactory.
      */
     public void setLogEventFactory(final LogEventFactory logEventFactory) {
@@ -242,6 +267,7 @@ public class LoggerConfig extends Abstra
 
     /**
      * Returns the valid of the additive flag.
+     * 
      * @return true if the LoggerConfig is additive, false otherwise.
      */
     public boolean isAdditive() {
@@ -250,14 +276,47 @@ public class LoggerConfig extends Abstra
 
     /**
      * Sets the additive setting.
-     * @param additive true if thee LoggerConfig should be additive, false otherwise.
+     * 
+     * @param additive true if the LoggerConfig should be additive, false
+     *            otherwise.
      */
     public void setAdditive(final boolean additive) {
         this.additive = additive;
     }
 
     /**
+     * Returns the value of logger configuration attribute {@code includeLocation},
+     * or, if no such attribute was configured, {@code true} if logging is
+     * synchronous or {@code false} if logging is asynchronous.
+     * 
+     * @return whether location should be passed downstream
+     */
+    public boolean isIncludeLocation() {
+        return includeLocation;
+    }
+
+    /**
+     * Returns an unmodifiable map with the configuration properties, or
+     * {@code null} if this {@code LoggerConfig} does not have any configuration
+     * properties.
+     * <p>
+     * For each {@code Property} key in the map, the value is {@code true} if
+     * the property value has a variable that needs to be substituted.
+     * 
+     * @return an unmodifiable map with the configuration properties, or
+     *         {@code null}
+     * @see Configuration#getSubst()
+     * @see StrSubstitutor
+     */
+    // LOG4J2-157
+    public Map<Property, Boolean> getProperties() {
+        return properties == null ? null : Collections
+                .unmodifiableMap(properties);
+    }
+
+    /**
      * Logs an event.
+     * 
      * @param loggerName The name of the Logger.
      * @param marker A Marker or null if none is present.
      * @param fqcn The fully qualified class name of the caller.
@@ -265,24 +324,29 @@ public class LoggerConfig extends Abstra
      * @param data The Message.
      * @param t A Throwable or null.
      */
-    public void log(final String loggerName, final Marker marker, final String fqcn, final Level level,
-                    final Message data, final Throwable t) {
+    public void log(final String loggerName, final Marker marker,
+            final String fqcn, final Level level, final Message data,
+            final Throwable t) {
         List<Property> props = null;
         if (properties != null) {
             props = new ArrayList<Property>(properties.size());
 
-            for (final Map.Entry<Property, Boolean> entry : properties.entrySet()) {
+            for (final Map.Entry<Property, Boolean> entry : properties
+                    .entrySet()) {
                 final Property prop = entry.getKey();
-                final String value = entry.getValue() ? config.getSubst().replace(prop.getValue()) : prop.getValue();
+                final String value = entry.getValue() ? config.getSubst()
+                        .replace(prop.getValue()) : prop.getValue();
                 props.add(Property.createProperty(prop.getName(), value));
             }
         }
-        final LogEvent event = logEventFactory.createEvent(loggerName, marker, fqcn, level, data, props, t);
+        final LogEvent event = logEventFactory.createEvent(loggerName, marker,
+                fqcn, level, data, props, t);
         log(event);
     }
 
     /**
-     * Waits for all log events to complete before shutting down this loggerConfig.
+     * Waits for all log events to complete before shutting down this
+     * loggerConfig.
      */
     private synchronized void waitForCompletion() {
         if (shutdown) {
@@ -303,6 +367,7 @@ public class LoggerConfig extends Abstra
 
     /**
      * Logs an event.
+     * 
      * @param event The log event.
      */
     public void log(final LogEvent event) {
@@ -313,6 +378,8 @@ public class LoggerConfig extends Abstra
                 return;
             }
 
+            event.setIncludeLocation(isIncludeLocation());
+
             callAppenders(event);
 
             if (additive && parent != null) {
@@ -330,7 +397,7 @@ public class LoggerConfig extends Abstra
         }
     }
 
-    private void callAppenders(final LogEvent event) {
+    protected void callAppenders(final LogEvent event) {
         for (final AppenderControl control : appenders.values()) {
             control.callAppender(event);
         }
@@ -338,6 +405,7 @@ public class LoggerConfig extends Abstra
 
     /**
      * Creates a log event.
+     * 
      * @param loggerName The name of the Logger.
      * @param marker An optional Marker.
      * @param fqcn The fully qualified class name of the caller.
@@ -347,9 +415,11 @@ public class LoggerConfig extends Abstra
      * @param t An optional Throwable.
      * @return The LogEvent.
      */
-    public LogEvent createEvent(final String loggerName, final Marker marker, final String fqcn, final Level level,
-                                final Message data, final List<Property> properties, final Throwable t) {
-        return new Log4jLogEvent(loggerName, marker, fqcn, level, data, properties, t);
+    public LogEvent createEvent(final String loggerName, final Marker marker,
+            final String fqcn, final Level level, final Message data,
+            final List<Property> properties, final Throwable t) {
+        return new Log4jLogEvent(loggerName, marker, fqcn, level, data,
+                properties, t);
     }
 
     @Override
@@ -359,9 +429,11 @@ public class LoggerConfig extends Abstra
 
     /**
      * Factory method to create a LoggerConfig.
+     * 
      * @param additivity True if additive, false otherwise.
      * @param levelName The Level to be associated with the Logger.
      * @param loggerName The name of the Logger.
+     * @param includeLocation whether location should be passed downstream
      * @param refs An array of Appender names.
      * @param properties Properties to pass to the Logger.
      * @param config The Configuration.
@@ -369,13 +441,15 @@ public class LoggerConfig extends Abstra
      * @return A new LoggerConfig.
      */
     @PluginFactory
-    public static LoggerConfig createLogger(@PluginAttr("additivity") final String additivity,
-                                            @PluginAttr("level") final String levelName,
-                                            @PluginAttr("name") final String loggerName,
-                                            @PluginElement("appender-ref") final AppenderRef[] refs,
-                                            @PluginElement("properties") final Property[] properties,
-                                            @PluginConfiguration final Configuration config,
-                                            @PluginElement("filters") final Filter filter) {
+    public static LoggerConfig createLogger(
+            @PluginAttr("additivity") final String additivity,
+            @PluginAttr("level") final String levelName,
+            @PluginAttr("name") final String loggerName,
+            @PluginAttr("includeLocation") final String includeLocation,
+            @PluginElement("appender-ref") final AppenderRef[] refs,
+            @PluginElement("properties") final Property[] properties,
+            @PluginConfiguration final Configuration config,
+            @PluginElement("filters") final Filter filter) {
         if (loggerName == null) {
             LOGGER.error("Loggers cannot be configured without a name");
             return null;
@@ -386,13 +460,28 @@ public class LoggerConfig extends Abstra
         try {
             level = Level.toLevel(levelName, Level.ERROR);
         } catch (final Exception ex) {
-            LOGGER.error("Invalid Log level specified: {}. Defaulting to Error", levelName);
+            LOGGER.error(
+                    "Invalid Log level specified: {}. Defaulting to Error",
+                    levelName);
             level = Level.ERROR;
         }
         final String name = loggerName.equals("root") ? "" : loggerName;
-        final boolean additive = additivity == null ? true : Boolean.parseBoolean(additivity);
+        final boolean additive = additivity == null ? true : Boolean
+                .parseBoolean(additivity);
 
-        return new LoggerConfig(name, appenderRefs, filter, level, additive, properties, config);
+        return new LoggerConfig(name, appenderRefs, filter, level, additive,
+                properties, config, includeLocation(includeLocation));
+    }
+    
+    // Note: for asynchronous loggers, includeLocation default is FALSE,
+    // for synchronous loggers, includeLocation default is TRUE.
+    private static boolean includeLocation(String includeLocationConfigValue) {
+        if (includeLocationConfigValue == null) {
+            final boolean sync = !"org.apache.logging.log4j.async.AsyncLoggerContextSelector"
+                    .equals(System.getProperty(Constants.LOG4J_CONTEXT_SELECTOR));
+            return sync;
+        }
+        return Boolean.parseBoolean(includeLocationConfigValue);
     }
 
     /**
@@ -402,24 +491,30 @@ public class LoggerConfig extends Abstra
     public static class RootLogger extends LoggerConfig {
 
         @PluginFactory
-        public static LoggerConfig createLogger(@PluginAttr("additivity") final String additivity,
-                                            @PluginAttr("level") final String levelName,
-                                            @PluginElement("appender-ref") final AppenderRef[] refs,
-                                            @PluginElement("properties") final Property[] properties,
-                                            @PluginConfiguration final Configuration config,
-                                            @PluginElement("filters") final Filter filter) {
+        public static LoggerConfig createLogger(
+                @PluginAttr("additivity") final String additivity,
+                @PluginAttr("level") final String levelName,
+                @PluginAttr("includeLocation") final String includeLocation,
+                @PluginElement("appender-ref") final AppenderRef[] refs,
+                @PluginElement("properties") final Property[] properties,
+                @PluginConfiguration final Configuration config,
+                @PluginElement("filters") final Filter filter) {
             final List<AppenderRef> appenderRefs = Arrays.asList(refs);
             Level level;
             try {
                 level = Level.toLevel(levelName, Level.ERROR);
             } catch (final Exception ex) {
-                LOGGER.error("Invalid Log level specified: {}. Defaulting to Error", levelName);
+                LOGGER.error(
+                        "Invalid Log level specified: {}. Defaulting to Error",
+                        levelName);
                 level = Level.ERROR;
             }
-            final boolean additive = additivity == null ? true : Boolean.parseBoolean(additivity);
+            final boolean additive = additivity == null ? true : Boolean
+                    .parseBoolean(additivity);
 
-            return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, level, additive, properties,
-                config);
+            return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs,
+                    filter, level, additive, properties, config,
+                    includeLocation(includeLocation));
         }
     }
 

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java?rev=1463078&r1=1463077&r2=1463078&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java Mon Apr  1 03:51:21 2013
@@ -49,6 +49,8 @@ public class Log4jLogEvent implements Lo
     private final ThreadContext.ContextStack ndc;
     private String threadName = null;
     private StackTraceElement location;
+    private boolean includeLocation;
+    private boolean endOfBatch = false;
 
     /**
      * Constructor.
@@ -222,31 +224,54 @@ public class Log4jLogEvent implements Lo
      * @return the StackTraceElement for the caller.
      */
     public StackTraceElement getSource() {
-        if (fqcnOfLogger == null) {
+        if (location != null) {
+            return location;
+        }
+        if (fqcnOfLogger == null || !includeLocation) {
             return null;
         }
-        if (location == null) {
-            final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
-            boolean next = false;
-            for (final StackTraceElement element : stackTrace) {
-                final String className = element.getClassName();
-                if (next) {
-                    if (fqcnOfLogger.equals(className)) {
-                        continue;
-                    }
-                    location = element;
-                    break;
-                }
+        location = calcLocation(fqcnOfLogger);
+        return location;
+    }
 
+    public static StackTraceElement calcLocation(String fqcnOfLogger) {
+        if (fqcnOfLogger == null) {
+            return null;
+        }
+        final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+        boolean next = false;
+        for (final StackTraceElement element : stackTrace) {
+            final String className = element.getClassName();
+            if (next) {
                 if (fqcnOfLogger.equals(className)) {
-                    next = true;
-                } else if (NOT_AVAIL.equals(className)) {
-                    break;
+                    continue;
                 }
+                return element;
+            }
+
+            if (fqcnOfLogger.equals(className)) {
+                next = true;
+            } else if (NOT_AVAIL.equals(className)) {
+                break;
             }
         }
+        return null;
+    }
 
-        return location;
+    public boolean isIncludeLocation() {
+        return includeLocation;
+    }
+
+    public void setIncludeLocation(boolean includeLocation) {
+        this.includeLocation = includeLocation;
+    }
+
+    public boolean isEndOfBatch() {
+        return endOfBatch;
+    }
+
+    public void setEndOfBatch(boolean endOfBatch) {
+        this.endOfBatch = endOfBatch;
     }
 
     /**
@@ -254,11 +279,12 @@ public class Log4jLogEvent implements Lo
      * @return a LogEventProxy.
      */
     protected Object writeReplace() {
-        return new LogEventProxy(this);
+        return new LogEventProxy(this, this.includeLocation);
     }
 
-    public static Serializable serialize(final Log4jLogEvent event) {
-        return new LogEventProxy(event);
+    public static Serializable serialize(final Log4jLogEvent event, 
+            final boolean includeLocation) {
+        return new LogEventProxy(event, includeLocation);
     }
 
     public static Log4jLogEvent deserialize(final Serializable event) {
@@ -267,8 +293,13 @@ public class Log4jLogEvent implements Lo
         }
         if (event instanceof LogEventProxy) {
             final LogEventProxy proxy = (LogEventProxy) event;
-            return new Log4jLogEvent(proxy.name, proxy.marker, proxy.fqcnOfLogger, proxy.level, proxy.message,
-                proxy.throwable, proxy.mdc, proxy.ndc, proxy.threadName, proxy.location, proxy.timestamp);
+            Log4jLogEvent result = new Log4jLogEvent(proxy.name, proxy.marker, 
+                    proxy.fqcnOfLogger, proxy.level, proxy.message, 
+                    proxy.throwable, proxy.mdc, proxy.ndc, proxy.threadName, 
+                    proxy.location, proxy.timestamp);
+            result.setEndOfBatch(proxy.isEndOfBatch);
+            result.setIncludeLocation(proxy.isLocationRequired);
+            return result;
         }
         throw new IllegalArgumentException("Event is not a serialized LogEvent: " + event.toString());
     }
@@ -304,8 +335,10 @@ public class Log4jLogEvent implements Lo
         private final ThreadContext.ContextStack ndc;
         private final String threadName;
         private final StackTraceElement location;
+        private final boolean isLocationRequired;
+        private final boolean isEndOfBatch;
 
-        public LogEventProxy(final Log4jLogEvent event) {
+        public LogEventProxy(final Log4jLogEvent event, boolean includeLocation) {
             this.fqcnOfLogger = event.fqcnOfLogger;
             this.marker = event.marker;
             this.level = event.level;
@@ -315,8 +348,10 @@ public class Log4jLogEvent implements Lo
             this.throwable = event.throwable;
             this.mdc = event.mdc;
             this.ndc = event.ndc;
-            this.location = event.getSource();
+            this.location = includeLocation ? event.getSource() : null;
             this.threadName = event.getThreadName();
+            this.isLocationRequired = includeLocation;
+            this.isEndOfBatch = event.endOfBatch;
         }
 
         /**
@@ -324,10 +359,12 @@ public class Log4jLogEvent implements Lo
          * @return Log4jLogEvent.
          */
         protected Object readResolve() {
-            return new Log4jLogEvent(name, marker, fqcnOfLogger, level, message, throwable, mdc, ndc, threadName,
-                                     location, timestamp);
+            Log4jLogEvent result = new Log4jLogEvent(name, marker, fqcnOfLogger, 
+                    level, message, throwable, mdc, ndc, threadName, location, 
+                    timestamp);
+            result.setEndOfBatch(isEndOfBatch);
+            result.setIncludeLocation(isLocationRequired);
+            return result;
         }
-
     }
-
 }

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/AsynchAppenderNoLocationTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/AsynchAppenderNoLocationTest.java?rev=1463078&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/AsynchAppenderNoLocationTest.java (added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/AsynchAppenderNoLocationTest.java Mon Apr  1 03:51:21 2013
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.appender;
+
+import static org.junit.Assert.*;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class AsynchAppenderNoLocationTest {
+    private static final String CONFIG = "log4j-asynch-no-location.xml";
+    private static Configuration config;
+    private static ListAppender app;
+    private static LoggerContext ctx;
+
+    @BeforeClass
+    public static void setupClass() {
+        System.setProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
+        ctx = (LoggerContext) LogManager.getContext(false);
+        config = ctx.getConfiguration();
+        for (final Map.Entry<String, Appender<?>> entry : config.getAppenders().entrySet()) {
+            if (entry.getKey().equals("List")) {
+                app = (ListAppender) entry.getValue();
+                break;
+            }
+        }
+    }
+
+    @AfterClass
+    public static void cleanupClass() {
+        System.clearProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
+        ctx.reconfigure();
+        StatusLogger.getLogger().reset();
+    }
+
+    @After
+    public void after() {
+        app.clear();
+    }
+    
+    @Test
+    public void testNoLocation() throws Exception {
+        final Logger logger = LogManager.getLogger(AsynchAppender.class);
+        logger.error("This is a test");
+        logger.warn("Hello world!");
+        Thread.sleep(100);
+        final List<String> list = app.getMessages();
+        assertNotNull("No events generated", list);
+        assertTrue("Incorrect number of events. Expected 2, got " + list.size(), list.size() == 2);
+        String msg = list.get(0);
+        String expected = "?  This is a test";
+        assertTrue("Expected " + expected + ", Actual " + msg, expected.equals(msg));
+        msg = list.get(1);
+        expected = "?  Hello world!";
+        assertTrue("Expected " + expected + ", Actual " + msg, expected.equals(msg));
+    }
+}

Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/DateLookupTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/DateLookupTest.java?rev=1463078&r1=1463077&r2=1463078&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/DateLookupTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/DateLookupTest.java Mon Apr  1 03:51:21 2013
@@ -94,5 +94,19 @@ public class DateLookupTest {
         public String getFQCN() {
             return null;
         }
+
+        public boolean isEndOfBatch() {
+            return false;
+        }
+
+        public void setEndOfBatch(boolean endOfBatch) {
+        }
+
+        public boolean isIncludeLocation() {
+            return false;
+        }
+
+        public void setIncludeLocation(boolean locationRequired) {
+        }
     }
 }

Added: logging/log4j/log4j2/trunk/core/src/test/resources/log4j-asynch-no-location.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j-asynch-no-location.xml?rev=1463078&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j-asynch-no-location.xml (added)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j-asynch-no-location.xml Mon Apr  1 03:51:21 2013
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<configuration status="error" name="RoutingTest" packages="org.apache.logging.log4j.test">
+
+  <appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m%n"/>
+    </Console>
+    <List name="List">
+      <PatternLayout pattern="%C %M %m"/>
+    </List>
+    <Asynch name="Asynch"> <!-- includeLocation="false" the default for async -->
+      <appender-ref ref="List"/>
+    </Asynch>
+  </appenders>
+
+  <loggers>
+    <root level="debug">
+      <appender-ref ref="Asynch"/>
+    </root>
+  </loggers>
+
+</configuration>
\ No newline at end of file

Modified: logging/log4j/log4j2/trunk/core/src/test/resources/log4j-asynch.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j-asynch.xml?rev=1463078&r1=1463077&r2=1463078&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j-asynch.xml (original)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j-asynch.xml Mon Apr  1 03:51:21 2013
@@ -25,7 +25,7 @@
     <List name="List">
       <PatternLayout pattern="%C %M %m"/>
     </List>
-    <Asynch name="Asynch">
+    <Asynch name="Asynch" includeLocation="true">
       <appender-ref ref="List"/>
     </Asynch>
   </appenders>

Modified: logging/log4j/log4j2/trunk/flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java?rev=1463078&r1=1463077&r2=1463078&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java (original)
+++ logging/log4j/log4j2/trunk/flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java Mon Apr  1 03:51:21 2013
@@ -277,4 +277,24 @@ public class FlumeEvent extends SimpleEv
     public ThreadContext.ContextStack getContextStack() {
         return event.getContextStack();
     }
+
+    @Override
+    public boolean isIncludeLocation() {
+        return event.isIncludeLocation();
+    }
+
+    @Override
+    public void setIncludeLocation(boolean includeLocation) {
+        event.setIncludeLocation(includeLocation);
+    }
+
+    @Override
+    public boolean isEndOfBatch() {
+        return event.isEndOfBatch();
+    }
+
+    @Override
+    public void setEndOfBatch(boolean endOfBatch) {
+        event.setEndOfBatch(endOfBatch);
+    }
 }

Added: logging/log4j/log4j2/trunk/log4j-async/pom.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-async/pom.xml?rev=1463078&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-async/pom.xml (added)
+++ logging/log4j/log4j2/trunk/log4j-async/pom.xml Mon Apr  1 03:51:21 2013
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>log4j</artifactId>
+    <groupId>org.apache.logging.log4j</groupId>
+    <version>2.0-beta5-SNAPSHOT</version>
+    <relativePath>../</relativePath>
+  </parent>
+
+  <groupId>org.apache.logging.log4j</groupId>
+  <artifactId>log4j-async</artifactId>
+  <packaging>jar</packaging>
+  <name>Apache Log4j Async</name>
+  <description>Log4j 2.0 Asynchronous Loggers for Low Latency Logging</description>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <log4jParentDir>${basedir}/..</log4jParentDir>
+    <docLabel>Asynchronous Logging Documentation</docLabel>
+    <projectDir>/log4j-async</projectDir>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.lmax</groupId>
+      <artifactId>disruptor</artifactId>
+      <version>3.0.0.beta3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j.adapters</groupId>
+      <artifactId>log4j-1.2-api</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>test-jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <forkMode>always</forkMode>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <version>1.2.1</version>
+        <executions>
+          <execution>
+            <phase>process-classes</phase>
+            <goals>
+              <goal>java</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <mainClass>org.apache.logging.log4j.core.config.plugins.PluginManager</mainClass>
+          <arguments>
+            <argument>${project.build.outputDirectory}</argument>
+            <argument>org.apache.logging.log4j.async</argument>
+          </arguments>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+      <reporting>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-changes-plugin</artifactId>
+            <version>${changes.plugin.version}</version>
+            <reportSets>
+              <reportSet>
+                <reports>
+                  <report>changes-report</report>
+                </reports>
+              </reportSet>
+            </reportSets>
+            <configuration>
+              <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
+              <useJql>true</useJql>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-checkstyle-plugin</artifactId>
+            <version>2.7</version>
+            <configuration>
+              <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation> -->
+              <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
+              <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
+              <enableRulesSummary>false</enableRulesSummary>
+              <propertyExpansion>basedir=${basedir}</propertyExpansion>
+              <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <version>${javadoc.plugin.version}</version>
+            <configuration>
+              <bottom>Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved. Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, and the
+                Apache Logging project logo are trademarks of The Apache Software Foundation.</bottom>
+              <!-- module link generation is completely broken in the javadoc plugin for a multi-module non-aggregating
+                   project -->
+              <detectOfflineLinks>false</detectOfflineLinks>
+              <linksource>true</linksource>
+              <tags>
+                <tag>
+                  <name>issue</name>
+                  <placement>a</placement>
+                  <head>JIRA issue:</head>
+                </tag>
+                <tag>
+                  <name>doubt</name>
+                  <placement>a</placement>
+                  <head>Troublesome:</head>
+                </tag>
+                <tag>
+                  <name>compare</name>
+                  <placement>a</placement>
+                  <head>Compare with:</head>
+                </tag>
+              </tags>
+            </configuration>
+            <reportSets>
+              <reportSet>
+                <id>non-aggregate</id>
+                <reports>
+                  <report>javadoc</report>
+                </reports>
+              </reportSet>
+            </reportSets>
+          </plugin>
+          <!--
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>findbugs-maven-plugin</artifactId>
+            <version>2.3.2</version>
+            <configuration>
+              <threshold>Normal</threshold>
+              <effort>Default</effort>
+              <excludeFilterFile>findbugs-exclude-filter.xml</excludeFilterFile>
+            </configuration>
+          </plugin>
+          -->
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-jxr-plugin</artifactId>
+            <version>2.3</version>
+            <reportSets>
+              <reportSet>
+                <id>non-aggregate</id>
+                <reports>
+                  <report>jxr</report>
+                </reports>
+              </reportSet>
+              <reportSet>
+                <id>aggregate</id>
+                <reports>
+                  <report>aggregate</report>
+                </reports>
+              </reportSet>
+            </reportSets>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-pmd-plugin</artifactId>
+            <version>${pmd.plugin.version}</version>
+            <configuration>
+              <targetJdk>1.5</targetJdk>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>cobertura-maven-plugin</artifactId>
+            <version>2.2</version>
+            <reportSets>
+              <reportSet>
+                <!-- Disabled at it kills the site generation via a NoClassDefFoundError -->
+                <reports />
+              </reportSet>
+            </reportSets>
+          </plugin>
+        </plugins>
+      </reporting>
+
+</project>
\ No newline at end of file

Added: logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLogger.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLogger.java?rev=1463078&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLogger.java (added)
+++ logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLogger.java Mon Apr  1 03:51:21 2013
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.async;
+
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import com.lmax.disruptor.BlockingWaitStrategy;
+import com.lmax.disruptor.EventHandler;
+import com.lmax.disruptor.ExceptionHandler;
+import com.lmax.disruptor.RingBuffer;
+import com.lmax.disruptor.SleepingWaitStrategy;
+import com.lmax.disruptor.WaitStrategy;
+import com.lmax.disruptor.YieldingWaitStrategy;
+import com.lmax.disruptor.dsl.Disruptor;
+import com.lmax.disruptor.dsl.ProducerType;
+import com.lmax.disruptor.util.Util;
+
+/**
+ * AsyncLogger is a logger designed for high throughput and low latency logging.
+ * It does not perform any I/O in the calling (application) thread, but instead
+ * hands off the work to another thread as soon as possible. The actual logging
+ * is performed in the background thread. It uses the LMAX Disruptor library for
+ * inter-thread communication. (<a
+ * href="http://lmax-exchange.github.com/disruptor/"
+ * >http://lmax-exchange.github.com/disruptor/</a>)
+ * <p>
+ * To use AsyncLogger, specify the System property
+ * -DLog4jContextSelector=log4j.async.AsyncLoggerContextSelector before you
+ * obtain a Logger, and all Loggers returned by LogManager.getLogger will be
+ * AsyncLoggers.
+ * <p>
+ * Note that for performance reasons, this logger does not support source
+ * location. Any %class, %location or %line conversion patterns in your
+ * log4j.xml configuration will produce either a "?" character or no output at
+ * all.
+ * <p>
+ * For best performance, use AsyncLogger with the FastFileAppender or
+ * FastRollingFileAppender, with immediateFlush=false. These appenders have
+ * built-in support for the batching mechanism used by the Disruptor library,
+ * and they will flush to disk at the end of each batch. This means that even
+ * with immediateFlush=false, there will never be any items left in the buffer;
+ * all log events will all be written to disk in a very efficient manner.
+ */
+public class AsyncLogger extends Logger { // depends on LOG4J2-151
+    private static final StatusLogger LOGGER = StatusLogger.getLogger();
+    private static volatile Disruptor<RingBufferLogEvent> disruptor;
+    private static Clock clock = ClockFactory.getClock();
+
+    private static ExecutorService executor = Executors
+            .newSingleThreadExecutor();
+    private ThreadLocal<Info> threadlocalInfo = new ThreadLocal<Info>();
+
+    static {
+        int ringBufferSize = calculateRingBufferSize();
+
+        WaitStrategy waitStrategy = createWaitStrategy();
+        disruptor = new Disruptor<RingBufferLogEvent>(
+                RingBufferLogEvent.FACTORY, ringBufferSize, executor,
+                ProducerType.MULTI, waitStrategy);
+        EventHandler<RingBufferLogEvent>[] handlers = new RingBufferLogEventHandler[] { new RingBufferLogEventHandler() };
+        disruptor.handleExceptionsWith(getExceptionHandler());
+        disruptor.handleEventsWith(handlers);
+
+        LOGGER.debug(
+                "Starting AsyncLogger disruptor with ringbuffer size {}...",
+                disruptor.getRingBuffer().getBufferSize());
+        disruptor.start();
+    }
+
+    private static int calculateRingBufferSize() {
+        String userPreferredRBSize = System.getProperty(
+                "AsyncLogger.RingBufferSize", "256000");
+        int ringBufferSize = 256000; // default
+        try {
+            int size = Integer.parseInt(userPreferredRBSize);
+            if (size < 128) {
+                size = 128;
+                LOGGER.warn(
+                        "Invalid RingBufferSize {}, using minimum size 128.",
+                        userPreferredRBSize);
+            }
+            ringBufferSize = size;
+        } catch (Exception ex) {
+            LOGGER.warn("Invalid RingBufferSize {}, using default size.",
+                    userPreferredRBSize);
+        }
+        return Util.ceilingNextPowerOfTwo(ringBufferSize);
+    }
+
+    private static WaitStrategy createWaitStrategy() {
+        String strategy = System.getProperty("AsyncLogger.WaitStrategy");
+        LOGGER.debug("property AsyncLogger.WaitStrategy={}", strategy);
+        if ("Sleep".equals(strategy)) {
+            LOGGER.debug("disruptor event handler uses SleepingWaitStrategy");
+            return new SleepingWaitStrategy();
+        } else if ("Yield".equals(strategy)) {
+            LOGGER.debug("disruptor event handler uses YieldingWaitStrategy");
+            return new YieldingWaitStrategy();
+        } else if ("Block".equals(strategy)) {
+            LOGGER.debug("disruptor event handler uses BlockingWaitStrategy");
+            return new BlockingWaitStrategy();
+        }
+        LOGGER.debug("disruptor event handler uses SleepingWaitStrategy");
+        return new SleepingWaitStrategy();
+    }
+
+    private static ExceptionHandler getExceptionHandler() {
+        String cls = System.getProperty("AsyncLogger.ExceptionHandler");
+        if (cls == null) {
+            LOGGER.debug("No AsyncLogger.ExceptionHandler specified");
+            return null;
+        }
+        try {
+            @SuppressWarnings("unchecked")
+            Class<? extends ExceptionHandler> klass = (Class<? extends ExceptionHandler>) Class
+                    .forName(cls);
+            ExceptionHandler result = klass.newInstance();
+            LOGGER.debug("AsyncLogger.ExceptionHandler=" + result);
+            return result;
+        } catch (Exception ignored) {
+            LOGGER.debug(
+                    "AsyncLogger.ExceptionHandler not set: error creating "
+                            + cls + ": ", ignored);
+            return null;
+        }
+    }
+
+    private static class Info {
+        RingBufferLogEventTranslator translator;
+        String cachedThreadName;
+    }
+
+    public AsyncLogger(LoggerContext context, String name,
+            MessageFactory messageFactory) {
+        super(context, name, messageFactory);
+    }
+
+    @Override
+    public void log(Marker marker, String fqcn, Level level, Message data,
+            Throwable t) {
+        Info info = threadlocalInfo.get();
+        if (info == null) {
+            info = new Info();
+            info.translator = new RingBufferLogEventTranslator();
+            info.cachedThreadName = Thread.currentThread().getName();
+            threadlocalInfo.set(info);
+        }
+
+        Boolean includeLocation = config.loggerConfig.isIncludeLocation();
+        info.translator.setValues(this, getName(), marker, fqcn, level, data,
+                t, //
+
+                // config properties are taken care of in the EventHandler
+                // thread in the #actualAsyncLog method
+
+                // needs shallow copy to be fast (LOG4J2-154)
+                ThreadContext.getImmutableContext(),//
+
+                // needs shallow copy to be fast (LOG4J2-154)
+                ThreadContext.getImmutableStack(), //
+
+                // Thread.currentThread().getName(), //
+                info.cachedThreadName, //
+
+                // location: very expensive operation. LOG4J2-153:
+                // Only include if "includeLocation=true" is specified,
+                // exclude if not specified or if "false" was specified.
+                includeLocation != null && includeLocation ? location(fqcn)
+                        : null,
+
+                // System.currentTimeMillis());
+                // CoarseCachedClock: 20% faster than system clock, 16ms gaps
+                // CachedClock: 10% faster than system clock, smaller gaps
+                clock.currentTimeMillis());
+
+        disruptor.publishEvent(info.translator);
+    }
+
+    private StackTraceElement location(String fqcnOfLogger) {
+        return Log4jLogEvent.calcLocation(fqcnOfLogger);
+    }
+
+    /**
+     * This method is called by the EventHandler that processes the
+     * RingBufferLogEvent in a separate thread.
+     * 
+     * @param event the event to log
+     */
+    public void actualAsyncLog(RingBufferLogEvent event) {
+        Map<Property, Boolean> properties = config.loggerConfig.getProperties();
+        event.mergePropertiesIntoContextMap(properties,
+                config.config.getSubst());
+        config.logEvent(event);
+    }
+
+    public static void stop() {
+        Disruptor<RingBufferLogEvent> temp = disruptor;
+
+        // Must guarantee that publishing to the RingBuffer has stopped
+        // before we call disruptor.shutdown()
+        disruptor = null; // client code fails with NPE if log after stop = OK
+        temp.shutdown();
+
+        // wait up to 10 seconds for the ringbuffer to drain
+        RingBuffer<RingBufferLogEvent> ringBuffer = temp.getRingBuffer();
+        for (int i = 0; i < 20; i++) {
+            if (ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize())) {
+                break;
+            }
+            try {
+                Thread.sleep(500); // give ringbuffer some time to drain...
+            } catch (InterruptedException e) {
+            }
+        }
+        executor.shutdown(); // finally, kill the processor thread
+    }
+
+}

Added: logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLoggerContext.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLoggerContext.java?rev=1463078&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLoggerContext.java (added)
+++ logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLoggerContext.java Mon Apr  1 03:51:21 2013
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.async;
+
+import java.net.URI;
+
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.message.MessageFactory;
+
+// depends on  LOG4J2-151
+public class AsyncLoggerContext extends LoggerContext {
+
+    public AsyncLoggerContext(String name) {
+        super(name);
+    }
+
+    public AsyncLoggerContext(String name, Object externalContext) {
+        super(name, externalContext);
+    }
+
+    public AsyncLoggerContext(String name, Object externalContext,
+            URI configLocn) {
+        super(name, externalContext, configLocn);
+    }
+
+    public AsyncLoggerContext(String name, Object externalContext,
+            String configLocn) {
+        super(name, externalContext, configLocn);
+    }
+
+    // @Override
+    protected Logger newInstance(LoggerContext ctx, String name,
+            MessageFactory messageFactory) {
+        return new AsyncLogger(ctx, name, messageFactory);
+    }
+
+    @Override
+    public void stop() {
+        AsyncLogger.stop();
+        super.stop();
+    }
+}

Added: logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLoggerContextSelector.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLoggerContextSelector.java?rev=1463078&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLoggerContextSelector.java (added)
+++ logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/AsyncLoggerContextSelector.java Mon Apr  1 03:51:21 2013
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.async;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.selector.ContextSelector;
+
+public class AsyncLoggerContextSelector implements ContextSelector {
+
+    private static final AsyncLoggerContext context = new AsyncLoggerContext(
+            "Default");
+
+    public LoggerContext getContext(String fqcn, ClassLoader loader,
+            boolean currentContext) {
+        return context;
+    }
+
+    public List<LoggerContext> getLoggerContexts() {
+        List<LoggerContext> list = new ArrayList<LoggerContext>();
+        list.add(context);
+        return Collections.unmodifiableList(list);
+    }
+
+    public LoggerContext getContext(String fqcn, ClassLoader loader,
+            boolean currentContext, URI configLocation) {
+        return context;
+    }
+
+}

Added: logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/CachedClock.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/CachedClock.java?rev=1463078&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/CachedClock.java (added)
+++ logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/CachedClock.java Mon Apr  1 03:51:21 2013
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.async;
+
+import com.lmax.disruptor.util.Util;
+
+
+public class CachedClock implements Clock {
+    private static CachedClock instance = new CachedClock();
+    private volatile long millis = System.currentTimeMillis();
+    private volatile short count = 0;
+    private final Thread updater = new Thread("Clock Updater Thread") {
+        public void run() {
+            while (true) {
+                long time = System.currentTimeMillis();
+                millis = time;
+                Util.getUnsafe().park(true, time + 1); // abs (millis)
+                // Util.getUnsafe().park(false, 1000 * 1000);// relative(nanos)
+            }
+        }
+    };
+
+    public static CachedClock instance() {
+        return instance;
+    }
+
+    private CachedClock() {
+        updater.setDaemon(true);
+        updater.start();
+    }
+
+    // @Override
+    public long currentTimeMillis() {
+
+        // improve granularity: also update time field every 1024 calls.
+        // (the bit fiddling means we don't need to worry about overflows)
+        if ((++count & 0x3FF) == 0x3FF) {
+            millis = System.currentTimeMillis();
+        }
+        return millis;
+    }
+}

Added: logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/Clock.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/Clock.java?rev=1463078&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/Clock.java (added)
+++ logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/Clock.java Mon Apr  1 03:51:21 2013
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.async;
+
+public interface Clock {
+    long currentTimeMillis();
+}

Added: logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/ClockFactory.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/ClockFactory.java?rev=1463078&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/ClockFactory.java (added)
+++ logging/log4j/log4j2/trunk/log4j-async/src/main/java/org/apache/logging/log4j/async/ClockFactory.java Mon Apr  1 03:51:21 2013
@@ -0,0 +1,41 @@
+package org.apache.logging.log4j.async;
+
+import org.apache.logging.log4j.status.StatusLogger;
+
+public class ClockFactory {
+
+    public static final String PROPERTY_NAME = "AsyncLogger.Clock";
+    //private static final Clock clock = createClock();
+
+    public static Clock getClock() {
+        return createClock();
+    }
+
+    private static Clock createClock() {
+        final StatusLogger LOGGER = StatusLogger.getLogger();
+        String userRequest = System.getProperty(PROPERTY_NAME);
+        if (userRequest == null || "SystemClock".equals(userRequest)) {
+            LOGGER.debug("Using default SystemClock for timestamps");
+            return new SystemClock();
+        }
+        if ("org.apache.logging.log4j.async.CachedClock".equals(userRequest)
+                || "CachedClock".equals(userRequest)) {
+            LOGGER.debug("Using specified CachedClock for timestamps");
+            return CachedClock.instance();
+        }
+        if ("org.apache.logging.log4j.async.CoarseCachedClock"
+                .equals(userRequest) || "CoarseCachedClock".equals(userRequest)) {
+            LOGGER.debug("Using specified CoarseCachedClock for timestamps");
+            return CoarseCachedClock.instance();
+        }
+        try {
+            Clock result = (Clock) Class.forName(userRequest).newInstance();
+            LOGGER.debug("Using {} for timestamps", userRequest);
+            return result;
+        } catch (Exception e) {
+            String fmt = "Could not create {}: {}, using default SystemClock for timestamps";
+            LOGGER.error(fmt, userRequest, e);
+            return new SystemClock();
+        }
+    }
+}