Hello,

While logging, we sometimes notice that the entire logging infra comes to a
halt, even though the rest of the application still works perfectly fine. I
have figured, appenders wrapped by AsyncAppender can throw a
java.lang.Throwable that is not a subclass of java.lang.Exception and such
an exception kills the AsyncAppender worker thread. Consider the following
snippet from AsyncAppender.java in 2.x branch:

boolean callAppenders(final LogEvent 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;
}

Further, this is the relevant AppenderControl#tryCallAppender(LogEvent)
method:

private void tryCallAppender(final LogEvent event) {
    try {
        appender.append(event);
    } catch (final RuntimeException ex) {
        handleAppenderError(event, ex);
    } catch (final Exception ex) {
        handleAppenderError(event, new AppenderLoggingException(ex));
    }
}

To avoid AsyncAppender.AsyncThread getting killed, I propose, in
tryCallAppender(), replacing the java.lang.Exception catch clause with
java.lang.Throwable instead. Objections? (If there are none, I will push
this to both master and release-2.x branches with some unit tests.)

To get some inspiration, I have checked the
java.util.concurrent.ThreadPoolExecutor#runWorker() method:

try {
    task.run();
} catch (RuntimeException x) {
    thrown = x; throw x;
} catch (Error x) {
    thrown = x; throw x;
} catch (Throwable x) {
    thrown = x; throw new Error(x);
}

This is inline with the change I propose for tryCallAppender().

For the records, the most frequent Throwable we encounter that is a super
class of Exception is ExceptionInInitializerError, in case you are
interested in.

Kind regards.

Reply via email to