欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

logback的AsyncAppender高效日志處理方式源碼解析

 更新時間:2023年10月29日 08:31:59   作者:codecraft  
這篇文章主要為大家介紹了logback的AsyncAppender高效日志處理方式源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

本文主要研究一下logback的AsyncAppender

AsyncAppender

ch/qos/logback/classic/AsyncAppender.java

public class AsyncAppender extends AsyncAppenderBase<ILoggingEvent> {
    boolean includeCallerData = false;
    /**
     * Events of level TRACE, DEBUG and INFO are deemed to be discardable.
     * @param event
     * @return true if the event is of level TRACE, DEBUG or INFO false otherwise.
     */
    protected boolean isDiscardable(ILoggingEvent event) {
        Level level = event.getLevel();
        return level.toInt() <= Level.INFO_INT;
    }
    protected void preprocess(ILoggingEvent eventObject) {
        eventObject.prepareForDeferredProcessing();
        if (includeCallerData)
            eventObject.getCallerData();
    }
    public boolean isIncludeCallerData() {
        return includeCallerData;
    }
    public void setIncludeCallerData(boolean includeCallerData) {
        this.includeCallerData = includeCallerData;
    }
}
AsyncAppender繼承了AsyncAppenderBase,它新增了includeCallerData配置,另外覆蓋了isDiscardable、preprocess方法,isDiscardable針對TRACE、DEBUG的級別返回true,INFO返回false;preprocess則判斷是否includeCallerData,是的話則執(zhí)行eventObject.getCallerData()

AsyncAppenderBase

ch/qos/logback/core/AsyncAppenderBase.java

public class AsyncAppenderBase<E> extends UnsynchronizedAppenderBase<E> implements AppenderAttachable<E> {
    AppenderAttachableImpl<E> aai = new AppenderAttachableImpl<E>();
    BlockingQueue<E> blockingQueue;
    /**
     * The default buffer size.
     */
    public static final int DEFAULT_QUEUE_SIZE = 256;
    int queueSize = DEFAULT_QUEUE_SIZE;
    int appenderCount = 0;
    static final int UNDEFINED = -1;
    int discardingThreshold = UNDEFINED;
    boolean neverBlock = false;
    Worker worker = new Worker();
    /**
     * The default maximum queue flush time allowed during appender stop. If the 
     * worker takes longer than this time it will exit, discarding any remaining 
     * items in the queue
     */
    public static final int DEFAULT_MAX_FLUSH_TIME = 1000;
    int maxFlushTime = DEFAULT_MAX_FLUSH_TIME;
    /**
     * Is the eventObject passed as parameter discardable? The base class's implementation of this method always returns
     * 'false' but sub-classes may (and do) override this method.
     * <p/>
     * <p>Note that only if the buffer is nearly full are events discarded. Otherwise, when the buffer is "not full"
     * all events are logged.
     *
     * @param eventObject
     * @return - true if the event can be discarded, false otherwise
     */
    protected boolean isDiscardable(E eventObject) {
        return false;
    }
    /**
     * Pre-process the event prior to queueing. The base class does no pre-processing but sub-classes can
     * override this behavior.
     *
     * @param eventObject
     */
    protected void preprocess(E eventObject) {
    }
    @Override
    public void start() {
        if (isStarted())
            return;
        if (appenderCount == 0) {
            addError("No attached appenders found.");
            return;
        }
        if (queueSize < 1) {
            addError("Invalid queue size [" + queueSize + "]");
            return;
        }
        blockingQueue = new ArrayBlockingQueue<E>(queueSize);
        if (discardingThreshold == UNDEFINED)
            discardingThreshold = queueSize / 5;
        addInfo("Setting discardingThreshold to " + discardingThreshold);
        worker.setDaemon(true);
        worker.setName("AsyncAppender-Worker-" + getName());
        // make sure this instance is marked as "started" before staring the worker Thread
        super.start();
        worker.start();
    }
    @Override
    public void stop() {
        if (!isStarted())
            return;
        // mark this appender as stopped so that Worker can also processPriorToRemoval if it is invoking
        // aii.appendLoopOnAppenders
        // and sub-appenders consume the interruption
        super.stop();
        // interrupt the worker thread so that it can terminate. Note that the interruption can be consumed
        // by sub-appenders
        worker.interrupt();
        InterruptUtil interruptUtil = new InterruptUtil(context);
        try {
            interruptUtil.maskInterruptFlag();
            worker.join(maxFlushTime);
            // check to see if the thread ended and if not add a warning message
            if (worker.isAlive()) {
                addWarn("Max queue flush timeout (" + maxFlushTime + " ms) exceeded. Approximately " + blockingQueue.size()
                                + " queued events were possibly discarded.");
            } else {
                addInfo("Queue flush finished successfully within timeout.");
            }
        } catch (InterruptedException e) {
            int remaining = blockingQueue.size();
            addError("Failed to join worker thread. " + remaining + " queued events may be discarded.", e);
        } finally {
            interruptUtil.unmaskInterruptFlag();
        }
    }
    @Override
    protected void append(E eventObject) {
        if (isQueueBelowDiscardingThreshold() && isDiscardable(eventObject)) {
            return;
        }
        preprocess(eventObject);
        put(eventObject);
    }
    protected boolean isDiscardable(E eventObject) {
        return false;
    }
    protected void preprocess(E eventObject) {
    }
    private boolean isQueueBelowDiscardingThreshold() {
        return (blockingQueue.remainingCapacity() < discardingThreshold);
    }
    private void put(E eventObject) {
        if (neverBlock) {
            blockingQueue.offer(eventObject);
        } else {
            putUninterruptibly(eventObject);
        }
    }
    private void putUninterruptibly(E eventObject) {
        boolean interrupted = false;
        try {
            while (true) {
                try {
                    blockingQueue.put(eventObject);
                    break;
                } catch (InterruptedException e) {
                    interrupted = true;
                }
            }
        } finally {
            if (interrupted) {
                Thread.currentThread().interrupt();
            }
        }
    }
    //......
}
AsyncAppenderBase繼承了UnsynchronizedAppenderBase,實現(xiàn)了AppenderAttachable接口,它定義了queueSize、discardingThreshold、neverBlock等屬性,其start方法會根據(jù)queueSize創(chuàng)建ArrayBlockingQueue,discardingThreshold默認為queueSize / 5,之后啟動Wroker;stop方法則執(zhí)行worker.interrupt(),然后等待maxFlushTime讓log進行flush;其append方法會先判斷isQueueBelowDiscardingThreshold及isDiscardable,都為true則直接返回,否則執(zhí)行preprocess、put方法

Worker

ch/qos/logback/core/AsyncAppenderBase.java

class Worker extends Thread {
        public void run() {
            AsyncAppenderBase<E> parent = AsyncAppenderBase.this;
            AppenderAttachableImpl<E> aai = parent.aai;
            // loop while the parent is started
            while (parent.isStarted()) {
                try {
                    E e = parent.blockingQueue.take();
                    aai.appendLoopOnAppenders(e);
                } catch (InterruptedException ie) {
                    break;
                }
            }
            addInfo("Worker thread will flush remaining events before exiting. ");
            for (E e : parent.blockingQueue) {
                aai.appendLoopOnAppenders(e);
                parent.blockingQueue.remove(e);
            }
            aai.detachAndStopAllAppenders();
        }
    }
Worker的run方法會不斷循環(huán)從blockingQueue阻塞取出原生,然后添加到AppenderAttachableImpl;在started為false的時候跳槽循環(huán),然后遍歷blockingQueue,添加到AppenderAttachableImpl,然后將其從blockingQueue;最后執(zhí)行detachAndStopAllAppenders

AppenderAttachableImpl

ch/qos/logback/core/spi/AppenderAttachableImpl.java

public int appendLoopOnAppenders(E e) {
        int size = 0;
        final Appender<E>[] appenderArray = appenderList.asTypedArray();
        final int len = appenderArray.length;
        for (int i = 0; i < len; i++) {
            appenderArray[i].doAppend(e);
            size++;
        }
        return size;
    }
    /**
     * Remove and processPriorToRemoval all previously attached appenders.
     */
    public void detachAndStopAllAppenders() {
        for (Appender<E> a : appenderList) {
            a.stop();
        }
        appenderList.clear();
    }
AppenderAttachableImpl的appendLoopOnAppenders方法會遍歷所有的appenderList執(zhí)行doAppend方法;其detachAndStopAllAppenders則遍歷appenderList,挨個執(zhí)行stop,最后clear掉整個appenderList

小結(jié)

logback的AsyncAppender使用ArrayBlockingQueue(默認size為256)來進行緩沖,每次append的時候會先判斷isQueueBelowDiscardingThreshold及isDiscardable,為true則直接返回/丟棄,之后執(zhí)行preprocess,最后執(zhí)行put,put的時候有個參數(shù)neverBlock,為true則使用的是offer方法,隊列滿的時候會被丟棄,為false則是阻塞的方法,等到put成功才返回;另外它有個worker線程,不斷從blockingQueue阻塞take元素出來然后寫入到appenderList,在關(guān)閉時還會遍歷隊列寫入到appenderList然后從隊列移除,最后清空隊列。

以上就是logback的AsyncAppender的詳細內(nèi)容,更多關(guān)于logback的AsyncAppender的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 調(diào)用Mybatis?plus中的saveBatch方法報找不到表的問題

    調(diào)用Mybatis?plus中的saveBatch方法報找不到表的問題

    在用Mybatis plus開發(fā)的項目中,用自帶的API批量保存的方法saveBatch操作時,發(fā)現(xiàn)報沒有找到表的錯誤,本文就來詳細的介紹一下解決方法,感興趣的可以了解一下
    2024-03-03
  • SpringRunner和SpringJUnit4ClassRunner的區(qū)別及說明

    SpringRunner和SpringJUnit4ClassRunner的區(qū)別及說明

    這篇文章主要介紹了SpringRunner和SpringJUnit4ClassRunner的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • springboot中事務(wù)管理@Transactional的注意事項與使用場景

    springboot中事務(wù)管理@Transactional的注意事項與使用場景

    今天小編就為大家分享一篇關(guān)于springboot中事務(wù)管理@Transactional的注意事項與使用場景,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • springmvc+Hibernate+JPA(混合事務(wù))解讀

    springmvc+Hibernate+JPA(混合事務(wù))解讀

    在Spring項目中,Spring Data JPA作為一種持久層框架,因其簡化數(shù)據(jù)庫操作而受到青睞,但在將其引入使用Hibernate的舊項目時,可能會遇到事務(wù)處理問題,解決方案包括配置兩種事務(wù)管理器:Hibernate事務(wù)管理器和JPA事務(wù)管理器
    2024-09-09
  • java不用循環(huán)語句打印數(shù)組元素的實例

    java不用循環(huán)語句打印數(shù)組元素的實例

    下面小編就為大家?guī)硪黄猨ava不用循環(huán)語句打印數(shù)組元素的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • java多線程-讀寫鎖原理

    java多線程-讀寫鎖原理

    本文主要介紹java多線程的知識,這里整理了相關(guān)資料及簡單示例代碼,有興趣的小伙伴可以參考下
    2016-09-09
  • mybatisplus實現(xiàn)自動填充時間的項目實踐

    mybatisplus實現(xiàn)自動填充時間的項目實踐

    在數(shù)據(jù)庫操作中,頻繁設(shè)置創(chuàng)建時間和更新時間字段非常繁瑣,通過使用MyBatis-Plus的自動填充功能,可以簡化操作,本文就來詳細的介紹一下,感興趣的可以了解一下
    2024-10-10
  • Spring Boot Security配置教程

    Spring Boot Security配置教程

    在本文里我們給大家分享了關(guān)于Spring Boot Security配置的相關(guān)步驟以及注意要點,需要的朋友們跟著操作下。
    2019-05-05
  • SpringBoot處理跨域請求的四種方法

    SpringBoot處理跨域請求的四種方法

    在現(xiàn)代Web應(yīng)用中,由于安全性和隱私的考慮,瀏覽器限制了從一個域向另一個域發(fā)起的跨域HTTP請求,解決這個問題的一種常見方式是實現(xiàn)跨域資源共享(CORS),SpringBoot提供了多種方式來處理跨域請求,本文將介紹其中的幾種方法,感興趣的朋友可以參考下
    2023-12-12
  • java 刪除數(shù)組元素與刪除重復(fù)數(shù)組元素的代碼

    java 刪除數(shù)組元素與刪除重復(fù)數(shù)組元素的代碼

    在java中刪除數(shù)組元素與過濾重復(fù)數(shù)組元素我們都會需要去遍歷數(shù)組然后根據(jù)我們設(shè)置的值或方法進行去除數(shù)組
    2013-10-10

最新評論