首页IT科技log4j maxbackupindex 最大设置多少(扩展log4j系列[一]为DailyRollingFileAppender加上maxBackupIndex属性 玮哥也是哥 ITeye技术网站)

log4j maxbackupindex 最大设置多少(扩展log4j系列[一]为DailyRollingFileAppender加上maxBackupIndex属性 玮哥也是哥 ITeye技术网站)

时间2025-06-17 23:12:49分类IT科技浏览3807
导读:在log4j的大多数appender中,都有maxBackupIndex属性,但是这个DailyRollingFileAppender没有,也就是说它会每天滚一个文件,却没有办法控制文件总个数。这绝对是系统的一个“着火点”,下面就开始动手改造了:...

在log4j的大多数appender中             ,都有maxBackupIndex属性                  ,但是这个DailyRollingFileAppender没有       ,也就是说它会每天滚一个文件          ,却没有办法控制文件总个数             。这绝对是系统的一个“着火点            ”                  ,下面就开始动手改造了:

一                  。研究整个log4j的appender结构:

对框架的一个模块进行扩展          ,并非总是直接继承某个类就好了       ,如果不进一步深入研究就有可能掉入某些陷阱       。(比如扩展log4j的Logger类                  ,直接继承它并不能得到任何好处             ,具体解释清参考官方文档          。)    ,还好log4j对level                   ,appender                ,layerout都扩展有很好支持的                  。

然后就是看log4j的配置文件了          。 配置文件是可以直接配置扩展appender属性的,这样就替我们节省了一堆定义             、解析                  、处理的过程

Java代码
<spanstyle="color:#ff0000;">#给自己的类取个对应的名</span> log4j.appender.appenderName=fully.qualified.name.of.appender.class <spanstyle="color:#ff0000;">#还可以给自己的类property设置值                ,也就是说扩展的maxBackupIndex属性可以配置</span> log4j.appender.appenderName.option1=value1 ... log4j.appender.appenderName.optionN=valueN
# 给自己的类取个对应的名 log4j.appender.appenderName=fully.qualified.name.of.appender.class #还可以给自己的类property设置值                   ,也就是说扩展的maxBackupIndex属性可以配置 log4j.appender.appenderName.option1=value1 ... log4j.appender.appenderName.optionN=valueN

二       。大致胸有成竹后    ,可以开始看DailyRollingFileAppender的源码了                  。

直接看属性跟方法结构

大致可以猜出这个类做了如下几个事情:继承了根类appender       、支持DatePattern解析并针对DatePattern设置的滚动条件组装filename          、实现“监听                    ”方法             ,到时间点切换logfile             。    。                   。 大部分的工作都给我们做好了:)

现在唯一需要改动的就是                  ,“切换文件      ”方法       ,在切换新文件的同时          ,删除掉最老的n个log                。

Java代码
/** Rolloverthecurrentfiletoanewfile. */ voidrollOver()throwsIOException{ /*Computefilename,butonlyifdatePatternisspecified*/ if(datePattern==null){ errorHandler.error("MissingDatePatternoptioninrollOver()."); return; } StringdatedFilename=fileName+sdf.format(now); //Itistooearlytorolloverbecausewearestillwithinthe //boundsofthecurrentinterval.Rolloverwilloccuroncethe //nextintervalisreached. if(scheduledFilename.equals(datedFilename)){ return; } //closecurrentfile,andrenameittodatedFilename this.closeFile(); Filetarget=newFile(scheduledFilename); if(target.exists()){ target.delete(); } Filefile=newFile(fileName); booleanresult=file.renameTo(target); if(result){ LogLog.debug(fileName+"->"+scheduledFilename); }else{ LogLog.error("Failedtorename["+fileName+"]to["+scheduledFilename+"]."); } try{ //Thiswillalsoclosethefile.ThisisOKsincemultiple //closeoperationsaresafe. this.setFile(fileName,false,this.bufferedIO,this.bufferSize); } catch(IOExceptione){ errorHandler.error("setFile("+fileName+",false)callfailed."); } scheduledFilename=datedFilename; }
/** Rollover the current file to a new file. */ void rollOver() throws IOException { /* Compute filename, but only if datePattern is specified */ if (datePattern == null) { errorHandler.error("Missing DatePattern option in rollOver()."); return; } String datedFilename = fileName+sdf.format(now); // It is too early to roll over because we are still within the // bounds of the current interval. Rollover will occur once the // next interval is reached. if (scheduledFilename.equals(datedFilename)) { return; } // close current file, and rename it to datedFilename 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+"]."); } try { // This will also close the file. This is OK since multiple // close operations are safe. this.setFile(fileName, false, this.bufferedIO, this.bufferSize); } catch(IOException e) { errorHandler.error("setFile("+fileName+", false) call failed."); } scheduledFilename = datedFilename; }

看到这里就发现问题了                  ,由于DatePattern格式可配置          ,那么产生的滚动的文件名也是不同的       ,也没有什么规律可循。

比如".yyyy-ww",是按周滚动                  ,当配置改成".yyyy-MM "按月滚动之后             ,通过文件名匹配删除旧文件将会导致错误                。

另外    ,日志文件的切换不是定时轮询而是事件促发机制                   ,只有在进行写操作的时候才会去判断是否需要滚动文件!那么写操作在跨过一个滚动周期执行的时候                ,文件名会产生空缺而不保证连续性                   。

也许这就是log4j本身没有对这个appender做文件个数限制的原因吧    。

三             。妥协吧                  。

框架的功能总是尽量强大的,但使用总是最简单的功能!在IDC环境中通常是不允许按时间滚动记log的                ,主要是防止日志文件撑爆硬盘成为着火点       。 这里考虑启用按时间滚动                   ,主要是性能日志的统计脚本需要日志文件以日期为名按天存储    ,并且只需要备份前一天的即可.

那么我的需求就简单了:简化功能!

仿造DailyRollingFileAppender实现1.仅支持按天滚动的

                  、2.格式写死的DatePattern

             ,3.最大备份文件个数为n的appender

          。(备份数可配考虑灵活性                  ,但一定要有参数检查预防万一!)

限制datepattern       ,一方面可以防止配错          ,弄成按月滚动肯定死翘翘;另一方面也容易处理MaxBackupIndex删除历史文件                  。 more                  ,既然知道是按天滚动          ,check的方法当然可以简化了:

最终修改版的按天滚动appender如下:

Java代码
packagecxxxxxxxj; importjava.io.File; importjava.io.IOException; importjava.text.SimpleDateFormat; importjava.util.ArrayList; importjava.util.Calendar; importjava.util.Date; importjava.util.List; importorg.apache.log4j.FileAppender; importorg.apache.log4j.Layout; importorg.apache.log4j.helpers.LogLog; importorg.apache.log4j.spi.LoggingEvent; /** *扩展的一个按天滚动的appender类 *暂时不支持datePattern设置       ,但是可以配置maxBackupIndex *@authorweisong * */ publicclassDayRollingFileAppenderextendsFileAppender{ /**不允许改写的datepattern*/ privatefinalStringdatePattern=".yyyy-MM-dd"; /**最多文件增长个数*/ privateintmaxBackupIndex=2; /**"文件名+上次最后更新时间"*/ privateStringscheduledFilename; /** Thenexttimeweestimatearollovershouldoccur.*/ privatelongnextCheck=System.currentTimeMillis()-1; Datenow=newDate(); SimpleDateFormatsdf; /** Thedefaultconstructordoesnothing.*/ publicDayRollingFileAppender(){ } /** 改造过的构造器 */ publicDayRollingFileAppender(Layoutlayout,Stringfilename, intmaxBackupIndex)throwsIOException{ super(layout,filename,true); this.maxBackupIndex=maxBackupIndex; activateOptions(); } /** *初始化本Appender对象的时候调用一次 */ publicvoidactivateOptions(){ super.activateOptions(); if(fileName!=null){//perf.log now.setTime(System.currentTimeMillis()); sdf=newSimpleDateFormat(datePattern); Filefile=newFile(fileName); //获取最后更新时间拼成的文件名 scheduledFilename=fileName+sdf.format(newDate(file.lastModified())); }else{ LogLog.error("Fileisnotsetforappender["+name+"]."); } if(maxBackupIndex<=0){ LogLog.error("maxBackupIndexresettodefaultvalue[2],orignalvalueis:"+maxBackupIndex); maxBackupIndex=2; } } /** 滚动文件的函数: 1.对文件名带的时间戳进行比较                  ,确定是否更新 2.if需要更新             ,当前文件rename到文件名+日期    ,重新开始写文件 3.针对配置的maxBackupIndex,删除过期的文件 */ voidrollOver()throwsIOException{ StringdatedFilename=fileName+sdf.format(now); //如果上次写的日期跟当前日期相同                   ,不需要换文件 if(scheduledFilename.equals(datedFilename)){ return; } //closecurrentfile,andrenameittodatedFilename this.closeFile(); Filetarget=newFile(scheduledFilename); if(target.exists()){ target.delete(); } Filefile=newFile(fileName); booleanresult=file.renameTo(target); if(result){ LogLog.debug(fileName+"->"+scheduledFilename); }else{ LogLog.error("Failedtorename["+fileName+"]to[" +scheduledFilename+"]."); } //删除过期文件 if(maxBackupIndex>0){ Filefolder=newFile(file.getParent()); List<String>maxBackupIndexDates=getMaxBackupIndexDates(); for(Fileff:folder.listFiles()){//遍历目录                ,将日期不在备份范围内的日志删掉 if(ff.getName().startsWith(file.getName())&&!ff.getName().equals(file.getName())){ //获取文件名带的日期时间戳 StringmarkedDate=ff.getName().substring(file.getName().length()); if(!maxBackupIndexDates.contains(markedDate)){ result=ff.delete(); } if(result){ LogLog.debug(ff.getName()+"->deleted"); }else{ LogLog.error("FailedtodeletedoldDayRollingFileAppenderfile:"+ff.getName()); } } } } try{ //Thiswillalsoclosethefile.ThisisOKsincemultiple //closeoperationsaresafe. this.setFile(fileName,false,this.bufferedIO,this.bufferSize); }catch(IOExceptione){ errorHandler.error("setFile("+fileName+",false)callfailed."); } scheduledFilename=datedFilename;//更新最后更新日期戳 } /** *Actualwritingoccurshere.这个方法是写操作真正的执行过程! **/ protectedvoidsubAppend(LoggingEventevent){ longn=System.currentTimeMillis(); if(n>=nextCheck){//在每次写操作前判断一下是否需要滚动文件 now.setTime(n); nextCheck=getNextDayCheckPoint(now); try{ rollOver(); }catch(IOExceptionioe){ LogLog.error("rollOver()failed.",ioe); } } super.subAppend(event); } /** *获取下一天的时间变更点 *@paramnow *@return */ longgetNextDayCheckPoint(Datenow){ Calendarcalendar=Calendar.getInstance(); calendar.setTime(now); 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,1); returncalendar.getTimeInMillis(); } /** *根据maxBackupIndex配置的备份文件个数,获取要保留log文件的日期范围集合 *@returnlist<fileName+yyyy-MM-dd> */ List<String>getMaxBackupIndexDates(){ List<String>result=newArrayList<String>(); if(maxBackupIndex>0){ for(inti=1;i<=maxBackupIndex;i++){ Calendarcalendar=Calendar.getInstance(); calendar.setTime(now); 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(sdf.format(calendar.getTime())); } } returnresult; } publicintgetMaxBackupIndex(){ returnmaxBackupIndex; } publicvoidsetMaxBackupIndex(intmaxBackupIndex){ this.maxBackupIndex=maxBackupIndex; } publicStringgetDatePattern(){ returndatePattern; } //publicstaticvoidmain(String[]args){ //DayRollingFileAppenderda=newDayRollingFileAppender(); //da.setMaxBackupIndex(2); //da.sdf=newSimpleDateFormat(da.getDatePattern()); //System.out.println(da.getMaxBackupIndexDates()); // //Filef=newFile("e:/log/b2c/perf.log"); //System.out.println("f.name="+f.getName()); //Filep=newFile(f.getParent()); //for(Fileff:p.listFiles()){ //System.out.println(ff); //} //} }
package cxxxxxxxj; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import org.apache.log4j.FileAppender; import org.apache.log4j.Layout; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; /** * 扩展的一个按天滚动的appender类 * 暂时不支持datePattern设置                ,但是可以配置maxBackupIndex * @author weisong * */ public class DayRollingFileAppender extends FileAppender { /**不允许改写的datepattern */ private final String datePattern = ".yyyy-MM-dd"; /**最多文件增长个数*/ private int maxBackupIndex = 2; /**"文件名+上次最后更新时间"*/ private String scheduledFilename; /** The next time we estimate a rollover should occur. */ private long nextCheck = System.currentTimeMillis () - 1; Date now = new Date(); SimpleDateFormat sdf; /** The default constructor does nothing. */ public DayRollingFileAppender() { } /** 改造过的构造器 */ public DayRollingFileAppender (Layout layout, String filename, int maxBackupIndex) throws IOException { super(layout, filename, true); this.maxBackupIndex = maxBackupIndex; activateOptions(); } /** * 初始化本Appender对象的时候调用一次 */ public void activateOptions() { super.activateOptions(); if(fileName != null) { //perf.log now.setTime(System.currentTimeMillis()); sdf = new SimpleDateFormat(datePattern); File file = new File(fileName); //获取最后更新时间拼成的文件名 scheduledFilename = fileName+sdf.format(new Date(file.lastModified())); } else { LogLog.error("File is not set for appender ["+name+"]."); } if(maxBackupIndex<=0) { LogLog.error("maxBackupIndex reset to default value[2],orignal value is:" + maxBackupIndex); maxBackupIndex=2; } } /** 滚动文件的函数: 1.对文件名带的时间戳进行比较                   ,确定是否更新 2.if需要更新    ,当前文件rename到文件名+日期             , 重新开始写文件 3. 针对配置的maxBackupIndex,删除过期的文件 */ void rollOver() throws IOException { String datedFilename = fileName + sdf.format(now); // 如果上次写的日期跟当前日期相同                  ,不需要换文件 if (scheduledFilename.equals(datedFilename)) { return; } // close current file, and rename it to datedFilename 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 (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 markedDate = ff.getName().substring(file.getName().length()); 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 will also close the file. This is OK since multiple // close operations are safe. this.setFile(fileName, false, this.bufferedIO, this.bufferSize); } catch (IOException e) { errorHandler.error("setFile(" + fileName + ", false) call failed."); } scheduledFilename = datedFilename; // 更新最后更新日期戳 } /** * Actual writing occurs here. 这个方法是写操作真正的执行过程! * */ protected void subAppend(LoggingEvent event) { long n = System.currentTimeMillis(); if (n >= nextCheck) { //在每次写操作前判断一下是否需要滚动文件 now.setTime(n); nextCheck = getNextDayCheckPoint(now); try { rollOver(); } catch (IOException ioe) { LogLog.error("rollOver() failed.", ioe); } } super.subAppend(event); } /** * 获取下一天的时间变更点 * @param now * @return */ long getNextDayCheckPoint(Date now) { Calendar calendar = Calendar.getInstance(); calendar.setTime(now); 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, 1); return calendar.getTimeInMillis(); } /** * 根据maxBackupIndex配置的备份文件个数          ,获取要保留log文件的日期范围集合 * @return list<fileName+yyyy-MM-dd> */ List<String> getMaxBackupIndexDates() { List<String> result = new ArrayList<String>(); if(maxBackupIndex>0) { for (int i = 1; i <= maxBackupIndex; i++) { Calendar calendar = Calendar.getInstance(); calendar.setTime(now); 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(sdf.format(calendar.getTime())); } } return result; } public int getMaxBackupIndex() { return maxBackupIndex; } public void setMaxBackupIndex(int maxBackupIndex) { this.maxBackupIndex = maxBackupIndex; } public String getDatePattern() { return datePattern; } // public static void main(String[] args) { // DayRollingFileAppender da = new DayRollingFileAppender(); // da.setMaxBackupIndex(2); // da.sdf = new SimpleDateFormat(da.getDatePattern()); // System.out.println(da.getMaxBackupIndexDates()); // // File f = new File("e:/log/b2c/perf.log"); // System.out.println("f.name=" + f.getName()); // File p = new File(f.getParent()); // for(File ff : p.listFiles()) { // System.out.println(ff); // } // } }
大小: 91.7 KB 大小: 66.7 KB 查看图片附件
声明:本站所有文章                  ,如无特殊说明或标注          ,均为本站原创发布                。任何个人或组织       ,在未征得本站同意时                  ,禁止复制          、盗用       、采集                  、发布本站内容到任何网站             、书籍等各类媒体平台                   。如若本站内容侵犯了原著者的合法权益             ,可联系我们进行处理    。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
css中隐藏元素并不占据原有空间怎么办(CSS中的元素显隐方法汇总) qqpctray无法正常启动(QQPCTray.exe是什么进程 QQPCTray.exe文件介绍)