log4j按小时输出日志,并且限制日志保存的天数

最近做项目的时候,遇到了日志的输出问题。我们想按小时输出日志,同时最多保存7天的日志。log4j本身自带的appender如下:

org.apache.log4j.ConsoleAppender 输出到控制台

org.apache.log4j.FileAppender 输出到文件

org.apache.log4j.DailyRollingFileAppender 

org.apache.log4j.RollingFileAppender 文件大小到达指定尺寸的时候产生一个新的文件

按小时输出可以使用DailRollingFileAppender,但是这个类没法限制文件的数量。如果继承该类,该类输出日志的方法rollover是default,无法重写。参考了其他博主的思路,DailRollingFileAppender继承了FileAppender,我们可以自己写一个类,继承FileAppender,代码还是用DailRollingFileAppender的代码,在其中添加限制文件保存天数的方法。

CustomLogAppender 类代码如下:

import org.apache.log4j.FileAppender;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.text.SimpleDateFormat;
import java.util.*;

import org.apache.log4j.Layout;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;

/**
 * @author 
 * @date 2018/10/30 16:41
 * 按小时滚动日志,指定保存的时间,删除超出时间的日志
 */
public class CustomLogAppender 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;
    private String datePattern = "'.'yyyy-MM-dd";
    private String scheduledFilename;
    /** 最多保存天数,默认七天 */
    private int maxBackupIndex = 7;
    private long nextCheck = System.currentTimeMillis() - 1L;
    Date now = new Date();
    SimpleDateFormat sdf;
    SimpleDateFormat newSdf = new SimpleDateFormat("'.'yyyy-MM-dd");
    RollingCalendar rc = new RollingCalendar();
    int checkPeriod = -1;
    static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");

    public CustomLogAppender() {
    }

    public CustomLogAppender(Layout layout, String filename, String datePattern) throws IOException {
        super(layout, filename, true);
        this.datePattern = datePattern;
        this.activateOptions();
    }

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

    public String getDatePattern() {
        return this.datePattern;
    }

    public void activateOptions() {
        super.activateOptions();
        if (this.datePattern != null && this.fileName != null) {
            this.now.setTime(System.currentTimeMillis());
            this.sdf = new SimpleDateFormat(this.datePattern);
            int type = this.computeCheckPeriod();
            this.printPeriodicity(type);
            this.rc.setType(type);
            File file = new File(this.fileName);
            this.scheduledFilename = this.fileName + this.sdf.format(new Date(file.lastModified()));
        } else {
            LogLog.error("Either File or DatePattern options are not set for appender [" + this.name + "].");
        }

    }

    void printPeriodicity(int type) {
        switch(type) {
            case 0:
                LogLog.debug("Appender [" + this.name + "] to be rolled every minute.");
                break;
            case 1:
                LogLog.debug("Appender [" + this.name + "] to be rolled on top of every hour.");
                break;
            case 2:
                LogLog.debug("Appender [" + this.name + "] to be rolled at midday and midnight.");
                break;
            case 3:
                LogLog.debug("Appender [" + this.name + "] to be rolled at midnight.");
                break;
            case 4:
                LogLog.debug("Appender [" + this.name + "] to be rolled at start of week.");
                break;
            case 5:
                LogLog.debug("Appender [" + this.name + "] to be rolled at start of every month.");
                break;
            default:
                LogLog.warn("Unknown periodicity for appender [" + this.name + "].");
        }

    }

    int computeCheckPeriod() {
        RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault());
        Date epoch = new Date(0L);
        if (this.datePattern != null) {
            for(int i = 0; i <= 5; ++i) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat(this.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 -1;
    }

    void rollOver() throws IOException {
        if (this.datePattern == null) {
            this.errorHandler.error("Missing DatePattern option in rollOver().");
        } else {
            String datedFilename = this.fileName + this.sdf.format(this.now);
            if (!this.scheduledFilename.equals(datedFilename)) {
                this.closeFile();
                File target = new File(this.scheduledFilename);
                if (target.exists()) {
                    target.delete();
                }

                File file = new File(this.fileName);
                boolean result = file.renameTo(target);
                if (result) {
                    LogLog.debug(this.fileName + " -> " + this.scheduledFilename);
                } else {
                    LogLog.error("Failed to rename [" + this.fileName + "] to [" + this.scheduledFilename + "].");
                }
                // 删除过期文件
                if (maxBackupIndex > 0) {
                    File folder = new File(file.getParent());
                    List<String> maxBackupIndexDates = getMaxBackupIndexDates();
                    for (File ff : folder.listFiles()) {
                        // 遍历目录,将日期不在备份范围内的日志删掉
                        if (ff.getName().startsWith(file.getName()) && !ff.getName().equals(file.getName())) {
                            // 获取文件名带的日期时间戳
                            String marked = ff.getName().substring( file.getName().length());
                            String markedDate = marked.substring(0,marked.lastIndexOf("-"));
                            if (!maxBackupIndexDates.contains(markedDate)) {
                                result = ff.delete();
                            }
                            if (result) {
                                LogLog.debug(ff.getName() + " -> deleted ");
                            } else {
                                LogLog.error("Failed to deleted old DayRollingFileAppender file :" + ff.getName());
                            }
                        }
                    }
                }
                try {
                    this.setFile(this.fileName, true, this.bufferedIO, this.bufferSize);
                } catch (IOException var6) {
                    this.errorHandler.error("setFile(" + this.fileName + ", true) call failed.");
                }

                this.scheduledFilename = datedFilename;
            }

        }
    }
    /**
     * 根据maxBackupIndex配置的保存天数,获取要保留log文件的日期范围集合
     * @return list<'fileName+yyyy-MM-dd'>
     */
    List<String> getMaxBackupIndexDates() {
        List<String> result = new ArrayList<String>();
        if (maxBackupIndex > 0) {
            for (int i = 0; i < maxBackupIndex; i++) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date(System.currentTimeMillis()));
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                calendar.set(Calendar.MILLISECOND, 0);

                // 注意MILLISECOND,毫秒也要置0...否则错了也找不出来的
                calendar.add(Calendar.DATE, -i);
                result.add(newSdf.format(calendar.getTime()));
            }
        }
        return result;
    }

    protected void subAppend(LoggingEvent event) {
        long n = System.currentTimeMillis();
        if (n >= this.nextCheck) {
            this.now.setTime(n);
            this.nextCheck = this.rc.getNextCheckMillis(this.now);

            try {
                this.rollOver();
            } catch (IOException var5) {
                if (var5 instanceof InterruptedIOException) {
                    Thread.currentThread().interrupt();
                }

                LogLog.error("rollOver() failed.", var5);
            }
        }

        super.subAppend(event);
    }

    public int getMaxBackupIndex() {
        return maxBackupIndex;
    }

    public void setMaxBackupIndex(int maxBackupIndex) {
        this.maxBackupIndex = maxBackupIndex;
    }
}
//这个类是org.apache.log4j里的私有类,外类无法引用,所以我在这里完全copy了出来
class RollingCalendar extends GregorianCalendar {
    //private static final long serialVersionUID = -3560331770601814177L;
    int type = -1;

    RollingCalendar() {
    }

    RollingCalendar(TimeZone tz, Locale locale) {
        super(tz, locale);
    }

    void setType(int type) {
        this.type = type;
    }

    public long getNextCheckMillis(Date now) {
        return this.getNextCheckDate(now).getTime();
    }

    public Date getNextCheckDate(Date now) {
        this.setTime(now);
        switch(this.type) {
            case 0:
                this.set(13, 0);
                this.set(14, 0);
                this.add(12, 1);
                break;
            case 1:
                this.set(12, 0);
                this.set(13, 0);
                this.set(14, 0);
                this.add(11, 1);
                break;
            case 2:
                this.set(12, 0);
                this.set(13, 0);
                this.set(14, 0);
                int hour = this.get(11);
                if (hour < 12) {
                    this.set(11, 12);
                } else {
                    this.set(11, 0);
                    this.add(5, 1);
                }
                break;
            case 3:
                this.set(11, 0);
                this.set(12, 0);
                this.set(13, 0);
                this.set(14, 0);
                this.add(5, 1);
                break;
            case 4:
                this.set(7, this.getFirstDayOfWeek());
                this.set(11, 0);
                this.set(12, 0);
                this.set(13, 0);
                this.set(14, 0);
                this.add(3, 1);
                break;
            case 5:
                this.set(5, 1);
                this.set(11, 0);
                this.set(12, 0);
                this.set(13, 0);
                this.set(14, 0);
                this.add(2, 1);
                break;
            default:
                throw new IllegalStateException("Unknown periodicity type.");
        }

        return this.getTime();
    }
}

然后在log4j.properties里使用这个appender。

log4j.rootLogger=INFO,CONSOLE,day
log4j.appender.day=改类所在路径.CustomLogAppender
log4j.appender.day.File=日志输出路径/日志名.log
log4j.appender.day.Threshold=INFO
#日志的后缀名格式,按小时
log4j.appender.day.DatePattern='.'yyyy-MM-dd-HH
#最多保存7天
log4j.appender.day.MaxBackupIndex=7
log4j.appender.day.Append=true
log4j.appender.day.layout=org.apache.log4j.PatternLayout
log4j.appender.day.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}][%l] %m%n

原文地址:http://www.shanhh.com/set_max_count_of_log_files_for_log4j/

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值