1

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

        }
    }
  • 这里重写了subAppend方法,调用父类subAppend方法之后,判断是否需要rollOver
  • 这里定义了maxFileSize,即单个文件的大小,然后还定义了nextRollover索引
  • 这里使用的是CountingQuietWriter,里头有个count来累积计算字符串的长度

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);
                }
            }
        }
  • 这个方法首先更新nextRollover的值,然后根据maxBackupIndex来递增重命名文件,然后再把现有的文件重名为为.1后缀
  • 重命名成功之后,再对新的文件进行setFile相关设置,关联writer,写入header

小结

RollingFileAppender在每次append的时候,都会先append数据,然后再判断是否超出文件大小限制,超出了再执行rollOver操作,对既有文件进行重命名,然后重新生成新的文件。注意这里没有进行同步操作,因此需要最外层调用的方法有同步并发控制。

doc


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...


引用和评论

0 条评论