聊聊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。

目录 ..........................................................................................................................I 译者声明.......................................................................................................................... 1 发布记录.......................................................................................................................... 1 1. 介绍.......................................................................................................................... 2 1.1. 什么是 logback ............................................................................................ 2 1.2. 第一步 ........................................................................................................ 2 1.2.1. 必要条件.............................................................................................. 2 1.3. 构建 logback................................................................................................ 5 2. 体系结构................................................................................................................... 6 2.1. logback 的体系结构 ..................................................................................... 6 2.2. LoggerAppender 和 Layout ........................................................................ 6 2.2.1. Logger 上下文 ...................................................................................... 6 2.2.2. 有效级别(Level)即级别继承 ............................................................. 7 2.2.3. 打印方法和基本选择规则 ..................................................................... 9 2.2.4. 获取 Logger........................................................................................ 10 2.2.5. Appender 和 Layout..............................................................................11 2.2.6. 参数化记录 ........................................................................................ 13 2.2.7. 更好的替代方法 ................................................................
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值