logging-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rpo...@apache.org
Subject svn commit: r1555468 - in /logging/log4j/log4j2/trunk: log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java src/changes/changes.xml
Date Sun, 05 Jan 2014 08:10:06 GMT
Author: rpopma
Date: Sun Jan  5 08:10:05 2014
New Revision: 1555468

URL: http://svn.apache.org/r1555468
Log:
LOG4J2-485: Fixed issue where toString methods that perform logging could deadlock AsyncAppender

Modified:
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
    logging/log4j/log4j2/trunk/src/changes/changes.xml

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java?rev=1555468&r1=1555467&r2=1555468&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
(original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
Sun Jan  5 08:10:05 2014
@@ -62,6 +62,7 @@ public final class AsyncAppender extends
     private AppenderControl errorAppender;
     private AsyncThread thread;
     private static final AtomicLong threadSequence = new AtomicLong(1);
+    private static ThreadLocal<Boolean> isAppenderThread = new ThreadLocal<Boolean>();
 
 
     private AsyncAppender(final String name, final Filter filter, final AppenderRef[] appenderRefs,
@@ -122,34 +123,43 @@ public final class AsyncAppender extends
     /**
      * Actual writing occurs here.
      * <p/>
-     * @param event The LogEvent.
+     * @param evt The LogEvent.
      */
     @Override
-    public void append(final LogEvent event) {
+    public void append(final LogEvent evt) {
         if (!isStarted()) {
             throw new IllegalStateException("AsyncAppender " + getName() + " is not active");
         }
-        if (event instanceof Log4jLogEvent) {
-            boolean appendSuccessful = false;
-            if (blocking) {
+        if (!(evt instanceof Log4jLogEvent)) {
+            return; // only know how to Serialize Log4jLogEvents
+        }
+        Log4jLogEvent event = (Log4jLogEvent) evt;
+        boolean appendSuccessful = false;
+        if (blocking) {
+            if (isAppenderThread.get() == Boolean.TRUE && queue.remainingCapacity()
== 0) {
+                // LOG4J2-485: avoid deadlock that would result from trying
+                // to add to a full queue from appender thread
+                event.setEndOfBatch(false); // queue is definitely not empty!
+                appendSuccessful = thread.callAppenders(event);
+            } else {
                 try {
                     // wait for free slots in the queue
-                    queue.put(Log4jLogEvent.serialize((Log4jLogEvent) event, includeLocation));
+                    queue.put(Log4jLogEvent.serialize(event, includeLocation));
                     appendSuccessful = true;
                 } catch (final InterruptedException e) {
                     LOGGER.warn("Interrupted while waiting for a free slot in the AsyncAppender
LogEvent-queue {}",
                             getName());
                 }
-            } else {
-                appendSuccessful = queue.offer(Log4jLogEvent.serialize((Log4jLogEvent) event,
includeLocation));
-                if (!appendSuccessful) {
-                    error("Appender " + getName() + " is unable to write primary appenders.
queue is full");
-                }
             }
-            if ((!appendSuccessful) && (errorAppender != null)) {
-                errorAppender.callAppender(event);
+        } else {
+            appendSuccessful = queue.offer(Log4jLogEvent.serialize(event, includeLocation));
+            if (!appendSuccessful) {
+                error("Appender " + getName() + " is unable to write primary appenders. queue
is full");
             }
         }
+        if ((!appendSuccessful) && (errorAppender != null)) {
+            errorAppender.callAppender(event);
+        }
     }
 
     /**
@@ -211,6 +221,7 @@ public final class AsyncAppender extends
 
         @Override
         public void run() {
+            isAppenderThread.set(Boolean.TRUE); // LOG4J2-485
             while (!shutdown) {
                 Serializable s;
                 try {
@@ -225,15 +236,7 @@ public final class AsyncAppender extends
                 }
                 final Log4jLogEvent event = Log4jLogEvent.deserialize(s);
                 event.setEndOfBatch(queue.isEmpty());
-                boolean success = false;
-                for (final AppenderControl control : appenders) {
-                    try {
-                        control.callAppender(event);
-                        success = true;
-                    } catch (final Exception ex) {
-                        // If no appender is successful the error appender will get it.
-                    }
-                }
+                boolean success = callAppenders(event);
                 if (!success && errorAppender != null) {
                     try {
                         errorAppender.callAppender(event);
@@ -249,9 +252,7 @@ public final class AsyncAppender extends
                     if (s instanceof Log4jLogEvent) {
                         final Log4jLogEvent event = Log4jLogEvent.deserialize(s);
                         event.setEndOfBatch(queue.isEmpty());
-                        for (final AppenderControl control : appenders) {
-                            control.callAppender(event);
-                        }
+                        callAppenders(event);
                     }
                 } catch (final InterruptedException ex) {
                     // May have been interrupted to shut down.
@@ -259,6 +260,28 @@ public final class AsyncAppender extends
             }
         }
 
+        /**
+         * Calls {@link AppenderControl#callAppender(LogEvent) callAppender} on
+         * all registered {@code AppenderControl} objects, and returns {@code true}
+         * if at least one appender call was successful, {@code false} otherwise.
+         * Any exceptions are silently ignored.
+         * 
+         * @param event the event to forward to the registered appenders
+         * @return {@code true} if at least one appender call succeeded, {@code false} otherwise
+         */
+        boolean callAppenders(final Log4jLogEvent event) {
+            boolean success = false;
+            for (final AppenderControl control : appenders) {
+                try {
+                    control.callAppender(event);
+                    success = true;
+                } catch (final Exception ex) {
+                    // If no appender is successful the error appender will get it.
+                }
+            }
+            return success;
+        }
+
         public void shutdown() {
             shutdown = true;
             if (queue.isEmpty()) {

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1555468&r1=1555467&r2=1555468&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Sun Jan  5 08:10:05 2014
@@ -21,6 +21,9 @@
   </properties>
   <body>
     <release version="2.0-RC1" date="2013-MM-DD" description="Bug fixes and enhancements">
+      <action issue="LOG4J2-485" dev="rpopma" type="fix">
+        Fixed issue where toString methods that perform logging could deadlock AsyncAppender.
+      </action>
       <action issue="LOG4J2-445" dev="rpopma" type="fix" due-to="Anthony Baldocchi">
         ResolverUtil cannot find packages in file URLs which include the '+' character.
       </action>



Mime
View raw message