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方法主要是校驗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主要是先寫入encoder.footerBytes(),再關閉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類型,會先執(zhí)行prepareForDeferredProcessing;writeOut先執(zhí)行encoder的encode,然后加鎖執(zhí)行outputStream.write(byteArray),如果需要immediateFlush則會執(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方法會加鎖執(zhí)行closeOutputStream、給outputStream賦值,再執(zhí)行encoderInit;closeOutputStream主要是為了清空前面遺留的數(shù)據(jù),encoderInit則先寫入encoder.headerBytes()
小結
logback的OutputStreamAppender主要是通過非公平的ReentrantLock來寫入outputStream。
以上就是logback OutputStreamAppender日志輸出效率提升源碼解析的詳細內(nèi)容,更多關于logback OutputStreamAppender的資料請關注腳本之家其它相關文章!
相關文章
Spring Boot 集成Shiro的多realm實現(xiàn)以及shiro基本入門教程
這篇文章主要介紹了Spring Boot 集成Shiro的多realm實現(xiàn)以及shiro基本入門,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
Mybatis攔截器如何實現(xiàn)數(shù)據(jù)權限過濾
本文介紹了MyBatis攔截器的使用,通過實現(xiàn)Interceptor接口對SQL進行處理,實現(xiàn)數(shù)據(jù)權限過濾功能,通過在本地線程變量中存儲數(shù)據(jù)權限相關信息,并在攔截器的intercept方法中進行SQL增強處理2024-12-12
Java_int、double型數(shù)組常用操作工具類(分享)
下面小編就為大家?guī)硪黄狫ava_int、double型數(shù)組常用操作工具類(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08

