order
This paper focuses on rocketmq's RollingFileAppender
RollingFileAppender
org/apache/rocketmq/logging/inner/LoggingBuilder.java
public static class RollingFileAppender extends FileAppender { protected long maxFileSize = 10 * 1024 * 1024; protected int maxBackupIndex = 1; private long nextRollover = 0; public RollingFileAppender() { super(); } public int getMaxBackupIndex() { return maxBackupIndex; } public long getMaximumFileSize() { return maxFileSize; } //...... public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException { super.setFile(fileName, append, this.bufferedIO, this.bufferSize); if (append) { File f = new File(fileName); ((CountingQuietWriter) qw).setCount(f.length()); } } public void setMaxBackupIndex(int maxBackups) { this.maxBackupIndex = maxBackups; } public void setMaximumFileSize(long maxFileSize) { this.maxFileSize = maxFileSize; } protected void setQWForFiles(Writer writer) { this.qw = new CountingQuietWriter(writer, this); } protected void subAppend(LoggingEvent event) { super.subAppend(event); if (fileName != null && qw != null) { long size = ((CountingQuietWriter) qw).getCount(); if (size >= maxFileSize && size >= nextRollover) { rollOver(); } } } protected class CountingQuietWriter extends QuietWriter { protected long count; public CountingQuietWriter(Writer writer, Appender appender) { super(writer, appender); } public void write(String string) { try { out.write(string); count += string.length(); } catch (IOException e) { appender.handleError("Write failure.", e, Appender.CODE_WRITE_FAILURE); } } public long getCount() { return count; } public void setCount(long count) { this.count = count; } } }
- Here, the subAppend method is overridden. After calling the parent subAppend method, judge whether rollOver is required
- Here we define maxFileSize, the size of a single file, and then we define the nextRollover index
- Here we use the CountingQuietWriter. There is a count in it to accumulate the length of the calculated string
RollingFileAppender.rollOver
org/apache/rocketmq/logging/inner/LoggingBuilder.java
public void rollOver() { File target; File file; if (qw != null) { long size = ((CountingQuietWriter) qw).getCount(); SysLogger.debug("rolling over count=" + size); nextRollover = size + maxFileSize; } SysLogger.debug("maxBackupIndex=" + maxBackupIndex); boolean renameSucceeded = true; if (maxBackupIndex > 0) { file = new File(fileName + '.' + maxBackupIndex); if (file.exists()) { renameSucceeded = file.delete(); } for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) { file = new File(fileName + "." + i); if (file.exists()) { target = new File(fileName + '.' + (i + 1)); SysLogger.debug("Renaming file " + file + " to " + target); renameSucceeded = file.renameTo(target); } } if (renameSucceeded) { target = new File(fileName + "." + 1); this.closeFile(); // keep windows happy. file = new File(fileName); SysLogger.debug("Renaming file " + file + " to " + target); renameSucceeded = file.renameTo(target); if (!renameSucceeded) { try { this.setFile(fileName, true, bufferedIO, bufferSize); } catch (IOException e) { if (e instanceof InterruptedIOException) { Thread.currentThread().interrupt(); } SysLogger.error("setFile(" + fileName + ", true) call failed.", e); } } } } if (renameSucceeded) { try { this.setFile(fileName, false, bufferedIO, bufferSize); nextRollover = 0; } catch (IOException e) { if (e instanceof InterruptedIOException) { Thread.currentThread().interrupt(); } SysLogger.error("setFile(" + fileName + ", false) call failed.", e); } } }
- This method first updates the value of nextRollover, then incrementally renames the file according to maxBackupIndex, and then renames the existing file to. 1 suffix
- After the Rename is successful, set the new file to the related settings of setFile, associate with the writer, and write to the header
Summary
RollingFileAppender will append the data first, and then judge whether it exceeds the file size limit. If it exceeds the limit, rollOver will be performed. Rename the existing file, and then regenerate the new file. Note that there is no synchronization operation here, so the methods that need to be called at the outermost layer have synchronization and concurrency control.