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

Anthony Baldocchi commented on LOG4J2-471:
------------------------------------------

Remko, in my current use case, the RingBuffer is configured to a smaller number 
of entries than the default (variable based on heap size and assuming a 
near-worst-case referenced object because asynchronous logging can potentially 
alter the expected lifecycle of objects if the logging thread is running 
behind; I was hitting OutOfMemoryErrors due to some large objects that couldn't 
be garbage collected until logging finished but new large objects could be 
generated because the thread that issued the log request was not blocked; 
262144 large objects overflowed the heap).

However, I think RingBuffer size only impacts the likelihood of encountering 
the issue (as the likelihood of hitting a full buffer decreases); as long as 
the buffer is filling more quickly than it is being emptied (not difficult to 
do with asynchronous logging), the buffer can reach fullness and, once full, 
this issue becomes significant.  With a high logging rate, a single rollover 
event might be all that is needed to reach buffer fullness, no matter how large.

The workaround I'm currently considering is a filter, akin to the BurstFilter, 
that makes use of the RingBufferAdmin introduced in 2.0-rc1 to reject logging 
events when the RingBuffer is full.  I like the idea of the errorAppender you 
mention for AsyncAppender; I'm going to see if I can add similar fallback 
functionality as I'd like to avoid dropping logging events entirely if at all 
possible.  

An alternative solution I was considering was making use of a ThreadLocal to 
identify the AsyncLogger thread and then since I could determine if the thread 
was the AsyncLogger thread and that the RingBuffer was full, skip the publish 
event step and instead just call config.loggerconfig.log(...), passing the 
arguments on through.  Patch for this second solution is attached.

> toString methods that perform logging can deadlock AsyncLogger
> --------------------------------------------------------------
>
>                 Key: LOG4J2-471
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-471
>             Project: Log4j 2
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: 2.0-beta9
>         Environment: Debian Squeeze
> Java 7u25
>            Reporter: Anthony Baldocchi
>            Assignee: Remko Popma
>
> The AsyncLogger thread is the only consumer of a Disruptor RingBuffer which 
> contains log events ostensibly produced by a number of other threads.  
> However, when AsyncLogger generates a log message, it has to call toString() 
> on objects which can potentially also perform logging internally.  This 
> results in a situation when the RingBuffer is nearly full whereby AsyncLogger 
> has pulled an event from the RingBuffer, calls toString() on the associated 
> objects, which call AsyncLogger.log which attempts to publish an event into a 
> full buffer, which will park repeatedly without hope of ever leaving the 
> loop.  Relevant stack trace is:
> "AsyncLogger-1" daemon prio=10 tid=0x00007f7a705a8000 nid=0x3d73 runnable 
> [0x00007f7a740d1000]
>    java.lang.Thread.State: TIMED_WAITING (parking)
>         at sun.misc.Unsafe.park(Native Method)
>         at 
> java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:349)
>         at 
> com.lmax.disruptor.MultiProducerSequencer.next(MultiProducerSequencer.java:133)
>         at 
> com.lmax.disruptor.MultiProducerSequencer.next(MultiProducerSequencer.java:102)
>         at com.lmax.disruptor.RingBuffer.publishEvent(RingBuffer.java:391)
>         at com.lmax.disruptor.dsl.Disruptor.publishEvent(Disruptor.java:219)
>         at 
> org.apache.logging.log4j.core.async.AsyncLogger.log(AsyncLogger.java:214)
>         at 
> org.apache.logging.log4j.spi.AbstractLoggerWrapper.log(AbstractLoggerWrapper.java:55)
>         at org.slf4j.impl.SLF4JLogger.debug(SLF4JLogger.java:138)
>         at org.somepackage.SomeException.toString (SomeException.java:32)
>         at java.lang.String.valueOf(String.java:2854)
>         at java.io.PrintWriter.println(PrintWriter.java:754)
>         at java.lang.Throwable$WrappedPrintWriter.println(Throwable.java:763)
>         at java.lang.Throwable.printStackTrace(Throwable.java:654)
>         - locked <0x00000000cb2f6380> (a java.io.PrintWriter)
>         at java.lang.Throwable.printStackTrace(Throwable.java:720)
>         at 
> org.apache.logging.log4j.core.pattern.ThrowablePatternConverter.formatOption(ThrowablePatternConverter.java:138)
>         at 
> org.apache.logging.log4j.core.pattern.ThrowablePatternConverter.format(ThrowablePatternConverter.java:80)
>         at 
> org.apache.logging.log4j.core.pattern.ExtendedThrowablePatternConverter.format(ExtendedThrowablePatternConverter.java:69)
>         at 
> org.apache.logging.log4j.core.pattern.PatternFormatter.format(PatternFormatter.java:36)
>         at 
> org.apache.logging.log4j.core.layout.PatternLayout.toSerializable(PatternLayout.java:167)
>         at 
> org.apache.logging.log4j.core.layout.PatternLayout.toSerializable(PatternLayout.java:52)
>         at 
> org.apache.logging.log4j.core.layout.AbstractStringLayout.toByteArray(AbstractStringLayout.java:45)
>         at 
> org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:111)
>         at 
> org.apache.logging.log4j.core.appender.RollingRandomAccessFileAppender.append(RollingRandomAccessFileAppender.java:96)
>         at 
> org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:99)
>         at 
> org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:425)
>         at 
> org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:406)
>         at 
> org.apache.logging.log4j.core.Logger$PrivateConfig.logEvent(Logger.java:273)
>         at 
> org.apache.logging.log4j.core.async.AsyncLogger.actualAsyncLog(AsyncLogger.java:230)
>         at 
> org.apache.logging.log4j.core.async.RingBufferLogEvent.execute(RingBufferLogEvent.java:98)
>         at 
> org.apache.logging.log4j.core.async.RingBufferLogEventHandler.onEvent(RingBufferLogEventHandler.java:43)
>         at 
> org.apache.logging.log4j.core.async.RingBufferLogEventHandler.onEvent(RingBufferLogEventHandler.java:28)
>         at 
> com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:133)
>         at 
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
>         at 
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
>         at java.lang.Thread.run(Thread.java:724)



--
This message was sent by Atlassian JIRA
(v6.1.5#6160)

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscr...@logging.apache.org
For additional commands, e-mail: log4j-dev-h...@logging.apache.org

Reply via email to