Uploaded image for project: 'Log4j 2'
  1. Log4j 2
  2. LOG4J2-1049

AsyncAppender eats my Interrupt

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Major
    • Resolution: Fixed
    • 2.2, 2.3
    • 2.4
    • Appenders
    • Java 7, Windows

    • Patch

    Description

      I wrote a LoggingThread that will be stopped by sending loggingThread.interrupt() from another Thread.

      LoggingThread.java
      class LoggingThread extends Thread {
        private final static Logger LOGGER = LoggerFactory.getLogger(LoggingThread .class);
        public void run() {
          while (!Thread.currentThread().isInterrupted()) {
            LOGGER.debug("{} is logging {}", this, "nothing");
          }
        }
      }
      

      Unfortunately, loggingThread.interrupt() is sometimes set before AsyncAppender.append() or at the beginning of that.

      AsyncAppender#append() line 153
      try {
        // wait for free slots in the queue
        queue.put(Log4jLogEvent.serialize(coreEvent, includeLocation));
        appendSuccessful = true;
      } catch (final InterruptedException e) {
        LOGGER.warn("Interrupted while waiting for a free slot in the AsyncAppender LogEvent-queue {}",
        getName());
      }
      

      This will make queue.put throw an InterruptedException and remove the interrupted flag of the current flag.

      I suggest a simple bugfix: Call Thread by Thread.currentThread().interrupt() in the catch clause. This will reset the interrupted flag of the current Thread.

      A more complex bugfix which doesn't loose a message:

      AsyncAppender#append() line 153
      Serializable serialized = Log4jLogEvent.serialize(coreEvent, includeLocation);
      try {
        // wait for free slots in the queue
        queue.put(serialized);
        appendSuccessful = true;
      } catch (final InterruptedException e) {
        try {
          // The interrupt is catched and the interrupted flag is unset.
          // Therefore offer() won't return with an InterruptedException
          // unless another Thread sends again an interrupt.
          // Use a timeout to handle the case where the Interrupt e
          // was really meant for a hanging put() and not just 
          // coincidently sent at the same time.
          // If the put() was really hanging,
          // offer() would return with false after 10ms and no second
          // external interrupt() is required
          appendSuccessful = queue.offer(serialized, 10L, TimeUnit.MILLISECONDS);
        } catch (final InterruptedException e2) {
          // queue.put is really hanging and someone 
        }
        if (!appendSuccessful) {
          LOGGER.warn("Interrupted while waiting for a free slot in the AsyncAppender LogEvent-queue {}",
          getName());
        }
        // set the interrupted flag again.
        Thread.currentThread().interrupt();
      }
      

      Attachments

        Activity

          People

            rpopma Remko Popma
            robert.schaft Robert Schaft
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Time Tracking

                Estimated:
                Original Estimate - 48h
                48h
                Remaining:
                Remaining Estimate - 48h
                48h
                Logged:
                Time Spent - Not Specified
                Not Specified