The actual code in the AsyncAppender does:
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
final Message message =
AsyncQueueFullMessageUtil.transform(logEvent.getMessage());
logMessageInCurrentThread(new
Log4jLogEvent.Builder(logEvent).setMessage(message).build());
} else {
// delegate to the event router (which may discard, enqueue and
block, or log in current thread)
final EventRoute route =
asyncQueueFullPolicy.getRoute(thread.getId(), memento.getLevel());
route.logMessage(this, memento);
}
} else {
error("Appender " + getName() + " is unable to write primary
appenders. queue is full");
logToErrorAppenderIfNecessary(false, memento);
}
}
}
And then the run method for the thread does:
while (!queue.isEmpty()) {
try {
final LogEvent event = queue.take();
if (event instanceof Log4jLogEvent) {
final Log4jLogEvent logEvent = (Log4jLogEvent) event;
logEvent.setEndOfBatch(queue.isEmpty());
callAppenders(logEvent);
count++;
} else {
ignored++;
LOGGER.trace("Ignoring event of class {}",
event.getClass().getName());
}
} catch (final InterruptedException ex) {
// May have been interrupted to shut down.
// Here we ignore interrupts and try to process all remaining events.
}
}
As you can see it doesn’t handle batches.
Ralph
> On Jan 9, 2018, at 7:27 AM, Jochen Wiedmann <[email protected]> wrote:
>
> On 2018-01-09 14:46, Apache <[email protected]> wrote:
>> The Logging api only allows you to log a single event at a time so it
>> doesn?019t make sense for an appender to have a method that accepts multiple
>> events since it can?019t happen. That said, appenders can queue the events
>> and send them downstream in batches. I believe some of the appenders do that
>> now.
>
>>
>> Is there some use case I am not aware of where this method could be called?
>
> As I wrote, the use case would be performance, assuming that the
> Appender can process a bunch of messages just as quickly as a single
> message. (Think of the JMSAppender using a BatchMessage, rather than a
> TextMessage, or ObjectMessage.)
>
> My trivial guess would be, that the AsyncAppender somewhere has code
> like the following:
>
> private void pushToSyncAppender(LogEvent[] events) {
> final Appender appender = this.syncAppender;
> for (LogEvent ev : events) {
> appender.append(ev);
> }
> }
>
> which could be changed to
>
> private void pushToSyncAppender(LogEvent[] events) {
> final Appender appender = this.syncAppender;
> if (appender instanceof BatchableAppender) {
> ((BatchableAppender) appender).append(events);
> } else {
> for (LogEvent ev : events) {
> appender.append(ev);
> }
> }
> }
>
> I have to admit, though, that I don't detect right now, where the
> AsyncAppender is actually pushing to the synchronous appender.
>
> Jochen
>