使用log4j实现保留N天内的日志

由于项目后期要根据日志进行查找原因,然后服务器的磁盘空间有限,不能永久保留日志,而且日志文件也会随着时间的推移变的越来越大.


于是需要保留一个月或者半个月的日志,但是log4j源码org.apache.log4j.DailyRollingFileAppender并不能完美的实现,


只能自己重写log4j的org.apache.log4j.DailyRollingFileAppender  以下是改写后的源码

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";

	private int  maxBackupIndex  = 1;

	private String scheduledFilename;

	/**
	 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 int getMaxBackupIndex() {
		return maxBackupIndex;
	}

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

	/**
	 * 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);
			File file = new File(fileName);
			scheduledFilename = fileName+sdf.format(new Date(file.lastModified()));
		} else {
			LogLog.error("Either File or DatePattern options are not set for appender ["+name+"].");
		}
	}

	/**
	 * 根据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(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);
				//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;
		}

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

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

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

		File target= new File(scheduledFilename);
		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);
	}
}

/**
 * 文件过滤器
 *
 * @author Mike.Peng
 * @time Jan 12, 2016  5:28:31 PM
 */
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的内部类
 * 提供周期类型和当前时间 ,计算并返回下一个周期的开始时间
 *
 * @author Mike.Peng
 * @time Jan 12, 2016  5:28:48 PM
 */
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();
	}
}

  然后是配置log4j.properties文件

log4j.rootLogger=DEBUG,D,consol

log4j.appender.consol=org.apache.log4j.ConsoleAppender
log4j.appender.consol.layout=org.apache.log4j.PatternLayout
log4j.appender.consol.Threshold = debug
log4j.appender.consol.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} - [ %p ]  %m%n
# cm.sh.lx.acc.util.CustomDailyRollingFileAppender
# org.apache.log4j.DailyRollingFileAppender
log4j.appender.D = cm.sh.lx.acc.util.CustomDailyRollingFileAppender
log4j.appender.D.File =${user.dir}/../uamlogs/ctg_applog_.log
log4j.appender.D.datePattern = yyyy-MM-dd-HH'.'
log4j.appender.D.maxBackupIndex=48
log4j.appender.D.Append = true
log4j.appender.D.Threshold = info
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern =%-d{yyyyMMddHHmmss:S}%m%n

log4j.logger.org.springframework=WARN
log4j.logger.com.ctg=info
log4j.logger.org.apache=WARN
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

maxBackupIndex就是保留多少个文件,  我是按照每小时进行生成一个文件,这样一天24个小时,你想保留几天的就设置这个参数即可.



以下是文件下载地址:

http://download.csdn.net/download/qq_38665235/10199861



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值