美文网首页
聊聊logback的OutputStreamAppender

聊聊logback的OutputStreamAppender

作者: go4it | 来源:发表于2023-10-28 10:57 被阅读0次

    本文主要研究一下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

          本文链接:https://www.haomeiwen.com/subject/agapidtx.html