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,然后执行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,再执行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方法主要是执行writeOut操作,如果是DeferredProcessingAware类型,会先执行prepareForDeferredProcessing;writeOut先执行encoder的encode,然后加锁执行outputStream.write(byteArray),如果需要immediateFlush则会执行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方法会加锁执行closeOutputStream、给outputStream赋值,再执行encoderInit;closeOutputStream主要是为了清空前面遗留的数据,encoderInit则先写入encoder.headerBytes()
小结
logback的OutputStreamAppender主要是通过非公平的ReentrantLock来写入outputStream。
以上就是logback OutputStreamAppender日志输出效率提升源码解析的详细内容,更多关于logback OutputStreamAppender的资料请关注脚本之家其它相关文章!
相关文章
如何利用postman完成JSON串的发送功能(springboot)
这篇文章主要介绍了如何利用postman完成JSON串的发送功能(springboot),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2023-07-07
Java 使用JdbcTemplate 中的queryForList发生错误解决办法
这篇文章主要介绍了Java 使用JdbcTemplate 中的queryForList发生错误解决办法的相关资料,需要的朋友可以参考下2017-07-07
Java Stream对象并行处理方法parallel()代码示例
在Java中Stream是一种用于处理集合数据的流式操作API,它提供了一种简洁、灵活、高效的方式来对集合进行各种操作,下面这篇文章主要给大家介绍了关于Java Stream对象并行处理方法parallel()的相关资料,需要的朋友可以参考下2023-11-11
SpringBoot中的ImportSelector类动态加载bean详解
这篇文章主要介绍了SpringBoot中的ImportSelector类动态加载bean详解,ImportSelector接口是spring中导入外部配置的核心接口,根据给定的条件(通常是一个或多个注释属性)判定要导入那个配置类,在spring自动化配置和@EnableXXX中都有它的存在,需要的朋友可以参考下2024-01-01


最新评论