重写log4j.jar中的DailyRollingFileAppender.java,实现按月保存日志,或者保留一定个数或者保留几个月的日志

一般来说,log4j.jar中提供的日志都是按天保存,并且当天第一次启动项目,去生成前一天的日志,并且Info和error日志信息都保存在一起,对于日志都没有分类,不好管理与查看;
       现如今重写 log4j.jar中的DailyRollingFileAppender.java,让日志按照自己约定的方式,满足客户的需求;
       重写的类名更改为:CustomDailyRollingFileAppender.java

日志生成要求:
第一种方式: 日志按天生成,按月保存到一个文件夹中,日志文件保留期限为3-4个月,超过时间则删除以前的日志;
第二种方式:根据log.properties中配置的保存数量进行清除超出的日志;
文件下载地址:https://download.csdn.net/download/su1573/10930807

log.properties:

log4j.rootLogger=INFO,CONSOLE,D,R
log4j.addivity.org.apache=false

####控制台######
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=INFO
log4j.appender.CONSOLE.layout.ConversionPattern= %d{yyyy-MM-dd HH\:mm\:ss} %5p [%c] (%L) - %m%n
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.Encoding=gbk
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout

####文件#####
#log4j.appender.A=org.apache.log4j.DailyRollingFileAppender  
#log4j.appender.A.File=${catalina.home}/logs/opension-back
#log4j.appender.A.DatePattern=yyyy-MM-dd'.log'
#log4j.appender.A.layout=org.apache.log4j.PatternLayout  
#log4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss} %5p [%c] (%L) - %m%n

##日志信息测试按天生成,有效期最低3个月,最多4个月
log4j.appender.D = com.sinosoft.utils.CustomDailyRollingFileAppender
log4j.appender.D.File =${catalina.home}/logs/opension-back
log4j.appender.D.datePattern = yyyy-MM-dd'.log'
log4j.appender.D.Append = true
log4j.appender.D.Threshold = info
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern =%d{yyyy-MM-dd HH\:mm\:ss} %5p [%c] (%L) - %m%n

##错误日志文件
log4j.appender.R = com.sinosoft.utils.CustomDailyRollingFileAppender
log4j.appender.R.File =${catalina.home}/logs/opension-back-error
log4j.appender.R.datePattern = yyyy-MM-dd'.log'
log4j.appender.R.Append = true
log4j.appender.R.Threshold = error
log4j.appender.R.layout = org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern =%d{yyyy-MM-dd HH\:mm\:ss} %5p [%c] (%L) - %m%n


代码如下:

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sinosoft.utils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;

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

/**
 * method:
 * Description:日志生成规则
 * author:sph
 * return
 */
public class CustomDailyRollingFileAppender 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;
    
    

    /**
     * 默认设置:"'.'yyyy-MM-dd"
     * 设置说明:按天循环打印日志
     */
    private String datePattern = "'.'yyyy-MM-dd";
    static  String logName   = "";
    static  String logTime  = "";

    private int  maxBackupIndex  = 1;

    private String scheduledFilename;
    private String logFilename;
    
    private static Date lastmodfiyTimeDate;  //文件上一次修改时间
    private static Date CreateTimeDate;      //文件创建时间
    private  String filePath = "";      //文件创建时间
    

    /**
     The next time we estimate a rollover should occur. */
    private long nextCheck = System.currentTimeMillis () - 1;

    Date now = new Date();

    SimpleDateFormat sdf;

    RollingCalendar rc = new RollingCalendar();

    int checkPeriod = TOP_OF_TROUBLE;

    /**
     * 获取当前环境所处的时区
     * 仅供computeCheckPeriod方法使用
     */
    static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");

    public CustomDailyRollingFileAppender() {}

    public CustomDailyRollingFileAppender(Layout layout, String filename, String datePattern) throws IOException {
        super(layout, filename, true);

        this.datePattern = datePattern;
        activateOptions();
    }

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

    public String getDatePattern() {
        return datePattern;
    }
    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }
    
    public String getFilePath() {
        return filePath;
    }

    public int getMaxBackupIndex() {
        return maxBackupIndex;
    }

    public void setMaxBackupIndex(int maxBackupIndex) {
        this.maxBackupIndex = maxBackupIndex;
    }

    public static Date getLastmodfiyTimeDate() {
        return lastmodfiyTimeDate;
    }

    public static void setLastmodfiyTimeDate(Date lastmodfiyTimeDate) {
        CustomDailyRollingFileAppender.lastmodfiyTimeDate = lastmodfiyTimeDate;
    }

    public static Date getCreateTimeDate() {
        return CreateTimeDate;
    }

    public static void setCreateTimeDate(Date createTimeDate) {
        CreateTimeDate = createTimeDate;
    }

    /**
     * activateOptions译名为激活操作
     * 意思是按照配置的参数进行初始化
     * scheduledFilename为log的最后一次修改时间
     */
    @Override
    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);
            Properties getProperties = PropertyUitls.getProperties("config.properties");
            String logFileDirExt =getProperties.getProperty("logFileDirExt");
            String openBack =getProperties.getProperty("openBack");  //opension-back
            String openBackError =getProperties.getProperty("openBackError");  //opension-back-error
            
            if(fileName.contains(openBack)) {
                logName = openBack;
            }
            if(fileName.contains(openBackError)) {
                logName = openBackError;
            }
            filePath = fileName.substring(0,fileName.indexOf(logName));
            removeOutTimeDir(filePath);  //删除过期的目录
            
            File file = new File(fileName);
            
            String lastDate = new SimpleDateFormat("yyyyMM").format(new Date(file.lastModified()));
            String nowDate = new SimpleDateFormat("yyyyMM").format(new Date());
            try {
                Date lastD = new SimpleDateFormat("yyyyMM").parse(lastDate);
                Date nowD = new SimpleDateFormat("yyyyMM").parse(nowDate);
                if(nowD.after(lastD)) {  //判断当前月是否在上一次文件修改月后面
                    logTime = lastDate;//是的话,文件日期去上个月
                }else {
                    logTime = nowDate; //不是的话,文件日期取当月
                }
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            
            String front = logTime+"-"+logFileDirExt;
            String logDir = filePath+front;  //到当前日期
            File fileDir = new File(logDir);
            if(!fileDir.exists()) {
                fileDir.mkdir();
            }
            
//            //新方法,取出创建日期
//            Path path = Paths.get(fileName);
//            BasicFileAttributeView basicview = Files.getFileAttributeView(path, BasicFileAttributeView.class,
//                    LinkOption.NOFOLLOW_LINKS);
//            BasicFileAttributes attr;
//            try {
//                attr = basicview.readAttributes();
//                lastmodfiyTimeDate=new Date(attr.lastModifiedTime().toMillis());
//                CreateTimeDate= new Date(attr.creationTime().toMillis());  //文件创建日期
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
            
            scheduledFilename = fileName+sdf.format(new Date(file.lastModified()));
//            scheduledFilename = logDir+File.separator+logName+sdf.format(new Date(file.lastModified()));
            logFilename = logDir+File.separator+logName+sdf.format(new Date(file.lastModified()));   //重新命名
        } else {
            LogLog.error("Either File or DatePattern options are not set for appender ["+name+"].");
        }
    }
    
    /**
     * 先根遍历序递归删除文件夹
     *
     * @param dirFile 要被删除的文件或者目录
     * @return 删除成功返回true, 否则返回false
     */
    public  boolean deleteFile(File dirFile) {
        // 如果dir对应的文件不存在,则退出
        if (!dirFile.exists()) {
            return false;
        }
        if (dirFile.isFile()) {
            return dirFile.delete();
        } else {
            for (File file : dirFile.listFiles()) {
                deleteFile(file);
            }
        }
        return dirFile.delete();
    }
    
    /*
     * 删除过期的日志目录
     */
    public void removeOutTimeDir(String filePath) {
        try {
            File path = new File(filePath);
            String[] parr = path.list();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
            Date today = new SimpleDateFormat("yyyyMM").parse(sdf.format(new Date()));
            for (String pf : parr) {
                if (pf.endsWith("logmes")) {
                    Date ffd = new SimpleDateFormat("yyyyMM").parse(pf.substring(0, 6));
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(ffd);
                    calendar.add(Calendar.MONTH, 4);// 增加4个月
                    Date addThrDate = calendar.getTime();
                    if (addThrDate.equals(today)) {
                        File reFile = new File(filePath + pf);
                        deleteFile(reFile); // 删除需要过期的目录
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 根据type打印做出日志打印
     * @param type
     */
    void printPeriodicity(int type) {
        switch(type) {
            case TOP_OF_MINUTE:
                LogLog.debug("Appender ["+name+"] to be rolled every minute.");
                break;
            case TOP_OF_HOUR:
                LogLog.debug("Appender ["+name+"] to be rolled on top of every hour.");
                break;
            case HALF_DAY:
                LogLog.debug("Appender ["+name+"] to be rolled at midday and midnight.");
                break;
            case TOP_OF_DAY:
                LogLog.debug("Appender ["+name+"] to be rolled at midnight.");
                break;
            case TOP_OF_WEEK:
                LogLog.debug("Appender ["+name+"] to be rolled at start of week.");
                break;
            case TOP_OF_MONTH:
                LogLog.debug("Appender ["+name+"] to be rolled at start of every month.");
                break;
            default:
                LogLog.warn("Unknown periodicity for appender ["+name+"].");
        }
    }


//   This method computes the roll over period by looping over the
//   periods, starting with the shortest, and stopping when the r0 is
//   different from from r1, where r0 is the epoch formatted according
//   the datePattern (supplied by the user) and r1 is the
//   epoch+nextMillis(i) formatted according to datePattern. All date
//   formatting is done in GMT and not local format because the test
//   logic is based on comparisons relative to 1970-01-01 00:00:00
//   GMT (the epoch).

    int computeCheckPeriod() {
        RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault());
        //设置初始时间为格林尼治时间:1970-01-01 00:00:00 GMT
        Date epoch = new Date(0L);
        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);
//                System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);
                if(r0 != null && r1 != null && !r0.equals(r1)) {
                    return i;
                }
            }
        }
        return TOP_OF_TROUBLE; // Deliberately head for trouble...
    }

    /**
     * 按照周期将当前日志文件转存为日期文件
     *
     * @throws IOException
     */
    void rollOver() throws IOException {

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

        /*//文件创建日期 加三个月后与当期日期比较 ------------
        Calendar calendar = Calendar.getInstance();

        calendar.setTime(CreateTimeDate);

        calendar.add(Calendar.MONTH, 3);//增加3个月
        
        Date addThrDate = calendar.getTime();  //三个月后的日期  比如:Thu Jan 17 15:03:37 CST 2019  -> Wed Apr 17 15:03:37 CST 2019
        File target= new File(scheduledFilename);  //D:/logs/opension-back.log2019-01-14
        if(now.before(addThrDate)) {  //日志未到3月期限,直接返回
            return;
        }else {   //日志刚到三月   比如 3月1 - 6月1  ,则关闭此文件
            // 关闭当前文件,重命名为日期文件
            this.closeFile();
            File file = new File(fileName);  //D:\logs\opension-back.log
            boolean result = file.renameTo(target);
            
            //-------------------------------------------------------
            if(result) {
                target.delete();  //删除目标文件
                LogLog.debug(fileName +" -> "+ scheduledFilename);
            } else {
                LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
            }
        }*/
        
        

        String datedFilename = fileName+sdf.format(now);  //原先的 通过时区取时间
        
        //通过测试取时间
//        Date dd = new Date();
//        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd'.log'");
//        String datedFilename = fileName+sdf1.format(dd);  //sph新加的  可以修改电脑时间  测试

        //如果最后一次的修改时间为当前时间 ,则不做任何任何操作
        if (scheduledFilename.equals(datedFilename)) {
            return;
        }

        // 关闭当前文件,重命名为日期文件
        this.closeFile();

        File target= new File(logFilename);  //更改后的日期文件夹里面的文件名  全路径D:\logs\201904-logmes\opension-back201904.log
        if (target.exists()) {
            target.delete();
        }

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

        //获取日志文件列表,控制数量,实现清理策略
        /*if (file.getParentFile().exists()){
            File[] files = file.getParentFile().listFiles(new LogFileFilter(file.getName()));
            Long[] dateArray = new Long[files.length];
            for (int i = 0; i < files.length; i++) {
                File fileItem = files[i];
                String fileDateStr = fileItem.getName().replace(file.getName(), "");
                Date filedate = null;
                try {
                    filedate = sdf.parse(fileDateStr);
                    long fileDateLong = filedate.getTime();
                    dateArray[i] = fileDateLong;
                } catch (ParseException e) {
                    LogLog.error("Parse File Date Throw Exception : " + e.getMessage());
                }
            }
            Arrays.sort(dateArray);
            if (dateArray.length > maxBackupIndex) {
                for (int i = 0; i < dateArray.length - maxBackupIndex; i++) {
                    String dateFileName = file.getPath() + sdf.format(dateArray[i]);
                    File dateFile = new File(dateFileName);
                    if (dateFile.exists()) {
                        dateFile.delete();
                    }
                }
            }
        }*/

        try {
            // This will also close the file. This is OK since multiple close operations are safe.
            this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
        }
        catch(IOException e) {
            errorHandler.error("setFile("+fileName+", true) call failed.");
        }
//        scheduledFilename = datedFilename;
    }

    /**
     * 写入日志之前判断是否需要新起一个日志来记录
     */
    @Override
    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();
                }
                LogLog.error("rollOver() failed.", ioe);
            }
        }
        super.subAppend(event);
    }
}

/**
 * 文件过滤器
 *
 */
class LogFileFilter implements FileFilter {
    private String logName;

    public LogFileFilter(String logName) {
        this.logName = logName;
    }

    @Override
    public boolean accept(File file) {
        if (logName == null || file.isDirectory()) {
            return false;
        } else {
            LogLog.debug(file.getName());
            return file.getName().startsWith(logName);
        }
    }
}

/**
 * CustomDailyRollingFileAppender的内部类
 * 提供周期类型和当前时间 ,计算并返回下一个周期的开始时间
 *
 */
class RollingCalendar extends GregorianCalendar {
    private static final long serialVersionUID = -3560331770601814177L;

    int type = CustomDailyRollingFileAppender.TOP_OF_TROUBLE;

    /**
     * RollingCalendar默认构造器
     */
    RollingCalendar() {
        super();
    }

    /**
     * RollingCalendar构造器
     * 根据地点时区 ,获取对应的日历Calendar
     * @param tz
     * @param locale
     */
    RollingCalendar(TimeZone tz, Locale locale) {
        super(tz, locale);
    }

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

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

    /**
     * 根据所传入的时间以及时间类型获取下一个时间
     * @param now
     * @return
     */
    public Date getNextCheckDate(Date now) {
        this.setTime(now);

        switch(type) {
            case CustomDailyRollingFileAppender.TOP_OF_MINUTE:
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.MINUTE, 1);
                break;
            case CustomDailyRollingFileAppender.TOP_OF_HOUR:
                this.set(Calendar.MINUTE, 0);
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.HOUR_OF_DAY, 1);
                break;
            case CustomDailyRollingFileAppender.HALF_DAY:
                this.set(Calendar.MINUTE, 0);
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                int hour = get(Calendar.HOUR_OF_DAY);
                if(hour < 12) {
                    this.set(Calendar.HOUR_OF_DAY, 12);
                } else {
                    this.set(Calendar.HOUR_OF_DAY, 0);
                    this.add(Calendar.DAY_OF_MONTH, 1);
                }
                break;
            case CustomDailyRollingFileAppender.TOP_OF_DAY:
                this.set(Calendar.HOUR_OF_DAY, 0);
                this.set(Calendar.MINUTE, 0);
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.DATE, 1);
                break;
            case CustomDailyRollingFileAppender.TOP_OF_WEEK:
                this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
                this.set(Calendar.HOUR_OF_DAY, 0);
                this.set(Calendar.MINUTE, 0);
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.WEEK_OF_YEAR, 1);
                break;
            case CustomDailyRollingFileAppender.TOP_OF_MONTH:
                this.set(Calendar.DATE, 1);
                this.set(Calendar.HOUR_OF_DAY, 0);
                this.set(Calendar.MINUTE, 0);
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.MONTH, 1);
                break;
            default:
                throw new IllegalStateException("Unknown periodicity type.");
        }
        return getTime();
    }
    
}


    
原文:https://blog.csdn.net/su1573/article/details/86582678

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值