Talk about DailyRollingFileAppender of rocketmq

  mq

Order

This article mainly studies DailyRollingFileAppender of rocketmq.

DailyRollingFileAppender

org/apache/rocketmq/logging/inner/LoggingBuilder.java

   public static class DailyRollingFileAppender extends FileAppender {

        static final int TOP_OF_TROUBLE = -1;
        static final int TOP_OF_MINUTE = 0;
        static final int TOP_OF_HOUR = 1;
        static final int HALF_DAY = 2;
        static final int TOP_OF_DAY = 3;
        static final int TOP_OF_WEEK = 4;
        static final int TOP_OF_MONTH = 5;


        /**
         * The date pattern. By default, the pattern is set to
         * "'.'yyyy-MM-dd" meaning daily rollover.
         */
        private String datePattern = "'.'yyyy-MM-dd";

        private String scheduledFilename;

        private long nextCheck = System.currentTimeMillis() - 1;

        Date now = new Date();

        SimpleDateFormat sdf;

        RollingCalendar rc = new RollingCalendar();

        final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");


        public void setDatePattern(String pattern) {
            datePattern = pattern;
        }

        public String getDatePattern() {
            return datePattern;
        }

        public void activateOptions() {
            super.activateOptions();
            if (datePattern != null && fileName != null) {
                now.setTime(System.currentTimeMillis());
                sdf = new SimpleDateFormat(datePattern);
                int type = computeCheckPeriod();
                printPeriodicity(type);
                rc.setType(type);
                File file = new File(fileName);
                scheduledFilename = fileName + sdf.format(new Date(file.lastModified()));

            } else {
                SysLogger.error("Either File or DatePattern options are not set for appender [" + name + "].");
            }
        }

        void printPeriodicity(int type) {
            switch (type) {
                case TOP_OF_MINUTE:
                    SysLogger.debug("Appender [" + name + "] to be rolled every minute.");
                    break;
                case TOP_OF_HOUR:
                    SysLogger.debug("Appender [" + name + "] to be rolled on top of every hour.");
                    break;
                case HALF_DAY:
                    SysLogger.debug("Appender [" + name + "] to be rolled at midday and midnight.");
                    break;
                case TOP_OF_DAY:
                    SysLogger.debug("Appender [" + name + "] to be rolled at midnight.");
                    break;
                case TOP_OF_WEEK:
                    SysLogger.debug("Appender [" + name + "] to be rolled at start of week.");
                    break;
                case TOP_OF_MONTH:
                    SysLogger.debug("Appender [" + name + "] to be rolled at start of every month.");
                    break;
                default:
                    SysLogger.warn("Unknown periodicity for appender [" + name + "].");
            }
        }

        int computeCheckPeriod() {
            RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault());
            // set sate to 1970-01-01 00:00:00 GMT
            Date epoch = new Date(0);
            if (datePattern != null) {
                for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
                    simpleDateFormat.setTimeZone(gmtTimeZone);
                    String r0 = simpleDateFormat.format(epoch);
                    rollingCalendar.setType(i);
                    Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));
                    String r1 = simpleDateFormat.format(next);
                    if (r0 != null && r1 != null && !r0.equals(r1)) {
                        return i;
                    }
                }
            }
            return TOP_OF_TROUBLE;
        }

        void rollOver() throws IOException {

            if (datePattern == null) {
                handleError("Missing DatePattern option in rollOver().");
                return;
            }

            String datedFilename = fileName + sdf.format(now);

            if (scheduledFilename.equals(datedFilename)) {
                return;
            }
            this.closeFile();

            File target = new File(scheduledFilename);
            if (target.exists() && !target.delete()) {
                SysLogger.error("Failed to delete [" + scheduledFilename + "].");
            }

            File file = new File(fileName);
            boolean result = file.renameTo(target);
            if (result) {
                SysLogger.debug(fileName + " -> " + scheduledFilename);
            } else {
                SysLogger.error("Failed to rename [" + fileName + "] to [" + scheduledFilename + "].");
            }

            try {
                this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
            } catch (IOException e) {
                handleError("setFile(" + fileName + ", true) call failed.");
            }
            scheduledFilename = datedFilename;
        }

        protected void subAppend(LoggingEvent event) {
            long n = System.currentTimeMillis();
            if (n >= nextCheck) {
                now.setTime(n);
                nextCheck = rc.getNextCheckMillis(now);
                try {
                    rollOver();
                } catch (IOException ioe) {
                    if (ioe instanceof InterruptedIOException) {
                        Thread.currentThread().interrupt();
                    }
                    SysLogger.error("rollOver() failed.", ioe);
                }
            }
            super.subAppend(event);
        }
    }
  • The subAppend method is rewritten here. first, check whether the current time is greater than the nextCheck value. if it is greater than the nextCheck value, update the nextcheck value. then, perform the rollOver operation. finally, call the subAppend method of the parent class.
  • The rollOver method first checks whether the datedFilename is equal to the scheduledFilename, if not, renames it, then calls the FileAppender’s setFile operation, and finally updates the scheduledFilename value

Summary

  • The implementation of rocketmq’s DailyRollingFileAppender is to rewrite subAppend, check whether the file needs to be renamed before each subAppend, and call the rollOver method if necessary.
  • The rollOver method mainly renames the file name as scheduledFilename, and the format of datePattern is. yyy-mm-dd

doc