[ 
https://issues.apache.org/jira/browse/LOG4J2-3185?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17443434#comment-17443434
 ] 

ASF subversion and git services commented on LOG4J2-3185:
---------------------------------------------------------

Commit 843ca800ba60464059a22e9e12edcaf5ecd92d95 in logging-log4j2's branch 
refs/heads/release-2.x from Volkan Yazici
[ https://gitbox.apache.org/repos/asf?p=logging-log4j2.git;h=843ca80 ]

LOG4J2-3060 LOG4J2-3185 Fix error-propagation logic in DefaultErrorHandler.


> DefaultErrorHandler can not share values across threads
> -------------------------------------------------------
>
>                 Key: LOG4J2-3185
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-3185
>             Project: Log4j 2
>          Issue Type: Bug
>          Components: Appenders, Core
>    Affects Versions: 2.14.1
>            Reporter: mzbonnt
>            Priority: Critical
>             Fix For: 2.15.0
>
>
> My application used a logger with AsyncAppender and set the blocking 
> attribute to false. The example code as following.
> {code:java}
> // Some example logger usage for catching all throwables and log it to disk 
> file
>     try {
>         // my application code, which may throw an exception 
>     } catch (Throwable t) {
>         logger.error("", t);
>     }
> {code}
> If there was too much throwable generated, then the the blocking queue in the 
> async appender will be full, and will never enqueue any more. Thus, it will 
> execute DefaultErrorHandler#error(String) method.
> {code:java}
>     // org.apache.logging.log4j.core.appender.AsyncAppender
>     @Override
>     public void append(final LogEvent logEvent) {
>         if (!isStarted()) {
>             throw new IllegalStateException("AsyncAppender " + getName() + " 
> is not active");
>         }
>         final Log4jLogEvent memento = Log4jLogEvent.createMemento(logEvent, 
> includeLocation);
>         InternalAsyncUtil.makeMessageImmutable(logEvent.getMessage());
>         if (!transfer(memento)) {
>             if (blocking) {
>                 if (AbstractLogger.getRecursionDepth() > 1) { // LOG4J2-1518, 
> LOG4J2-2031
>                     // If queue is full AND we are in a recursive call, call 
> appender directly to prevent deadlock
>                     AsyncQueueFullMessageUtil.logWarningToStatusLogger();
>                     logMessageInCurrentThread(logEvent);
>                 } else {
>                     // delegate to the event router (which may discard, 
> enqueue and block, or log in current thread)
>                     final EventRoute route = 
> asyncQueueFullPolicy.getRoute(dispatcher.getId(), memento.getLevel());
>                     route.logMessage(this, memento);
>                 }
>             } else {
>                 error("Appender " + getName() + " is unable to write primary 
> appenders. queue is full");
>                 logToErrorAppenderIfNecessary(false, memento);
>             }
>         }
>     }
> {code}
> Application usually runs with multi threads, if the AsyncAppender inner queue 
> was full, then the DefaultErrorHandler may be executed across threads. 
> However, the exceptionCount filed and lastException fields were not volatile 
> variables, it may cause their value were not shared across threads.
> {code:java}
>     // org.apache.logging.log4j.core.appender.DefaultErrorHandler
>     private static final int MAX_EXCEPTIONS = 3;
>     private static final long EXCEPTION_INTERVAL = 
> TimeUnit.MINUTES.toNanos(5);
>     private int exceptionCount = 0;
>     private long lastException = System.nanoTime() - EXCEPTION_INTERVAL - 1;
>     @Override
>     public void error(final String msg) {
>         final long current = System.nanoTime();
>         if (current - lastException > EXCEPTION_INTERVAL || exceptionCount++ 
> < MAX_EXCEPTIONS) {
>             LOGGER.error(msg);
>         }
>         lastException = current;
>     }
> {code}



--
This message was sent by Atlassian Jira
(v8.20.1#820001)

Reply via email to