logback OutputStreamAppender高效日志输出源码解析
更新时间:2023年10月29日 17:05:21 作者:codecraft
这篇文章主要介绍了为大家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的资料请关注脚本之家其它相关文章!
相关文章
mybatis-plus批量更新updateBatchById问题
这篇文章主要介绍了mybatis-plus批量更新updateBatchById问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2023-07-07
最新评论