LOG4J2-493 removed obsolete counter, improved status logging

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/25fe68d2
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/25fe68d2
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/25fe68d2

Branch: refs/heads/LOG4J2-1161
Commit: 25fe68d2de481d66b4dd26ac67ecdb6f2f72e4d7
Parents: 6e45177
Author: rpopma <rpo...@apache.org>
Authored: Fri Oct 23 02:15:08 2015 +0900
Committer: rpopma <rpo...@apache.org>
Committed: Fri Oct 23 02:15:08 2015 +0900

----------------------------------------------------------------------
 .../log4j/core/async/AsyncLoggerHelper.java     | 78 +++++++++-----------
 1 file changed, 35 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/25fe68d2/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerHelper.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerHelper.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerHelper.java
index 33a34e1..027fa0d 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerHelper.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerHelper.java
@@ -36,16 +36,10 @@ import com.lmax.disruptor.dsl.Disruptor;
 import com.lmax.disruptor.dsl.ProducerType;
 
 /**
- * Helper class for AsyncLogger:
- * <ul>
- * <li>Separates the AsyncLogger business logic (logging) from the mechanics 
of working with the LMAX Disruptor.</li>
- * <li>Disruptor initialization no longer happens in a initializer block in 
AsyncLogger to prevent problems where
- * the Disruptor is unintentionally initialized (and a thread started) because 
a method in AsyncLogger is called
- * (LOG4J2-1159).</li>
- * <li>Enable a reference counting scheme tracking the total number of starts 
and stops, so the Disruptor and associated
- * Executor can be shut down when usage becomes zero. This fixes a 
long-standing issue that made AsyncLoggers unsuitable
- * for use in web applications (LOG4J2-493).</li>
- * </ul>
+ * Helper class for async loggers: AsyncLoggerHelper handles the mechanics of 
working with the LMAX Disruptor, and
+ * works with its associated AsyncLoggerContext to synchronize the life cycle 
of the Disruptor and its thread with the
+ * life cycle of the context. The AsyncLoggerHelper of the context is shared 
by all AsyncLogger objects created by that
+ * AsyncLoggerContext.
  */
 public class AsyncLoggerHelper {
     private static final int SLEEP_MILLIS_BETWEEN_DRAIN_ATTEMPTS = 50;
@@ -54,34 +48,36 @@ public class AsyncLoggerHelper {
     private static final int RINGBUFFER_DEFAULT_SIZE = 256 * 1024;
     private static final StatusLogger LOGGER = StatusLogger.getLogger();
 
+    private final String contextName;
     private ExecutorService executor;
     private volatile Disruptor<RingBufferLogEvent> disruptor;
-    private volatile int count = 0;
+
+    public AsyncLoggerHelper(String contextName) {
+        this.contextName = contextName;
+    }
+
+    public String getContextName() {
+        return contextName;
+    }
 
     Disruptor<RingBufferLogEvent> getDisruptor() {
         return disruptor;
     }
 
     /**
-     * Increases the reference count and creates and starts a new Disruptor 
and associated thread if none currently
-     * exists.
+     * Creates and starts a new Disruptor and associated thread if none 
currently exists.
      * 
-     * @see #release()
+     * @see #stop()
      */
     synchronized void start() {
-        count++;
-        initDisruptor();
-    }
-
-    private synchronized void initDisruptor() {
         if (disruptor != null) {
-            LOGGER.trace("AsyncLoggerHelper not starting new disruptor, using 
existing object. Ref count is {}.", count);
+            LOGGER.trace("[{}] AsyncLoggerHelper not starting new disruptor, 
using existing object.", contextName);
             return;
         }
-        LOGGER.trace("AsyncLoggerHelper creating new disruptor. Ref count is 
{}.", count);
+        LOGGER.trace("[{}] AsyncLoggerHelper creating new disruptor.", 
contextName);
         final int ringBufferSize = calculateRingBufferSize();
         final WaitStrategy waitStrategy = createWaitStrategy();
-        executor = Executors.newSingleThreadExecutor(new 
DaemonThreadFactory("AsyncLogger-"));
+        executor = Executors.newSingleThreadExecutor(new 
DaemonThreadFactory(contextName + "-Logger-"));
         Info.initExecutorThreadInstance(executor);
 
         disruptor = new Disruptor<>(RingBufferLogEvent.FACTORY, 
ringBufferSize, executor, ProducerType.MULTI,
@@ -91,8 +87,8 @@ public class AsyncLoggerHelper {
         final RingBufferLogEventHandler[] handlers = {new 
RingBufferLogEventHandler()};
         disruptor.handleEventsWith(handlers);
 
-        LOGGER.debug("Starting AsyncLogger disruptor with ringbuffer size 
{}...", disruptor.getRingBuffer()
-                .getBufferSize());
+        LOGGER.debug("[{}] Starting AsyncLogger disruptor with ringbuffer size 
{}...", contextName, disruptor
+                .getRingBuffer().getBufferSize());
         disruptor.start();
     }
 
@@ -104,19 +100,20 @@ public class AsyncLoggerHelper {
             int size = Integer.parseInt(userPreferredRBSize);
             if (size < RINGBUFFER_MIN_SIZE) {
                 size = RINGBUFFER_MIN_SIZE;
-                LOGGER.warn("Invalid RingBufferSize {}, using minimum size 
{}.", userPreferredRBSize,
+                LOGGER.warn("[{}] Invalid RingBufferSize {}, using minimum 
size {}.", contextName, userPreferredRBSize,
                         RINGBUFFER_MIN_SIZE);
             }
             ringBufferSize = size;
         } catch (final Exception ex) {
-            LOGGER.warn("Invalid RingBufferSize {}, using default size {}.", 
userPreferredRBSize, ringBufferSize);
+            LOGGER.warn("[{}] Invalid RingBufferSize {}, using default size 
{}.", contextName, userPreferredRBSize,
+                    ringBufferSize);
         }
         return Integers.ceilingNextPowerOfTwo(ringBufferSize);
     }
 
     private WaitStrategy createWaitStrategy() {
         final String strategy = 
PropertiesUtil.getProperties().getStringProperty("AsyncLogger.WaitStrategy");
-        LOGGER.debug("property AsyncLogger.WaitStrategy={}", strategy);
+        LOGGER.debug("[{}] property AsyncLogger.WaitStrategy={}", contextName, 
strategy);
         if ("Sleep".equals(strategy)) {
             return new SleepingWaitStrategy();
         } else if ("Yield".equals(strategy)) {
@@ -124,24 +121,25 @@ public class AsyncLoggerHelper {
         } else if ("Block".equals(strategy)) {
             return new BlockingWaitStrategy();
         }
-        LOGGER.debug("disruptor event handler uses BlockingWaitStrategy");
+        LOGGER.debug("[{}] disruptor event handler uses BlockingWaitStrategy", 
contextName);
         return new BlockingWaitStrategy();
     }
 
     private ExceptionHandler<RingBufferLogEvent> getExceptionHandler() {
         final String cls = 
PropertiesUtil.getProperties().getStringProperty("AsyncLogger.ExceptionHandler");
         if (cls == null) {
-            LOGGER.debug("No AsyncLogger.ExceptionHandler specified");
+            LOGGER.debug("[{}] No AsyncLogger.ExceptionHandler specified", 
contextName);
             return null;
         }
         try {
             @SuppressWarnings("unchecked")
             final ExceptionHandler<RingBufferLogEvent> result = Loader
                     .newCheckedInstanceOf(cls, ExceptionHandler.class);
-            LOGGER.debug("AsyncLogger.ExceptionHandler={}", result);
+            LOGGER.debug("[{}] AsyncLogger.ExceptionHandler={}", contextName, 
result);
             return result;
         } catch (final Exception ignored) {
-            LOGGER.debug("AsyncLogger.ExceptionHandler not set: error creating 
" + cls + ": ", ignored);
+            LOGGER.debug("[{}] AsyncLogger.ExceptionHandler not set: error 
creating " + cls + ": ", contextName,
+                    ignored);
             return null;
         }
     }
@@ -150,11 +148,11 @@ public class AsyncLoggerHelper {
         // LOG4J2-639: catch NPE if disruptor field was set to null in 
release()
         try {
             // Note: we deliberately access the volatile disruptor field 
afresh here.
-            // Avoiding this and using an older refrence could result in 
adding a log event to the disruptor after it
+            // Avoiding this and using an older reference could result in 
adding a log event to the disruptor after it
             // was shut down, which could cause the publishEvent method to 
hang and never return.
             disruptor.publishEvent(translator);
         } catch (final NullPointerException npe) {
-            LOGGER.fatal("Ignoring log event after log4j was shut down.");
+            LOGGER.fatal("[{}] Ignoring log event after log4j was shut down.", 
contextName);
         }
     }
 
@@ -173,18 +171,12 @@ public class AsyncLoggerHelper {
      * shut down and their references set to {@code null}.
      */
     synchronized void stop() {
-        if (--count > 0) {
-            LOGGER.trace("AsyncLoggerHelper: not shutting down disruptor: ref 
count is {}.", count);
-            return;
-        }
-
         final Disruptor<RingBufferLogEvent> temp = getDisruptor();
         if (temp == null) {
-            LOGGER.trace("AsyncLoggerHelper: disruptor already shut down: ref 
count is {}. (Resetting to zero.)", count);
-            count = 0; // ref count must not be negative or #claim() will not 
work correctly
+            LOGGER.trace("[{}] AsyncLoggerHelper: disruptor already shut 
down.", contextName);
             return; // disruptor was already shut down by another thread
         }
-        LOGGER.debug("AsyncLoggerHelper: shutting down disruptor: ref count is 
{}.", count);
+        LOGGER.debug("[{}] AsyncLoggerHelper: shutting down disruptor.", 
contextName);
 
         // Must guarantee that publishing to the RingBuffer has stopped
         // before we call disruptor.shutdown()
@@ -201,7 +193,7 @@ public class AsyncLoggerHelper {
         }
         temp.shutdown(); // busy-spins until all events currently in the 
disruptor have been processed
 
-        LOGGER.trace("AsyncLoggerHelper: shutting down disruptor executor.");
+        LOGGER.trace("[{}] AsyncLoggerHelper: shutting down disruptor 
executor.", contextName);
         executor.shutdown(); // finally, kill the processor thread
         executor = null;
         // Info.THREADLOCAL.remove(); // LOG4J2-323
@@ -210,7 +202,7 @@ public class AsyncLoggerHelper {
     /**
      * Returns {@code true} if the specified disruptor still has unprocessed 
events.
      */
-    private boolean hasBacklog(final Disruptor<?> theDisruptor) {
+    private static boolean hasBacklog(final Disruptor<?> theDisruptor) {
         final RingBuffer<?> ringBuffer = theDisruptor.getRingBuffer();
         return !ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize());
     }

Reply via email to