logback?OutputStreamAppender高效日志輸出源碼解析
序
本文主要研究一下logback的OutputStreamAppender
OutputStreamAppender
logback-core/src/main/java/ch/qos/logback/core/OutputStreamAppender.java
public class OutputStreamAppender<E> extends UnsynchronizedAppenderBase<E> { /** * It is the encoder which is ultimately responsible for writing the event to an * {@link OutputStream}. */ protected Encoder<E> encoder; /** * All synchronization in this class is done via the lock object. */ protected final ReentrantLock streamWriteLock = new ReentrantLock(false); /** * This is the {@link OutputStream outputStream} where output will be written. */ private OutputStream outputStream; boolean immediateFlush = true; //...... }
OutputStreamAppender繼承了UnsynchronizedAppenderBase,它定義了encoder、streamWriteLock、outputStream、immediateFlush屬性
start
/** * Checks that requires parameters are set and if everything is in order, * activates this appender. */ public void start() { int errors = 0; if (this.encoder == null) { addStatus(new ErrorStatus("No encoder set for the appender named \"" + name + "\".", this)); errors++; } if (this.outputStream == null) { addStatus(new ErrorStatus("No output stream set for the appender named \"" + name + "\".", this)); errors++; } // only error free appenders should be activated if (errors == 0) { super.start(); } }
其start方法主要是校驗(yàn)encoder、outputStream,然后執(zhí)行super.start()
stop
/** * Stop this appender instance. The underlying stream or writer is also closed. * * <p> * Stopped appenders cannot be reused. */ public void stop() { if(!isStarted()) return; streamWriteLock.lock(); try { closeOutputStream(); super.stop(); } finally { streamWriteLock.unlock(); } } protected void closeOutputStream() { if (this.outputStream != null) { try { // before closing we have to output out layout's footer encoderClose(); this.outputStream.close(); this.outputStream = null; } catch (IOException e) { addStatus(new ErrorStatus("Could not close output stream for OutputStreamAppender.", this, e)); } } } void encoderClose() { if (encoder != null && this.outputStream != null) { try { byte[] footer = encoder.footerBytes(); writeBytes(footer); } catch (IOException ioe) { this.started = false; addStatus(new ErrorStatus("Failed to write footer for appender named [" + name + "].", this, ioe)); } } }
其stop方法主要是加鎖然后closeOutputStream,再執(zhí)行super.stop;closeOutputStream主要是先寫(xiě)入encoder.footerBytes(),再關(guān)閉outputStream
append
protected void append(E eventObject) { if (!isStarted()) { return; } subAppend(eventObject); } protected void subAppend(E event) { if (!isStarted()) { return; } try { // this step avoids LBCLASSIC-139 if (event instanceof DeferredProcessingAware) { ((DeferredProcessingAware) event).prepareForDeferredProcessing(); } writeOut(event); } catch (IOException ioe) { // as soon as an exception occurs, move to non-started state // and add a single ErrorStatus to the SM. this.started = false; addStatus(new ErrorStatus("IO failure in appender", this, ioe)); } } protected void writeOut(E event) throws IOException { byte[] byteArray = this.encoder.encode(event); writeBytes(byteArray); } private void writeBytes(byte[] byteArray) throws IOException { if (byteArray == null || byteArray.length == 0) return; streamWriteLock.lock(); try { writeByteArrayToOutputStreamWithPossibleFlush(byteArray); } finally { streamWriteLock.unlock(); } } /** * A simple method to write to an outputStream and flush the stream if immediateFlush is set to true. * * @since 1.3.9/1.4.9 */ protected final void writeByteArrayToOutputStreamWithPossibleFlush(byte[] byteArray) throws IOException { this.outputStream.write(byteArray); if (immediateFlush) { this.outputStream.flush(); } }
append方法主要是執(zhí)行writeOut操作,如果是DeferredProcessingAware類型,會(huì)先執(zhí)行prepareForDeferredProcessing;writeOut先執(zhí)行encoder的encode,然后加鎖執(zhí)行outputStream.write(byteArray),如果需要immediateFlush則會(huì)執(zhí)行outputStream.flush()
setOutputStream
public void setOutputStream(OutputStream outputStream) { streamWriteLock.lock(); try { // close any previously opened output stream closeOutputStream(); this.outputStream = outputStream; if (encoder == null) { addWarn("Encoder has not been set. Cannot invoke its init method."); return; } encoderInit(); } finally { streamWriteLock.unlock(); } } protected void closeOutputStream() { if (this.outputStream != null) { try { // before closing we have to output out layout's footer encoderClose(); this.outputStream.close(); this.outputStream = null; } catch (IOException e) { addStatus(new ErrorStatus("Could not close output stream for OutputStreamAppender.", this, e)); } } } void encoderInit() { if (encoder != null && this.outputStream != null) { try { byte[] header = encoder.headerBytes(); writeBytes(header); } catch (IOException ioe) { this.started = false; addStatus( new ErrorStatus("Failed to initialize encoder for appender named [" + name + "].", this, ioe)); } } }
setOutputStream方法會(huì)加鎖執(zhí)行closeOutputStream、給outputStream賦值,再執(zhí)行encoderInit;closeOutputStream主要是為了清空前面遺留的數(shù)據(jù),encoderInit則先寫(xiě)入encoder.headerBytes()
小結(jié)
logback的OutputStreamAppender主要是通過(guò)非公平的ReentrantLock來(lái)寫(xiě)入outputStream。
以上就是logback OutputStreamAppender日志輸出效率提升源碼解析的詳細(xì)內(nèi)容,更多關(guān)于logback OutputStreamAppender的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Springboot Logback日志多文件輸出方式(按日期和大小分割)
- 使用logback配置按天和文件大小切割輸出日志
- java使用Logback配置輸出日志內(nèi)容到文件示例代碼
- logback自定義json日志輸出示例詳解
- Slf4j+logback實(shí)現(xiàn)JSON格式日志輸出方式
- logback過(guò)濾部分日志輸出的操作
- logback輸出日志屏蔽quartz的debug等級(jí)日志方式
- dubbo 如何使用logback來(lái)輸出日志
- springboot使用Logback把日志輸出到控制臺(tái)或輸出到文件
- Logback如何將日志輸出到Kafka配置示例
相關(guān)文章
Spring Boot 集成Shiro的多realm實(shí)現(xiàn)以及shiro基本入門(mén)教程
這篇文章主要介紹了Spring Boot 集成Shiro的多realm實(shí)現(xiàn)以及shiro基本入門(mén),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10關(guān)于Android觸摸事件分發(fā)的原理詳析
觸摸事件分發(fā)機(jī)制一直以來(lái)都是Android中比較重要的一大塊,自定義view,各種復(fù)雜的自定義手勢(shì)交互都與觸摸事件分發(fā)機(jī)制關(guān)系密,下面這篇文章主要給大家介紹了關(guān)于Android觸摸事件分發(fā)原理的相關(guān)資料,需要的朋友可以參考下2022-01-01Mybatis攔截器如何實(shí)現(xiàn)數(shù)據(jù)權(quán)限過(guò)濾
本文介紹了MyBatis攔截器的使用,通過(guò)實(shí)現(xiàn)Interceptor接口對(duì)SQL進(jìn)行處理,實(shí)現(xiàn)數(shù)據(jù)權(quán)限過(guò)濾功能,通過(guò)在本地線程變量中存儲(chǔ)數(shù)據(jù)權(quán)限相關(guān)信息,并在攔截器的intercept方法中進(jìn)行SQL增強(qiáng)處理2024-12-12Java_int、double型數(shù)組常用操作工具類(分享)
下面小編就為大家?guī)?lái)一篇Java_int、double型數(shù)組常用操作工具類(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08關(guān)于maven使用過(guò)程中無(wú)法導(dǎo)入依賴的一些總結(jié)
這篇文章主要介紹了關(guān)于maven使用過(guò)程中無(wú)法導(dǎo)入依賴的一些總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08