序
本文主要研究一下rocketmq的FileAppender
WriterAppender
org/apache/rocketmq/logging/inner/LoggingBuilder.java
public static class WriterAppender extends Appender { protected boolean immediateFlush = true; protected String encoding; protected QuietWriter qw; public WriterAppender() { } public void setImmediateFlush(boolean value) { immediateFlush = value; } public boolean getImmediateFlush() { return immediateFlush; } public void activateOptions() { } public void append(LoggingEvent event) { if (!checkEntryConditions()) { return; } subAppend(event); } protected boolean checkEntryConditions() { if (this.closed) { SysLogger.warn("Not allowed to write to a closed appender."); return false; } if (this.qw == null) { handleError("No output stream or file set for the appender named [" + name + "]."); return false; } if (this.layout == null) { handleError("No layout set for the appender named [" + name + "]."); return false; } return true; } public synchronized void close() { if (this.closed) { return; } this.closed = true; writeFooter(); reset(); } protected void closeWriter() { if (qw != null) { try { qw.close(); } catch (IOException e) { handleError("Could not close " + qw, e, CODE_CLOSE_FAILURE); } } } protected OutputStreamWriter createWriter(OutputStream os) { OutputStreamWriter retval = null; String enc = getEncoding(); if (enc != null) { try { retval = new OutputStreamWriter(os, enc); } catch (IOException e) { SysLogger.warn("Error initializing output writer."); SysLogger.warn("Unsupported encoding?"); } } if (retval == null) { retval = new OutputStreamWriter(os); } return retval; } public String getEncoding() { return encoding; } public void setEncoding(String value) { encoding = value; } public synchronized void setWriter(Writer writer) { reset(); this.qw = new QuietWriter(writer, this); writeHeader(); } protected void subAppend(LoggingEvent event) { this.qw.write(this.layout.format(event)); if (layout.ignoresThrowable()) { String[] s = event.getThrowableStr(); if (s != null) { for (String s1 : s) { this.qw.write(s1); this.qw.write(LINE_SEP); } } } if (shouldFlush(event)) { this.qw.flush(); } } protected void reset() { closeWriter(); this.qw = null; } protected void writeFooter() { if (layout != null) { String f = layout.getFooter(); if (f != null && this.qw != null) { this.qw.write(f); this.qw.flush(); } } } protected void writeHeader() { if (layout != null) { String h = layout.getHeader(); if (h != null && this.qw != null) { this.qw.write(h); } } } protected boolean shouldFlush(final LoggingEvent event) { return event != null && immediateFlush; } }
这个接口定义了writeHeader、writeFooter、append等方法
append方法这里参数是LoggingEvent,内部委托给subAppend
subAppend方法调用layout进行格式化event,然后如果需要flush,则会直接对qw进行flush
FileAppender
org/apache/rocketmq/logging/inner/LoggingBuilder.java
public static class FileAppender extends WriterAppender { protected boolean fileAppend = true; protected String fileName = null; protected boolean bufferedIO = false; protected int bufferSize = 8 * 1024; public FileAppender() { } public FileAppender(Layout layout, String filename, boolean append) throws IOException { this.layout = layout; this.setFile(filename, append, false, bufferSize); } public void setFile(String file) { fileName = file.trim(); } public boolean getAppend() { return fileAppend; } public String getFile() { return fileName; } public void activateOptions() { if (fileName != null) { try { setFile(fileName, fileAppend, bufferedIO, bufferSize); } catch (IOException e) { handleError("setFile(" + fileName + "," + fileAppend + ") call failed.", e, CODE_FILE_OPEN_FAILURE); } } else { SysLogger.warn("File option not set for appender [" + name + "]."); SysLogger.warn("Are you using FileAppender instead of ConsoleAppender?"); } } protected void closeFile() { if (this.qw != null) { try { this.qw.close(); } catch (IOException e) { if (e instanceof InterruptedIOException) { Thread.currentThread().interrupt(); } SysLogger.error("Could not close " + qw, e); } } } public boolean getBufferedIO() { return this.bufferedIO; } public int getBufferSize() { return this.bufferSize; } public void setAppend(boolean flag) { fileAppend = flag; } public void setBufferedIO(boolean bufferedIO) { this.bufferedIO = bufferedIO; if (bufferedIO) { immediateFlush = false; } } public void setBufferSize(int bufferSize) { this.bufferSize = bufferSize; } public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException { SysLogger.debug("setFile called: " + fileName + ", " + append); if (bufferedIO) { setImmediateFlush(false); } reset(); FileOutputStream ostream; try { ostream = new FileOutputStream(fileName, append); } catch (FileNotFoundException ex) { String parentName = new File(fileName).getParent(); if (parentName != null) { File parentDir = new File(parentName); if (!parentDir.exists() && parentDir.mkdirs()) { ostream = new FileOutputStream(fileName, append); } else { throw ex; } } else { throw ex; } } Writer fw = createWriter(ostream); if (bufferedIO) { fw = new BufferedWriter(fw, bufferSize); } this.setQWForFiles(fw); this.fileName = fileName; this.fileAppend = append; this.bufferedIO = bufferedIO; this.bufferSize = bufferSize; writeHeader(); SysLogger.debug("setFile ended"); } protected void setQWForFiles(Writer writer) { this.qw = new QuietWriter(writer, this); } protected void reset() { closeFile(); this.fileName = null; super.reset(); } }
写文件,这里定义了bufferSize为8 * 1024,如果开启bufferedIO,则创建的是BufferedWriter
setQWForFiles方法根据指定的writer创建了QuietWriter
setFile方法设置了qw之后,就直接writeHeader
QuietWriter
org/apache/rocketmq/logging/inner/LoggingBuilder.java
private static class QuietWriter extends FilterWriter { protected Appender appender; public QuietWriter(Writer writer, Appender appender) { super(writer); this.appender = appender; } public void write(String string) { if (string != null) { try { out.write(string); } catch (Exception e) { appender.handleError("Failed to write [" + string + "].", e, Appender.CODE_WRITE_FAILURE); } } } public void flush() { try { out.flush(); } catch (Exception e) { appender.handleError("Failed to flush writer,", e, Appender.CODE_FLUSH_FAILURE); } } }
QuietWriter继承自jdk的FilterWriter,实现了write(String)方法,重写了flush方法
FilterWriter实现了write(int c),write(char cbuf[], int off, int len),write(String str, int off, int len)方法,用于对字符串进行过滤
作者:go4it
链接:https://www.jianshu.com/p/ab96bec4f8f6