一区二区三区电影_国产伦精品一区二区三区视频免费_亚洲欧美国产精品va在线观看_国产精品一二三四

聯(lián)系我們 - 廣告服務(wù) - 聯(lián)系電話:
您的當前位置: > 關(guān)注 > > 正文

Log4j2源碼解析:同步寫、異步寫原理、中間技術(shù)思考

來源:CSDN 時間:2023-03-07 11:41:12

Log4j2中的組件 從配置開始API基本使用小細節(jié) 寫日志的原理主要流程 同步寫異步寫 順便說一下ArrayBlockingQueue notFull 與 notEmpty 異步寫是怎么玩的巧妙的異步寫設(shè)計 ByteBuffer與RandomAccessFileGarbage-free避免創(chuàng)建多余對象異步Logger性能 寫在最后

本文主要記錄我對Log4j2源碼閱讀后的一些個人理解,包括的內(nèi)容有:Log4j2的組件、同步寫、異步寫原理、以及中間技術(shù)的個人思考。而log4j2的使用與配置稍顯簡易,可在很多地方找到說明,本文則不重點討論這部分的內(nèi)容。


【資料圖】

Log4j2中的組件

Log4j2以插件的方式來配置各個組件,在配置中可自由的插拔組件,并支持自動生效(配置monitorInterval)。

從配置開始

Log4j2支持多種格式配置文件,xml、json、yaml、properties。相應(yīng)地,初始化時會逐個查找并加載這類文件。以最常用的xml配置為例,Log4j2默認的文件名稱為log4j2.xml,主要配置如下:

target/rolling.log

如上配置的對象有: 1. Configuration: 表示日志環(huán)境的一份配置描述,用于構(gòu)建一份運行時的LoggerContext2. Logger表示日志記錄器,可有多個。示例中有2個普通記錄器,1個根記錄器。一個記錄器需要指定Appender,可指定多個,表示日志記錄到哪里。 3. Appenders表示日志的輸出源,可有多個。示例中有3個,Console表示通過標準輸出流輸出到控制臺,RollingRandomAccessFile表示可滾動的記錄日志,日志文件到達一定的大小后,會啟用壓縮。 Async表示一種異步的輸出端,通過異步線程與隊列的方式寫入日志到其關(guān)聯(lián)的實際Appender中。

API基本使用

// 獲取Logger private static final Logger logger = LogManager.getLogger("HelloWorld"); private static final Logger logger = LogManager.getLogger(Class.getName()); logger.info("Hello, World!");logger.debug("Logging in user {} with birthday {}", user.getName(), user.getBirthdayCalendar());logger.debug("Logging in user %s with birthday %s", user.getName(), user.getBirthdayCalendar());

小細節(jié)

Log4j2在對外的info,warn等API上在內(nèi)置了logIfEnabled的判斷,而不用在程序中顯示的寫上:

if (logger.isInfoEnabled()) {    logger.info();}if (logger.isWarnEnabled()) {    logger.warn();}

所以在寫日志時,放心的直接用logger.info,logger.warn吧。

寫日志的原理

主要流程

同步寫

如上流程是典型的同步寫的過程,多線程并發(fā)寫是通過臨界區(qū)來實現(xiàn)。簡要過程如下:

相關(guān)代碼: AbstractOutputStreamAppender#directEncodeEvent 以常用的基于PatternLayout的日志格式為例:

private void encodeSynchronized(final CharsetEncoder charsetEncoder, final CharBuffer charBuffer,            final StringBuilder source, final ByteBufferDestination destination) {      // 臨界區(qū)阻塞式Encode        synchronized (destination) {            try {                TextEncoderHelper.encodeText(charsetEncoder, charBuffer, destination.getByteBuffer(), source,                        destination);            } catch (final Exception ex) {               ..            }        }    }// 根據(jù)不同的Appender用OutputStream.writeBytespublic synchronized void flush() {        flushBuffer(byteBuffer);        flushDestination();}

異步寫

如上配置的Async表示一種異步輸出器,對應(yīng)的實現(xiàn)為AsyncAppender。 異步Appender使用異步線程加阻塞隊列(BlockingQueue)來實現(xiàn)異步寫的功能。默認情況下通過BlockingQueueFactory創(chuàng)建缺省的隊列類型為:ArrayBlockingQueue,隊列大小為128.

順便說一下ArrayBlockingQueue

notFull 與 notEmpty

put和take阻塞調(diào)用線程是借用notFull和notEmpty兩個條件對象來實現(xiàn)的。

所以在理解這兩個詞的意思時,看看Doug Lea給的注釋:

等待take的條件    private final Condition notEmpty;    等待put的條件    private final Condition notFull;

換言之,此處的notEmpty表示為:只有隊列在notEmpty的條件下才能take, 如果隊列為empty,那么當前take的線程則需要等待。類似的,當隊列在notFull時,才能put, 如果隊列為full, 那么當前put的線程則需要等待。

異步寫是怎么玩的

業(yè)務(wù)線程并發(fā)調(diào)用同一個Logger寫日志時,Log4j2內(nèi)部把內(nèi)容解析成LogEvent,然后投遞到隊列中,由異步的線程來負責(zé)消費。

相關(guān)代碼: 投遞到隊列:

public void append(final LogEvent logEvent) {         ...         獲取不可變的副本對象        final Log4jLogEvent memento = Log4jLogEvent.createMemento(logEvent, includeLocation);        if (!transfer(memento)) { // 投遞到隊列失敗,降級策略            if (blocking) { // 新版本默認為true                // 根據(jù)策略不同,可丟棄、可等待、可由當前線程執(zhí)行                final EventRoute route = asyncQueueFullPolicy.getRoute(thread.getId(), memento.getLevel());                route.logMessage(this, memento);            } else {                // 交由error-appender處理                logToErrorAppenderIfNecessary(false, memento);            }        }    }// 投遞LogEvent到隊列,新版本可指定隊列為LinkedTransferQueueprivate boolean transfer(final LogEvent memento) {        return queue instanceof TransferQueue            ? ((TransferQueue) queue).tryTransfer(memento)            : queue.offer(memento);}

消費寫LogEvent

消費while (!queue.isEmpty()) {     try {           final LogEvent event = queue.take();           if (event instanceof Log4jLogEvent) {               final Log4jLogEvent logEvent = (Log4jLogEvent) event;               logEvent.setEndOfBatch(queue.isEmpty());               // 在異步線程中調(diào)用Appender寫日志               callAppenders(logEvent);           } else {               ...          }       } catch (final InterruptedException ex) {           不處理異常,繼續(xù)寫日志       } }

巧妙的異步寫設(shè)計

實際環(huán)境中,很多業(yè)務(wù)線程在并發(fā)的寫日志到隊列中,并由一條異步消費者線程負責(zé)消費寫。高并發(fā)的場景下,很容易造成生成的速度大于消費的速度。 為了不阻塞生成,投遞LogEvent時選擇的是隊列的offer方法,如果成功入隊,則執(zhí)行馬上返回給應(yīng)用。如果隊列滿了,則默認降級為在同步寫,這種設(shè)計能極大的提供性能 。而消費時選擇的隊列的take方法,如果生產(chǎn)的日志較少,則park消費者線程,讓出CPU。 注意到offer方法在入隊成功時,也會調(diào)用notEmpty.signal()方法,進而喚醒消費者,從而讓它繼續(xù)工作。

ByteBuffer與RandomAccessFile

項目中常常會用到RollingRandomAccessFile這種Appender,而在Log4j2中都是基于ByteBuffer來管理字節(jié)緩沖,并用于處理字節(jié)流與字符流的高效轉(zhuǎn)換。最后采用RandomAccessFile來寫B(tài)ytes到文件。Log4j2官方給出的性能測試報告提到相較于BufferedOutputStream,ByteBuffer + RandomAccessFile有20-200%的性能改善。

private ByteBuffer getByteBuffer() {        ByteBuffer result = byteBufferThreadLocal.get();        if (result == null) {            result = ByteBuffer.wrap(new byte[byteBufferSize]);            byteBufferThreadLocal.set(result);        }        return result;}

在輸出ByteBuffer時,根據(jù)Appender的不同選擇不同的輸出策略。基于RandomAccessFile的輸出為: randomAccessFile.write(byteBuffer.toArray(), 0, byteBuffer.limit());

Garbage-free(避免創(chuàng)建多余對象)

Log4j2提倡創(chuàng)建最少的對象做更多事,盡量避免創(chuàng)建多余的對象。在內(nèi)部有很多細節(jié)代碼,這里分析2個例子。 1. API設(shè)計上避免創(chuàng)建變長數(shù)組 用void info(String message, Object p0, Object p1, Object p2, Object p3)這類參數(shù)明確的api替換帶變長數(shù)組的api.

提供工具來避免基礎(chǔ)類型參數(shù)的自動裝箱. 自動裝箱會創(chuàng)建大量的對象,Log4j2提供Unbox工具類來轉(zhuǎn)換為StringBuilder.

異步Logger

事實上log4j2的異步logger才是性能改善最卓越的部分。異步Logger內(nèi)部采用 Disruptor來實現(xiàn),它是一個用于代替隊列的無鎖化線程間的通信的工具庫,可以明顯的提高吞吐量并降低延遲。 自己后續(xù)會對Disruptor做一個學(xué)習(xí)與分析。感謝關(guān)注。

性能

Log4j2的性能改善是明顯的,官方文檔:http://logging.apache.org/log4j/2.x/performance.html 提供了大量的場景對比結(jié)果,有興趣的可以去了解一下。

寫在最后

The log4j1.x amost has became End of Life。So upgrade it and learn about it.

哦,對了,升級的時候可以用SLF4J來做統(tǒng)一的外觀,然后引入log4j-api,log4j-core, slf4j-api,還有slf4j到log4j2的橋接器log4j-slf4j-impl就行。但是需要注意的是: 咱們內(nèi)部中間件大多默認依賴了slf4j-log4j12,因此需要把這類依賴全部排出, 可以用如下的tip:

org.slf4jslf4j-log4j12999-not-exist

Good luck. Tks.

責(zé)任編輯:

標簽:

相關(guān)推薦:

精彩放送:

新聞聚焦
Top 一区二区三区电影_国产伦精品一区二区三区视频免费_亚洲欧美国产精品va在线观看_国产精品一二三四
亚洲无玛一区| 亚洲一级免费视频| 亚洲国产欧美日韩| av成人老司机| 亚洲一区二区黄色| 狠狠色综合网站久久久久久久| 亚洲二区在线视频| 久久精品亚洲国产奇米99| 欧美日韩午夜剧场| aa级大片欧美三级| 欧美日韩日本视频| 亚洲一区免费在线观看| 国产精品网站在线播放| 午夜精品久久| 国产一区二区三区四区老人| 久久久久一区二区三区| 国产女同一区二区| 国产午夜精品久久久| 日韩视频在线一区二区| 亚洲午夜一二三区视频| 亚洲国产岛国毛片在线| 亚洲国产精品一区二区www在线 | 国产嫩草一区二区三区在线观看| 亚洲高清激情| 欧美日韩成人综合在线一区二区| 亚洲欧美国产毛片在线| 一区二区三区在线免费视频| 欧美另类人妖| 欧美国产一区在线| 91久久一区二区| 国产精品高潮呻吟久久av无限 | 国产精品久久久爽爽爽麻豆色哟哟| 一区二区三区久久精品| 亚洲性感激情| 亚洲六月丁香色婷婷综合久久| 国产精品久久久久久妇女6080| 久久视频免费观看| 美女91精品| 欧美国产一区二区三区激情无套| 久久一二三四| 欧美偷拍一区二区| 亚洲午夜日本在线观看| 伊人男人综合视频网| 免费久久99精品国产| 裸体女人亚洲精品一区| 麻豆91精品| 久热精品视频在线观看一区| 久久精品综合网| 久久久久久久久久久成人| 久久综合九色综合欧美狠狠| 欧美日韩一区二区三区四区在线观看 | 国产精品99久久久久久久久久久久 | 欧美人成在线| 亚洲国产老妈| 亚洲第一久久影院| 久久久久久久综合狠狠综合| 欧美日韩在线高清| 国内自拍一区| 国产一在线精品一区在线观看| av不卡免费看| 国产精品久久激情| 亚洲免费视频成人| 国产视频一区在线| 亚洲欧美精品中文字幕在线| 欧美久久久久中文字幕| 亚洲激情国产| 一本一道久久综合狠狠老精东影业 | 99re66热这里只有精品4| 久久久www成人免费精品| 欧美精品免费视频| 在线观看日韩av电影| 欧美专区福利在线| 国语对白精品一区二区| 欧美成人tv| 亚洲一区二区三区成人在线视频精品 | 欧美伦理a级免费电影| 亚洲宅男天堂在线观看无病毒| 国产精品久久久久永久免费观看 | 欧美高清hd18日本| 亚洲网站啪啪| 亚洲美女黄色| 久久久一本精品99久久精品66| 国产欧美日韩在线| 国产精品看片资源| 国产精品每日更新| 国产精品一区二区三区四区五区| 国产日本欧美在线观看| 狠狠色丁香久久综合频道| 午夜精品久久久久| 国产精品99久久久久久有的能看| 国产日韩欧美在线看| 国产欧美91| 国产一区二区电影在线观看| 影音先锋中文字幕一区| 欧美视频在线观看免费| 欧美体内she精视频在线观看| 欧美激情在线狂野欧美精品| 欧美一区二区三区在线| 亚洲小说欧美另类婷婷| 亚洲欧美日韩久久精品| 欧美亚洲色图校园春色| 久久精品国内一区二区三区| 久久九九免费视频| aa亚洲婷婷| 国语自产精品视频在线看| 中文日韩电影网站| 欧美日韩第一区| 99成人精品| 欧美日本韩国一区| 99国产精品久久久久久久久久| 另类综合日韩欧美亚洲| 激情欧美一区二区| 美女免费视频一区| 亚洲国产精品成人va在线观看| 欧美一区二区三区免费观看| 欧美午夜美女看片| 中日韩在线视频| 国产精品你懂的| 久久久噜噜噜久久中文字免| 国产综合色产在线精品| 久久亚洲春色中文字幕久久久| 国模 一区 二区 三区| 欧美一区二区三区啪啪| 久久蜜臀精品av| 韩国美女久久| 久久久久久久成人| 国产精品成人久久久久| 在线视频你懂得一区| 国产欧美一区二区三区另类精品 | 99国内精品久久| 欧美高清视频一区| 国产一区二区三区奇米久涩| 亚洲大片av| 日韩视频免费在线| 中文av一区特黄| 国产精品一二三四| 久久综合电影| 亚洲中字在线| 亚洲靠逼com| 国产一区亚洲| 欧美日韩成人精品| 精品51国产黑色丝袜高跟鞋| 亚洲一二三四区| 国产精品久久久久一区二区三区| 在线观看日韩www视频免费 | 欧美日韩亚洲免费| 亚洲精品极品| 欧美视频一区二区| 亚洲天堂网在线观看| 国产精品久久久久国产a级| 99综合精品| 欧美特黄一级大片| 欧美一级一区| 影音先锋在线一区| 欧美区二区三区| 久久精品国产欧美激情| 狠狠入ady亚洲精品| 欧美激情在线免费观看| 亚洲欧美久久久| 亚洲国产日韩欧美在线动漫| 欧美sm极限捆绑bd| 性做久久久久久久久| 在线国产日韩| 国产精品一区免费视频| 欧美好骚综合网| 欧美在线影院| 亚洲一区二区三区久久| 好吊妞**欧美| 国产欧美一区二区白浆黑人| 欧美精品在线视频观看| 久久久久se| 久久精品99久久香蕉国产色戒| 亚洲精品1区| 亚洲福利电影| 在线欧美影院| 亚洲电影免费观看高清完整版在线| 国产美女精品| 国产精品中文字幕欧美| 国产精品久久久久久久久久久久 | 加勒比av一区二区| 国产精品爽爽爽| 国产精品自拍一区| 国产精品久久久久毛片大屁完整版| 欧美成人一区二免费视频软件| 开心色5月久久精品| 久久久av毛片精品| 免费在线视频一区| 欧美三级精品| 国产精品亚洲一区| 国内精品久久久久久久影视麻豆 | 国产精品久久久久久久9999| 欧美午夜性色大片在线观看| 欧美视频在线看| 国产精品美女久久久免费| 国产一区二区三区免费观看| 永久免费精品影视网站| 99精品黄色片免费大全| 久久黄色小说| 国产精品vvv| 亚洲人成亚洲人成在线观看图片|