log4j生成的日志同时按大小和日期生成文件,并自动清除过期日志_log4j按日期生成日志-程序员宅基地

技术标签: java  日志时间  java日志  javaDemo  日志大小  log4j  

最近做的项目,遇到了的情境:

1、要每个日志按固定大小生成,超过设定大大小就生成新的日志文件

2、同时在文件名字后面加上日期,并自动按照设置的保留天数保留日志,过期的日志自动删除。

3、设置同一日期最多生成日志数,超过这个数量,则删除今天最老的日志,滚动排序,新生成的日志永远编号最大。

然而,log4j自带的生成日志的几个方法,可以按照日期时间生成日志,也可以按照设置的大小滚动生成日志,就是没有即按照大小生成,又在日志名字后面加上日期,同时又清除过期日志的方法。看了源码,决定综合重新写一个类,实现这些需求。


第一,准备jar  :log4j-1.2.17.jar,commons-logging-1.1.1.jar,这2个就可以了,其他关于日志的jar包就不要加进来了,在优先级上会有冲突。

第二,定义一个类,继承RollingFileAppender类,这个类是按照日志大小滚动生成日志,并把日志编号。我就在这个类基础上重新写了其中的一些方法,加上日期和删除功能,稍加改动就行了。

package log;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;




import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.helpers.LogLog;
public class RoolingAndDateFileAppender extends RollingFileAppender{
	private String datePattern;
	private String dateStr="";//文件后面的日期
	private String expirDays="1";//保留最近几天
	private String isCleanLog="true";
	private String maxIndex="100";
	private File rootDir;
	public void setDatePattern(String datePattern){
		if(null!=datePattern&&!"".equals(datePattern)){
			this.datePattern=datePattern;
		}
	}
	public String getDatePattern(){
		return this.datePattern;
	}
	public void rollOver(){
		dateStr=new SimpleDateFormat(this.datePattern).format(new Date(System.currentTimeMillis()));
		File target = null;
		File file=null;
		if(qw!=null){
			long size=((CountingQuietWriter)this.qw).getCount();
			LogLog.debug("rolling over count="+size);
		}
		LogLog.debug("maxBackupIndex="+this.maxBackupIndex);
		//如果maxIndex<=0则不需命名
		if(maxIndex!=null&&Integer.parseInt(maxIndex)>0){
			//删除旧文件
			file=new File(this.fileName+'.'+dateStr+'.'+Integer.parseInt(this.maxIndex));
			if(file.exists()){
				//如果当天日志达到最大设置数量,则删除当天第一个日志,其他日志为尾号减一
				Boolean boo = reLogNum();
				if(!boo){
					LogLog.debug("日志滚动重命名失败!");
				}
			}
	}
		//获取当天日期文件个数
		int count=cleanLog();
		//生成新文件
		target=new File(fileName+"."+dateStr+"."+(count+1));
		this.closeFile();
		file=new File(fileName);
		LogLog.debug("Renaming file"+file+"to"+target);
		file.renameTo(target);
		try{
			setFile(this.fileName,false,this.bufferedIO,this.bufferSize);
		}catch(IOException e){
			LogLog.error("setFile("+this.fileName+",false)call failed.",e);
		}
	}
	public int cleanLog(){
		int count=0;//记录当天文件个数
		if(Boolean.parseBoolean(isCleanLog)){
			File f=new File(fileName);
			rootDir=f.getParentFile();
			File[] listFiles = rootDir.listFiles();
			for(File file:listFiles){
				if(file.getName().contains(dateStr)){
					count=count+1;//是当天日志,则+1
				}else{
					if(Boolean.parseBoolean(isCleanLog)){
						//清除过期日志
						String[] split=file.getName().split("\\\\")[0].split("\\.");
						//校验日志名字,并取出日期,判断过期时间
						if(split.length==4 && isExpTime(split[2])){
							file.delete();
					}
				}
				}
			}
		}
		return count;
	}
	public Boolean isExpTime(String time){
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		try{
			Date logTime=format.parse(time);
			Date nowTime=format.parse(format.format(new Date()));
			//算出日志与当前日期相差几天
			int days=(int)(nowTime.getTime()-logTime.getTime())/(1000*3600*24);
			if(Math.abs(days)>=Integer.parseInt(expirDays)){
				return true;
			}else{
				return false;
			}
		}catch(Exception e){
			LogLog.error(e.toString());
			return false;
		}
	}
	/**
	 * 如果当天日志达到最大设置数量,则每次删除尾号为1的日志,
	 * 其他日志编号依次减去1,重命名
	 * @return
	 */
	public Boolean reLogNum(){
		boolean renameTo=false;
		File startFile = new File(this.fileName+'.'+dateStr+'.'+"1");
		if(startFile.exists()&&startFile.delete()){
			for(int i=2;i<=Integer.parseInt(maxIndex);i++){
				File target = new File(this.fileName+'.'+dateStr+'.'+(i-1));
				this.closeFile();
				File file = new File(this.fileName+'.'+dateStr+'.'+i);
				renameTo=file.renameTo(target);
			}
		}
		return renameTo;
	}
	public String getDateStr() {
		return dateStr;
	}
	public void setDateStr(String dateStr) {
		this.dateStr = dateStr;
	}
	public String getExpirDays() {
		return expirDays;
	}
	public void setExpirDays(String expirDays) {
		this.expirDays = expirDays;
	}
	public String getIsCleanLog() {
		return isCleanLog;
	}
	public void setIsCleanLog(String isCleanLog) {
		this.isCleanLog = isCleanLog;
	}
	public String getMaxIndex() {
		return maxIndex;
	}
	public void setMaxIndex(String maxIndex) {
		this.maxIndex = maxIndex;
	}
	
  }



第三,log4j.properties文件配置

log4j.rootLogger=ALL,R,CONSOLE

log4j.appender.R=log.RoolingAndDateFileAppender
#log4j.appender.R.Encoding=UTF-8
log4j.appender.R.file=../log/logs/logRecoed.log
log4j.appender.R.Append=true
log4j.appender.R.DatePattern=yyyy-MM-dd
log4j.appender.R.MaxFileSize=5KB
log4j.appender.R.maxIndex=10
log4j.appender.R.expirDays=1
log4j.appender.R.isCleanLog=true

log4j.appender.R.layout.ConversionPattern=[%p] %t %c %d{yyyy-MM-dd HH:mm:ss} %m  %n
log4j.appender.R.layout=org.apache.log4j.PatternLayout

#console
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout.ConversionPattern=[%p] %t %c %d{yyyy-MM-dd HH:mm:ss} %m  %n
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout







第四、测试:

public class TextLog {
public static void main(String[] args) {
	Log log = LogFactory.getLog(TextLog.class);
	for(int i=0;i<=500;i++){
		System.out.println("循环"+"--"+i);
		try{
			System.out.println(1%0);
		}catch(Exception e){
			log.info("测试日志"+"--"+"异常信息"+i+":"+e);
		}
	}
}
}

第五,运行结果:

生成的日志:


控制台结果:

循环--0
[INFO] main log.TextLog 2018-01-11 23:00:11 测试日志--异常信息0:java.lang.ArithmeticException: / by zero  
循环--1
[INFO] main log.TextLog 2018-01-11 23:00:11 测试日志--异常信息1:java.lang.ArithmeticException: / by zero  
循环--2
[INFO] main log.TextLog 2018-01-11 23:00:11 测试日志--异常信息2:java.lang.ArithmeticException: / by zero  
循环--3

。。。。。。

(完)


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhangyunfeixyz/article/details/79039273

智能推荐

河北农业大学C语言题目,河北农业大学2010-2011学年现科C语言考试试题及答案.doc...-程序员宅基地

文章浏览阅读240次。河北农业大学2010-2011学年现科C语言考试试题及答案河北农业大学课程考试试卷2010—2011学年第2学期 2010 级 独立学院 专业 卷别:A考试科目: C语言程序设计 考核方式: 闭卷考试姓 名: 学号: 专业班级:(注:考生务必将答案写在答题纸上,写在本试卷上无效)本试卷共( 3 )页选择题(共30分,每题1..._河北农业大学c语言程序设计答案

2743:字符串判等_字符串判等 查看提交统计提问 总时间限制: 1000ms 内存限制: 65536kb 描述-程序员宅基地

文章浏览阅读1.2k次。2743:字符串判等查看提交统计提示提问总时间限制: 1000ms 内存限制: 65536kB描述字符串的相关比较 strcmp strlen 最后为了容易比较 在字符串后加上 '\0' 代表字符串的结束判断两个由大小写字母和空格组成的字符串在忽略大小写,且忽略空格后是否相等。输入两行,每行包含一个字符串。输出若两个字符串_字符串判等 查看提交统计提问 总时间限制: 1000ms 内存限制: 65536kb 描述

iOS11 打开相册上移问题解决方法_ios wkwebview打开相册 照片上移-程序员宅基地

文章浏览阅读1k次。原因是app设置了:if (@available(iOS 11, *)) { UIScrollView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; }解决方案 :在弹出系统相册前添加 if (@available(iOS 11, *)) { UIScr..._ios wkwebview打开相册 照片上移

pyecharts 标准线_数据可视化之pyecharts-程序员宅基地

文章浏览阅读1.8k次。EChartsECharts是什么?下面是来自官方的介绍:ECharts,缩写来自Enterprise Charts,商业级数据图表,一个纯Javascript的图表库,可以流畅的运行在PC和移动设备上,兼容当前绝大部分浏览器(IE6/7/8/9/10/11,chrome,firefox,Safari等),底层依赖轻量级的Canvas类库ZRender,提供直观,生动,可交互,可高度个性化定制的数..._pyecharts添加鼠标绘制工具线

计算机网络应用层课后习题练习(二)_6-40用asn.1基本编码规则对以下4个数组(sequence-of)进行编码。假定每一个数字占-程序员宅基地

文章浏览阅读8.2k次,点赞8次,收藏30次。计算机网络应用层课后习题练习(一)计算机网络应用层课后习题练习(二)应用层知识点概览课后习题练习(二)应用层知识点概览课后习题练习(二)6-17在浏览 器中应当有几个可选解释程序。试给出一些可选解释程序的名称。HTML解释器,java解释器HTML解释器必备,有某些java小程序需要用到java解释器6-18 - 一个万维网网点有1000万个页面,平均每个页面有10个超链。读取- -..._6-40用asn.1基本编码规则对以下4个数组(sequence-of)进行编码。假定每一个数字占

Android通讯录查询篇--ContactsContract.Data开篇_kotlin 通讯录 查询-程序员宅基地

文章浏览阅读2.8k次。正在学习Android,想先找个简单点的东西练习一下,先想到的是通讯录,不过关于手机通讯录方面的资料在我现有的书和视频上都很少看到。没办法只有自己看SDK Docs了。  不管怎么说还是先赞Google的Android Docs,确实很全面,只要你想找就一定能找到你要的东西。不过我感觉想把里面的各个类的关系联系起来还是有点困难,特别是像英文水平过于一般的我,看的那叫个累呀。  好了,还是来说一下正题吧。Android刚开始在通讯录方面好像是提供的Contact_kotlin 通讯录 查询

随便推点

流瞬ElectroMagneticWorks(EMWorks).EMS.2017.SP1.4.for.SW2011-2018.Win64三维电磁场仿真软件 EMS帮助设计人员计算的电、磁、机械和-程序员宅基地

文章浏览阅读3.2k次。流瞬ElectroMagneticWorks(EMWorks).EMS.2017.SP1.4.for.SW2011-2018.Win64三维电磁场仿真软件 EMS帮助设计人员计算的电、磁、机械和热参数包括力、转矩、磁通密度、磁场、电场、电流、流、涡流、电感、电容、电阻、磁链、损耗、饱和,感应电压,力密度,功率损耗,温度、温度梯度、热通量和更。EMS是一种基于强大的有限元方法的三维电磁场仿真_emworks

Mat::isContinuous()接口_mat n_iscontinuous-程序员宅基地

文章浏览阅读537次。这里的continue的意思是在内存上continue,正常情况下,头一行的末尾在内存里和下一行的开头是相连的,但是有时候我们做了一些操作,选取了Mat 的一部分,例如选了一个ROI 这时候就不满足上面说的相连了。那么这时候continuous就被判定为假。..._mat n_iscontinuous

android 8.0系统原生锁屏流程分析_android timeout锁屏流程 源码-程序员宅基地

文章浏览阅读2.1k次。android 8.0,9.0系统锁屏流程分析_android timeout锁屏流程 源码

中标麒麟OS连接win10上的SMB共享_中标麒麟访问windows共享-程序员宅基地

文章浏览阅读1.2w次。使用中标麒麟文件共享Samba功能,主要用的是开始菜单里的连接到服务器,或者文件浏览器里的访问服务器功能!!!文件共享实施手册(仅供参考)中标麒麟系列OS访问windows上的共享文件夹(SMB)1.开启win上的Samba共享服务(控制面板-程序-启用或关闭windows功能,如图1)2.设置文件夹共享2.1(右击文件夹-属性-共享,添加访问的用户名,没有可以新建,新建的时候跳过邮箱登陆即可,如图2。选择Everyone要配置好相应的权限及设置图5相关选项)2.2点击高级共享选项,设置._中标麒麟访问windows共享

React Native与原生模块、组件之间的关系浅析(二)_reactnative 安卓constantstoexport-程序员宅基地

文章浏览阅读502次。那么书接上回,今天主要是继续探究React Native与原生模块的架构方式。原生模块原生模块可以访问activity、运行环境、GPS、存储空间等。原生模块就是能够在JavaScript层调用的API。因为对原生模块的全部请求都要异步执行。如果原生方法需要为JavaScript层的调用返回数据,该操作将通过promise或者回调函数来完成。React Native为这两种方式都提供了..._reactnative 安卓constantstoexport

不同类型的设备对font-weight的支持情况_安卓能识别的字体粗细font-weight: bold;-程序员宅基地

文章浏览阅读1.6k次,点赞2次,收藏4次。安卓系统:ios系统:可以看出:对于汉字 => 安卓和ios的区分是一样的,只有normal和bold。但是注意一点,ios的加粗是从600往后开始算的,安卓的是从700开始算的。所以我们日常要是给文字加粗,正常就是写font-weight:bold/700;对于字母和数字 => 安卓是有对于不同数值的粗细区分的,但是ios没有,跟汉字一样只有normal和bold。另外,lighter只针对安卓有效果,相当于是100/200的粗细效果。normal统一都是400,bold是700_安卓能识别的字体粗细font-weight: bold;

推荐文章

热门文章

相关标签