logback异步日志

异步日志类

ch.qos.logback.classic.AsyncAppender

异步日志配置

<appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender>    
                   <!-- config options -->
                 <!-- 设置非阻塞模式 -->
       <neverBlock>true</neverBlock>
       <!-- 设置队列大小,默认256 -->
       <queueSize>1024</queueSize>
       <!-- 当队列的剩余容量小于这个discardingThreshold并且当前日志level TRACE, DEBUG or INFO ,则丢弃这些日志 -->
       <discardingThreshold>0</discardingThreshold>
       <!-- 引用普通同步日志 -->
       <appender-ref ref="taskLogAppender"/>
</appender>

discardingThreshold

 @Override
 protected void append(E eventObject) {
     //当队列的剩余容量小于这个discardingThreshold,且当前日志level TRACE, DEBUG or INFO ,则丢弃这些日志
     if (isQueueBelowDiscardingThreshold() && isDiscardable(eventObject)) {
         return;
     }
     preprocess(eventObject);
     put(eventObject);
 }

 private boolean isQueueBelowDiscardingThreshold() {
     return (blockingQueue.remainingCapacity() < discardingThreshold);
 }

 protected boolean isDiscardable(ILoggingEvent event) {
   Level level = event.getLevel();
   return level.toInt() <= Level.INFO_INT;
}

logback本质是一个BlockingQueue<E> blockingQueue

当调用put方法添加元素时候neverBlock=true时,调用的是offer方法;否则,调用的是put方法。

 private void put(E eventObject) {
    if (neverBlock) {
        blockingQueue.offer(eventObject);
    } else {
        try {
            blockingQueue.put(eventObject);
        } catch (InterruptedException e) {
            // Interruption of current thread when in doAppend method should not be consumed
            // by AsyncAppender
            Thread.currentThread().interrupt();
        }
    }
}       

ArrayBlockingQueue#offer方法是非阻塞的。

public boolean offer(E e) {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        if (count == items.length)
            return false;
        else {
            enqueue(e);
            return true;
        }
    } finally {
        lock.unlock();
    }
}

ArrayBlockingQueue#put

public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length)
            notFull.await();
        enqueue(e);
    } finally {
        lock.unlock();
    }
}

如果调用的是put方法,当队列满时,会挂起当前线程。所以设置异步日志方法需要将neverBlock设置为true