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