`
tcxiang
  • 浏览: 89489 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

log4j自动日志删除(转)

 
阅读更多

最近要实现定期删除N天前的日志。 以前都是利用运维的一个cron脚本来定期删除的, 总觉得可移植性不是很好, 比如要指定具体的日志文件路径, 有时候想想为什么log4j自己不实现这个功能呢? 后来发现在logback中已经实现了这个功能. 其配置如下: 

Xml代码  收藏代码
  1. <appender name="vstore"  
  2.      class="ch.qos.logback.core.rolling.RollingFileAppender">  
  3.      <file>default.log</file>  
  4.      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
  5.           <fileNamePattern>./logs/%d/default.log.%d  
  6.           </fileNamePattern>  
  7.           <maxHistory>7</maxHistory>  
  8.      </rollingPolicy>  
  9.   
  10.      <encoder>  
  11.           <pattern>%d{HH:mm:ss.SSS} %level [%thread] %c{0}[%line] %msg%n  
  12.           </pattern>  
  13.      </encoder>  
  14. </appender>  



但是我的应用因为依赖的log相关的jar包的问题, 没法使用logback的jar包, 因为必须使用新的方式来处理. 于是google了一下, 发现老外也遇到了类似的问题. 比如这里是一个解决办法: 
http://stackoverflow.com/questions/1050256/how-can-i-get-log4j-to-delete-old-rotating-log-files 
这个方式是采用的RollingFileAppender, 然后通过设置maxBackupIndex属性来指定要保留的日志的最大值(这里采用一天一个日志).但是我们一直采用的是DailyRollingFileAppender. 可是该appender没有maxBackupIndex这个属性, 于是又google了一把, 发现老外也想到的解决办法, 而且这里有两个解决方法, 即在RollingFileAppender的基础上, 加入了maxBackupIndex属性. 

一种实现方案: 
http://www.zybonics.com/zybocodes/code/CodeViewForm.php?codeID=428 

Java代码  收藏代码
  1. /************************** 
  2. * Zybocodes ******************************* 
  3. * Code For : 
  4. * log4j custom DailyRollingFileAppender - manage your 
  5. * logs:maxBackupIndex zip roll archive logging log management 
  6. * logs 
  7. * Contributor : Ed Sarrazin 
  8. * Ref link : http://jconvert.sourceforge.net 
  9. * For this and other codes/logic under any technology visit: 
  10. * http://www.zybonics.com/zybocodes/ 
  11. ********************************************************************/  
  12.   
  13. /* 
  14. * Licensed to the Apache Software Foundation (ASF) under one or more 
  15. * contributor license agreements. See the NOTICE file distributed with 
  16. * this work for additional information regarding copyright ownership. 
  17. * The ASF licenses this file to You under the Apache License, Version 2.0 
  18. * (the "License"); you may not use this file except in compliance with 
  19. * the License. You may obtain a copy of the License at 
  20. * http://www.apache.org/licenses/LICENSE-2.0 
  21. * Unless required by applicable law or agreed to in writing, software 
  22. * distributed under the License is distributed on an "AS IS" BASIS, 
  23. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  24. * See the License for the specific language governing permissions and 
  25. * limitations under the License. 
  26. */  
  27. package logger;  
  28.   
  29. import java.io.File;  
  30. import java.io.FileFilter;  
  31. import java.io.FileInputStream;  
  32. import java.io.FileOutputStream;  
  33. import java.io.IOException;  
  34. import java.io.InputStream;  
  35. import java.io.InterruptedIOException;  
  36. import java.text.ParseException;  
  37. import java.text.SimpleDateFormat;  
  38. import java.util.Calendar;  
  39. import java.util.Date;  
  40. import java.util.GregorianCalendar;  
  41. import java.util.Locale;  
  42. import java.util.TimeZone;  
  43. import java.util.zip.ZipEntry;  
  44. import java.util.zip.ZipInputStream;  
  45. import java.util.zip.ZipOutputStream;  
  46.   
  47. import org.apache.log4j.FileAppender;  
  48. import org.apache.log4j.Layout;  
  49. import org.apache.log4j.helpers.LogLog;  
  50. import org.apache.log4j.spi.LoggingEvent;  
  51.   
  52. /** 
  53. * @author Ed Sarrazin 
  54. *  <pre> 
  55. *  AdvancedDailyRollingFileAppender is a copy of apaches DailyRollingFileAppender.  This copy was made because it could not be extended due to package level access.  This new version will allow two new properties to be set: 
  56. *  MaxNumberOfDays:            Max number of log files to keep, denoted in days.  If using compression, this days should be longer than 
  57. *  -                           CompressBackupsAfterDays and will become irrelevant as files will be moved to archive before this time. 
  58. *  CompressBackups:            Indicating if older log files should be backed up to a compressed format. 
  59. *  RollCompressedBackups:      TURE/FALSE indicating that compressed backups should be rolled out (deleted after certain age) 
  60. *  CompressBackupsAfterDays:   Number of days to wait until adding files to compressed backup. (Files that are compressed are deleted) 
  61. *  CompressBackupsDatePattern: example - "'.'yyyy-MM" - this will create compressed backups grouped by pattern.  In this example, every month 
  62. *  CompressMaxNumberDays:      Number of days to keep compressed backups.  RollCompressedBackups must be true. 
  63.  
  64. *  Here is a listing of the log4j.properties file you would use: 
  65.  
  66. *  log4j.appender.RootAppender=com.edsdev.log4j.AdvancedDailyRollingFileAppender 
  67. *  log4j.appender.RootAppender.DatePattern='.'yyyyMMdd 
  68. *  log4j.appender.RootAppender.MaxNumberOfDays=60 
  69. *  log4j.appender.RootAppender.CompressBackups=true 
  70. *  log4j.appender.RootAppender.CompressBackupsAfterDays=31 
  71. *  log4j.appender.RootAppender.CompressBackupsDatePattern='.'yyyyMM 
  72. *  log4j.appender.RootAppender.RollCompressedBackups=true 
  73. *  log4j.appender.RootAppender.CompressMaxNumberDays=365 
  74.  
  75. *  </pre> 
  76. * AdvancedDailyRollingFileAppender extends {@link FileAppender} so that the underlying file is rolled over at a user 
  77. * chosen frequency. AdvancedDailyRollingFileAppender has been observed to exhibit synchronization issues and data loss. 
  78. * The log4j extras companion includes alternatives which should be considered for new deployments and which are 
  79. * discussed in the documentation for org.apache.log4j.rolling.RollingFileAppender. 
  80. * <p> 
  81. * The rolling schedule is specified by the <b>DatePattern</b> option. This pattern should follow the 
  82. * {@link SimpleDateFormat} conventions. In particular, you <em>must</em> escape literal text within a pair of single 
  83. * quotes. A formatted version of the date pattern is used as the suffix for the rolled file name. 
  84. * <p> 
  85. * For example, if the <b>File</b> option is set to <code>/foo/bar.log</code> and the <b>DatePattern</b> set to 
  86. * <code>'.'yyyy-MM-dd</code>, on 2001-02-16 at midnight, the logging file <code>/foo/bar.log</code> will be copied 
  87. * to <code>/foo/bar.log.2001-02-16</code> and logging for 2001-02-17 will continue in <code>/foo/bar.log</code> 
  88. * until it rolls over the next day. 
  89. * <p> 
  90. * Is is possible to specify monthly, weekly, half-daily, daily, hourly, or minutely rollover schedules. 
  91. * <p> 
  92. * <table border="1" cellpadding="2"> 
  93. * <tr> 
  94. * <th>DatePattern</th> 
  95. * <th>Rollover schedule</th> 
  96. * <th>Example</th> 
  97. * <tr> 
  98. * <td><code>'.'yyyy-MM</code> 
  99. * <td>Rollover at the beginning of each month</td> 
  100. * <td>At midnight of May 31st, 2002 <code>/foo/bar.log</code> will be copied to <code>/foo/bar.log.2002-05</code>. 
  101. * Logging for the month of June will be output to <code>/foo/bar.log</code> until it is also rolled over the next 
  102. * month. 
  103. * <tr> 
  104. * <td><code>'.'yyyy-ww</code> 
  105. * <td>Rollover at the first day of each week. The first day of the week depends on the locale.</td> 
  106. * <td>Assuming the first day of the week is Sunday, on Saturday midnight, June 9th 2002, the file <i>/foo/bar.log</i> 
  107. * will be copied to <i>/foo/bar.log.2002-23</i>. Logging for the 24th week of 2002 will be output to 
  108. * <code>/foo/bar.log</code> until it is rolled over the next week. 
  109. * <tr> 
  110. * <td><code>'.'yyyy-MM-dd</code> 
  111. * <td>Rollover at midnight each day.</td> 
  112. * <td>At midnight, on March 8th, 2002, <code>/foo/bar.log</code> will be copied to 
  113. * <code>/foo/bar.log.2002-03-08</code>. Logging for the 9th day of March will be output to <code>/foo/bar.log</code> 
  114. * until it is rolled over the next day. 
  115. * <tr> 
  116. * <td><code>'.'yyyy-MM-dd-a</code> 
  117. * <td>Rollover at midnight and midday of each day.</td> 
  118. * <td>At noon, on March 9th, 2002, <code>/foo/bar.log</code> will be copied to 
  119. * <code>/foo/bar.log.2002-03-09-AM</code>. Logging for the afternoon of the 9th will be output to 
  120. * <code>/foo/bar.log</code> until it is rolled over at midnight. 
  121. * <tr> 
  122. * <td><code>'.'yyyy-MM-dd-HH</code> 
  123. * <td>Rollover at the top of every hour.</td> 
  124. * <td>At approximately 11:00.000 o'clock on March 9th, 2002, <code>/foo/bar.log</code> will be copied to 
  125. * <code>/foo/bar.log.2002-03-09-10</code>. Logging for the 11th hour of the 9th of March will be output to 
  126. * <code>/foo/bar.log</code> until it is rolled over at the beginning of the next hour. 
  127. * <tr> 
  128. * <td><code>'.'yyyy-MM-dd-HH-mm</code> 
  129. * <td>Rollover at the beginning of every minute.</td> 
  130. * <td>At approximately 11:23,000, on March 9th, 2001, <code>/foo/bar.log</code> will be copied to 
  131. * <code>/foo/bar.log.2001-03-09-10-22</code>. Logging for the minute of 11:23 (9th of March) will be output to 
  132. * <code>/foo/bar.log</code> until it is rolled over the next minute. </table> 
  133. * <p> 
  134. * Do not use the colon ":" character in anywhere in the <b>DatePattern</b> option. The text before the colon is 
  135. * interpeted as the protocol specificaion of a URL which is probably not what you want. 
  136. * @author Eirik Lygre 
  137. * @author Ceki Gülcü 
  138. */  
  139. public class AdvancedDailyRollingFileAppender extends FileAppender {  
  140.   
  141.     // The code assumes that the following constants are in a increasing  
  142.     // sequence.  
  143.     static final int TOP_OF_TROUBLE = -1;  
  144.     static final int TOP_OF_MINUTE = 0;  
  145.     static final int TOP_OF_HOUR = 1;  
  146.     static final int HALF_DAY = 2;  
  147.     static final int TOP_OF_DAY = 3;  
  148.     static final int TOP_OF_WEEK = 4;  
  149.     static final int TOP_OF_MONTH = 5;  
  150.   
  151.     /** Indicates if log files should be moved to archive file */  
  152.     private String compressBackups = "false";  
  153.     /** Indicates if archive file that may be created will be rolled off as it ages */  
  154.     private String rollCompressedBackups = "false";  
  155.     /** Maximum number of days to keep log files */  
  156.     private int maxNumberOfDays = 31;  
  157.     /** Number of days to wait before moving a log file to an archive */  
  158.     private int compressBackupsAfterDays = 31;  
  159.     /** Pattern used to name archive file (also controls what log files are grouped together */  
  160.     private String compressBackupsDatePattern = "'.'yyyy-MM";  
  161.     /** Maximum number of days to keep archive file before deleting */  
  162.     private int compressMaxNumberDays = 365;  
  163.   
  164.     /** 
  165.      * The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" meaning daily rollover. 
  166.      */  
  167.     private String datePattern = "'.'yyyy-MM-dd";  
  168.   
  169.     /** 
  170.      * The log file will be renamed to the value of the scheduledFilename variable when the next interval is entered. 
  171.      * For example, if the rollover period is one hour, the log file will be renamed to the value of "scheduledFilename" 
  172.      * at the beginning of the next hour. The precise time when a rollover occurs depends on logging activity. 
  173.      */  
  174.     private String scheduledFilename;  
  175.   
  176.     /** 
  177.      * The next time we estimate a rollover should occur. 
  178.      */  
  179.     private long nextCheck = System.currentTimeMillis() - 1;  
  180.   
  181.     Date now = new Date();  
  182.   
  183.     SimpleDateFormat sdf;  
  184.   
  185.     RollingCalendar rc = new RollingCalendar();  
  186.   
  187.     int checkPeriod = TOP_OF_TROUBLE;  
  188.   
  189.     // The gmtTimeZone is used only in computeCheckPeriod() method.  
  190.     static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");  
  191.   
  192.     /** 
  193.      * The default constructor does nothing. 
  194.      */  
  195.     public AdvancedDailyRollingFileAppender() {  
  196.     }  
  197.   
  198.     /** 
  199.      * Instantiate a <code>AdvancedDailyRollingFileAppender</code> and open the file designated by 
  200.      * <code>filename</code>. The opened filename will become the ouput destination for this appender. 
  201.      */  
  202.     public AdvancedDailyRollingFileAppender(Layout layout, String filename, String datePattern) throws IOException {  
  203.         super(layout, filename, true);  
  204.         this.datePattern = datePattern;  
  205.         activateOptions();  
  206.     }  
  207.   
  208.     /** 
  209.      * The <b>DatePattern</b> takes a string in the same format as expected by {@link SimpleDateFormat}. This options 
  210.      * determines the rollover schedule. 
  211.      */  
  212.     public void setDatePattern(String pattern) {  
  213.         datePattern = pattern;  
  214.     }  
  215.   
  216.     /** Returns the value of the <b>DatePattern</b> option. */  
  217.     public String getDatePattern() {  
  218.         return datePattern;  
  219.     }  
  220.   
  221.     public String getCompressBackups() {  
  222.         return compressBackups;  
  223.     }  
  224.   
  225.     public void setCompressBackups(String compressBackups) {  
  226.         this.compressBackups = compressBackups;  
  227.     }  
  228.   
  229.     public String getMaxNumberOfDays() {  
  230.         return "" + maxNumberOfDays;  
  231.     }  
  232.   
  233.     public void setMaxNumberOfDays(String days) {  
  234.         try {  
  235.             this.maxNumberOfDays = Integer.parseInt(days);  
  236.         } catch (Exception e) {  
  237.             // just leave it at default  
  238.         }  
  239.   
  240.     }  
  241.   
  242.     @Override  
  243.     public void activateOptions() {  
  244.         super.activateOptions();  
  245.         if (datePattern != null && fileName != null) {  
  246.             now.setTime(System.currentTimeMillis());  
  247.             sdf = new SimpleDateFormat(datePattern);  
  248.             int type = computeCheckPeriod();  
  249.             printPeriodicity(type);  
  250.             rc.setType(type);  
  251.             File file = new File(fileName);  
  252.             scheduledFilename = fileName + sdf.format(new Date(file.lastModified()));  
  253.   
  254.         } else {  
  255.             LogLog.error("Either File or DatePattern options are not set for appender [" + name + "].");  
  256.         }  
  257.     }  
  258.   
  259.     void printPeriodicity(int type) {  
  260.         switch (type) {  
  261.             case TOP_OF_MINUTE:  
  262.                 LogLog.debug("Appender [" + name + "] to be rolled every minute.");  
  263.                 break;  
  264.             case TOP_OF_HOUR:  
  265.                 LogLog.debug("Appender [" + name + "] to be rolled on top of every hour.");  
  266.                 break;  
  267.             case HALF_DAY:  
  268.                 LogLog.debug("Appender [" + name + "] to be rolled at midday and midnight.");  
  269.                 break;  
  270.             case TOP_OF_DAY:  
  271.                 LogLog.debug("Appender [" + name + "] to be rolled at midnight.");  
  272.                 break;  
  273.             case TOP_OF_WEEK:  
  274.                 LogLog.debug("Appender [" + name + "] to be rolled at start of week.");  
  275.                 break;  
  276.             case TOP_OF_MONTH:  
  277.                 LogLog.debug("Appender [" + name + "] to be rolled at start of every month.");  
  278.                 break;  
  279.             default:  
  280.                 LogLog.warn("Unknown periodicity for appender [" + name + "].");  
  281.         }  
  282.     }  
  283.   
  284.     // This method computes the roll over period by looping over the  
  285.     // periods, starting with the shortest, and stopping when the r0 is  
  286.     // different from from r1, where r0 is the epoch formatted according  
  287.     // the datePattern (supplied by the user) and r1 is the  
  288.     // epoch+nextMillis(i) formatted according to datePattern. All date  
  289.     // formatting is done in GMT and not local format because the test  
  290.     // logic is based on comparisons relative to 1970-01-01 00:00:00  
  291.     // GMT (the epoch).  
  292.   
  293.     int computeCheckPeriod() {  
  294.         RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault());  
  295.         // set sate to 1970-01-01 00:00:00 GMT  
  296.         Date epoch = new Date(0);  
  297.         if (datePattern != null) {  
  298.             for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {  
  299.                 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);  
  300.                 simpleDateFormat.setTimeZone(gmtTimeZone); // do all date  
  301.                                                            // formatting in GMT  
  302.                 String r0 = simpleDateFormat.format(epoch);  
  303.                 rollingCalendar.setType(i);  
  304.                 Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));  
  305.                 String r1 = simpleDateFormat.format(next);  
  306.                 // System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);  
  307.                 if (r0 != null && r1 != null && !r0.equals(r1)) {  
  308.                     return i;  
  309.                 }  
  310.             }  
  311.         }  
  312.         return TOP_OF_TROUBLE; // Deliberately head for trouble...  
  313.     }  
  314.   
  315.     /** 
  316.      * Rollover the current file to a new file. 
  317.      */  
  318.     void rollOver() throws IOException {  
  319.   
  320.         /* Compute filename, but only if datePattern is specified */  
  321.         if (datePattern == null) {  
  322.             errorHandler.error("Missing DatePattern option in rollOver().");  
  323.             return;  
  324.         }  
  325.   
  326.         String datedFilename = fileName + sdf.format(now);  
  327.         // It is too early to roll over because we are still within the  
  328.         // bounds of the current interval. Rollover will occur once the  
  329.         // next interval is reached.  
  330.         if (scheduledFilename.equals(datedFilename)) {  
  331.             return;  
  332.         }  
  333.   
  334.         // close current file, and rename it to datedFilename  
  335.         this.closeFile();  
  336.   
  337.         File target = new File(scheduledFilename);  
  338.         if (target.exists()) {  
  339.             target.delete();  
  340.         }  
  341.   
  342.         File file = new File(fileName);  
  343.         boolean result = file.renameTo(target);  
  344.         if (result) {  
  345.             LogLog.debug(fileName + " -> " + scheduledFilename);  
  346.         } else {  
  347.             LogLog.error("Failed to rename [" + fileName + "] to [" + scheduledFilename + "].");  
  348.         }  
  349.   
  350.         try {  
  351.             // This will also close the file. This is OK since multiple  
  352.             // close operations are safe.  
  353.             this.setFile(fileName, truethis.bufferedIO, this.bufferSize);  
  354.         } catch (IOException e) {  
  355.             errorHandler.error("setFile(" + fileName + ", true) call failed.");  
  356.         }  
  357.         scheduledFilename = datedFilename;  
  358.     }  
  359.   
  360.     /** 
  361.      * This method differentiates AdvancedDailyRollingFileAppender from its super class. 
  362.      * <p> 
  363.      * Before actually logging, this method will check whether it is time to do a rollover. If it is, it will schedule 
  364.      * the next rollover time and then rollover. 
  365.      */  
  366.     @Override  
  367.     protected void subAppend(LoggingEvent event) {  
  368.         long n = System.currentTimeMillis();  
  369.         if (n >= nextCheck) {  
  370.             now.setTime(n);  
  371.             nextCheck = rc.getNextCheckMillis(now);  
  372.             try {  
  373.                 cleanupAndRollOver();  
  374.             } catch (IOException ioe) {  
  375.                 if (ioe instanceof InterruptedIOException) {  
  376.                     Thread.currentThread().interrupt();  
  377.                 }  
  378.                 LogLog.error("cleanupAndRollover() failed.", ioe);  
  379.             }  
  380.         }  
  381.         super.subAppend(event);  
  382.     }  
  383.   
  384.     /* 
  385.      * This method checks to see if we're exceeding the number of log backups 
  386.      * that we are supposed to keep, and if so, 
  387.      * deletes the offending files. It then delegates to the rollover method to 
  388.      * rollover to a new file if required. 
  389.      */  
  390.     protected void cleanupAndRollOver() throws IOException {  
  391.         File file = new File(fileName);  
  392.         Calendar cal = Calendar.getInstance();  
  393.   
  394.         cal.add(Calendar.DATE, -maxNumberOfDays);  
  395.         Date cutoffDate = cal.getTime();  
  396.   
  397.         cal = Calendar.getInstance();  
  398.         cal.add(Calendar.DATE, -compressBackupsAfterDays);  
  399.         Date cutoffZip = cal.getTime();  
  400.   
  401.         cal = Calendar.getInstance();  
  402.         cal.add(Calendar.DATE, -compressMaxNumberDays);  
  403.         Date cutoffDelZip = cal.getTime();  
  404.   
  405.         if (file.getParentFile().exists()) {  
  406.             File[] files = file.getParentFile().listFiles(new StartsWithFileFilter(file.getName(), false));  
  407.             int nameLength = file.getName().length();  
  408.             for (int i = 0; i < files.length; i++) {  
  409.                 String datePart = null;  
  410.                 try {  
  411.                     datePart = files[i].getName().substring(nameLength);  
  412.                     Date date = sdf.parse(datePart);  
  413.                     // cutoffDate for deletion should be further back than  
  414.                     // cutoff for backup  
  415.                     if (date.before(cutoffDate)) {  
  416.                         files[i].delete();  
  417.                     } else if (getCompressBackups().equalsIgnoreCase("YES")  
  418.                             || getCompressBackups().equalsIgnoreCase("TRUE")) {  
  419.                         if (date.before(cutoffZip)) {  
  420.                             zipAndDelete(files[i], cutoffZip);  
  421.                         }  
  422.                     }  
  423.                 } catch (ParseException pe) {  
  424.                     // Ignore - bad parse format, not a log file, current log  
  425.                     // file, or bad format on log file  
  426.                 } catch (Exception e) {  
  427.                     LogLog.warn("Failed to process file " + files[i].getName(), e);  
  428.                 }  
  429.                 try {  
  430.                     if ((getRollCompressedBackups().equalsIgnoreCase("YES") || getRollCompressedBackups()  
  431.                             .equalsIgnoreCase("TRUE"))  
  432.                             && files[i].getName().endsWith(".zip")) {  
  433.                         datePart = files[i].getName().substring(nameLength, files[i].getName().length() - 4);  
  434.                         Date date = new SimpleDateFormat(compressBackupsDatePattern).parse(datePart);  
  435.                         if (date.before(cutoffDelZip)) {  
  436.                             files[i].delete();  
  437.                         }  
  438.                     }  
  439.                 } catch (ParseException e) {  
  440.                     // Ignore - parse exceptions mean that format is wrong or  
  441.                     // there are other files in this dir  
  442.                 } catch (Exception e) {  
  443.                     LogLog.warn("Evaluating archive file for rolling failed: " + files[i].getName(), e);  
  444.                 }  
  445.             }  
  446.         }  
  447.         rollOver();  
  448.     }  
  449.   
  450.     /** 
  451.      * Compresses the passed file to a .zip file, stores the .zip in the same directory as the passed file, and then 
  452.      * deletes the original, leaving only the .zipped archive. 
  453.      * @param file 
  454.      */  
  455.     private void zipAndDelete(File file, Date cutoffZip) throws IOException {  
  456.         if (!file.getName().endsWith(".zip")) {  
  457.             String rootLogFileName = new File(fileName).getName();  
  458.             String datePart = file.getName().substring(rootLogFileName.length());  
  459.             String fileRoot = file.getName().substring(0, file.getName().indexOf(datePart));  
  460.             SimpleDateFormat sdf = new SimpleDateFormat(getCompressBackupsDatePattern());  
  461.             String newFile = fileRoot + sdf.format(cutoffZip);  
  462.             File zipFile = new File(file.getParent(), newFile + ".zip");  
  463.   
  464.             if (zipFile.exists()) {  
  465.                 addFilesToExistingZip(zipFile, new File[] { file });  
  466.             } else {  
  467.   
  468.                 FileInputStream fis = new FileInputStream(file);  
  469.                 FileOutputStream fos = new FileOutputStream(zipFile);  
  470.                 ZipOutputStream zos = new ZipOutputStream(fos);  
  471.                 ZipEntry zipEntry = new ZipEntry(file.getName());  
  472.                 zos.putNextEntry(zipEntry);  
  473.   
  474.                 byte[] buffer = new byte[4096];  
  475.                 while (true) {  
  476.                     int bytesRead = fis.read(buffer);  
  477.                     if (bytesRead == -1)  
  478.                         break;  
  479.                     else {  
  480.                         zos.write(buffer, 0, bytesRead);  
  481.                     }  
  482.                 }  
  483.                 zos.closeEntry();  
  484.                 fis.close();  
  485.                 zos.close();  
  486.             }  
  487.             file.delete();  
  488.         }  
  489.     }  
  490.   
  491.     /** 
  492.      * This is used to add files to a zip that already exits. 
  493.      * @param zipFile 
  494.      * @param files 
  495.      * @throws IOException 
  496.      */  
  497.     public static void addFilesToExistingZip(File zipFile, File[] files) throws IOException {  
  498.         // get a temp file  
  499.         File tempFile = File.createTempFile(zipFile.getName(), null);  
  500.         // delete it, otherwise you cannot rename your existing zip to it.  
  501.         tempFile.delete();  
  502.   
  503.         boolean renameOk = zipFile.renameTo(tempFile);  
  504.         if (!renameOk) {  
  505.             throw new RuntimeException("could not rename the file " + zipFile.getAbsolutePath() + " to "  
  506.                     + tempFile.getAbsolutePath());  
  507.         }  
  508.         byte[] buf = new byte[1024];  
  509.   
  510.         ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));  
  511.         ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));  
  512.   
  513.         ZipEntry entry = zin.getNextEntry();  
  514.         while (entry != null) {  
  515.             String name = entry.getName();  
  516.             boolean notInFiles = true;  
  517.             for (File f : files) {  
  518.                 if (f.getName().equals(name)) {  
  519.                     notInFiles = false;  
  520.                     break;  
  521.                 }  
  522.             }  
  523.             if (notInFiles) {  
  524.                 // Add ZIP entry to output stream.  
  525.                 out.putNextEntry(new ZipEntry(name));  
  526.                 // Transfer bytes from the ZIP file to the output file  
  527.                 int len;  
  528.                 while ((len = zin.read(buf)) > 0) {  
  529.                     out.write(buf, 0, len);  
  530.                 }  
  531.             }  
  532.             entry = zin.getNextEntry();  
  533.         }  
  534.         // Close the streams  
  535.         zin.close();  
  536.         // Compress the files  
  537.         for (int i = 0; i < files.length; i++) {  
  538.             InputStream in = new FileInputStream(files[i]);  
  539.             // Add ZIP entry to output stream.  
  540.             out.putNextEntry(new ZipEntry(files[i].getName()));  
  541.             // Transfer bytes from the file to the ZIP file  
  542.             int len;  
  543.             while ((len = in.read(buf)) > 0) {  
  544.                 out.write(buf, 0, len);  
  545.             }  
  546.             // Complete the entry  
  547.             out.closeEntry();  
  548.             in.close();  
  549.         }  
  550.         // Complete the ZIP file  
  551.         out.close();  
  552.         tempFile.delete();  
  553.     }  
  554.   
  555.     public String getCompressBackupsAfterDays() {  
  556.         return "" + compressBackupsAfterDays;  
  557.     }  
  558.   
  559.     public void setCompressBackupsAfterDays(String days) {  
  560.         try {  
  561.             compressBackupsAfterDays = Integer.parseInt(days);  
  562.         } catch (Exception e) {  
  563.             // ignore - just use default  
  564.         }  
  565.     }  
  566.   
  567.     public String getCompressBackupsDatePattern() {  
  568.         return compressBackupsDatePattern;  
  569.     }  
  570.   
  571.     public void setCompressBackupsDatePattern(String pattern) {  
  572.         compressBackupsDatePattern = pattern;  
  573.     }  
  574.   
  575.     public String getCompressMaxNumberDays() {  
  576.         return compressMaxNumberDays + "";  
  577.     }  
  578.   
  579.     public void setCompressMaxNumberDays(String days) {  
  580.         try {  
  581.             this.compressMaxNumberDays = Integer.parseInt(days);  
  582.         } catch (Exception e) {  
  583.             // ignore - just use default  
  584.         }  
  585.     }  
  586.   
  587.     public String getRollCompressedBackups() {  
  588.         return rollCompressedBackups;  
  589.     }  
  590.   
  591.     public void setRollCompressedBackups(String rollCompressedBackups) {  
  592.         this.rollCompressedBackups = rollCompressedBackups;  
  593.     }  
  594.   
  595. }  
  596.   
  597. class StartsWithFileFilter implements FileFilter {  
  598.     private String startsWith;  
  599.     private boolean inclDirs = false;  
  600.   
  601.     /** 
  602.      *  
  603.      */  
  604.     public StartsWithFileFilter(String startsWith, boolean includeDirectories) {  
  605.         super();  
  606.         this.startsWith = startsWith.toUpperCase();  
  607.         inclDirs = includeDirectories;  
  608.     }  
  609.   
  610.     /* 
  611.      * (non-Javadoc) 
  612.      * @see java.io.FileFilter#accept(java.io.File) 
  613.      */  
  614.     @Override  
  615.     public boolean accept(File pathname) {  
  616.         if (!inclDirs && pathname.isDirectory()) {  
  617.             return false;  
  618.         } else  
  619.             return pathname.getName().toUpperCase().startsWith(startsWith);  
  620.     }  
  621. }  
  622.   
  623. /** 
  624. * RollingCalendar is a helper class to AdvancedDailyRollingFileAppender. Given a periodicity type and the current time, 
  625. * it computes the start of the next interval. 
  626. */  
  627. class RollingCalendar extends GregorianCalendar {  
  628.     private static final long serialVersionUID = -3560331770601814177L;  
  629.   
  630.     int type = AdvancedDailyRollingFileAppender.TOP_OF_TROUBLE;  
  631.   
  632.     RollingCalendar() {  
  633.         super();  
  634.     }  
  635.   
  636.     RollingCalendar(TimeZone tz, Locale locale) {  
  637.         super(tz, locale);  
  638.     }  
  639.   
  640.     void setType(int type) {  
  641.         this.type = type;  
  642.     }  
  643.   
  644.     public long getNextCheckMillis(Date now) {  
  645.         return getNextCheckDate(now).getTime();  
  646.     }  
  647.   
  648.     public Date getNextCheckDate(Date now) {  
  649.         this.setTime(now);  
  650.   
  651.         switch (type) {  
  652.             case AdvancedDailyRollingFileAppender.TOP_OF_MINUTE:  
  653.                 this.set(Calendar.SECOND, 0);  
  654.                 this.set(Calendar.MILLISECOND, 0);  
  655.                 this.add(Calendar.MINUTE, 1);  
  656.                 break;  
  657.             case AdvancedDailyRollingFileAppender.TOP_OF_HOUR:  
  658.                 this.set(Calendar.MINUTE, 0);  
  659.                 this.set(Calendar.SECOND, 0);  
  660.                 this.set(Calendar.MILLISECOND, 0);  
  661.                 this.add(Calendar.HOUR_OF_DAY, 1);  
  662.                 break;  
  663.             case AdvancedDailyRollingFileAppender.HALF_DAY:  
  664.                 this.set(Calendar.MINUTE, 0);  
  665.                 this.set(Calendar.SECOND, 0);  
  666.                 this.set(Calendar.MILLISECOND, 0);  
  667.                 int hour = get(Calendar.HOUR_OF_DAY);  
  668.                 if (hour < 12) {  
  669.                     this.set(Calendar.HOUR_OF_DAY, 12);  
  670.                 } else {  
  671.                     this.set(Calendar.HOUR_OF_DAY, 0);  
  672.                     this.add(Calendar.DAY_OF_MONTH, 1);  
  673.                 }  
  674.                 break;  
  675.             case AdvancedDailyRollingFileAppender.TOP_OF_DAY:  
  676.                 this.set(Calendar.HOUR_OF_DAY, 0);  
  677.                 this.set(Calendar.MINUTE, 0);  
  678.                 this.set(Calendar.SECOND, 0);  
  679.                 this.set(Calendar.MILLISECOND, 0);  
  680.                 this.add(Calendar.DATE, 1);  
  681.                 break;  
  682.             case AdvancedDailyRollingFileAppender.TOP_OF_WEEK:  
  683.                 this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());  
  684.                 this.set(Calendar.HOUR_OF_DAY, 0);  
  685.                 this.set(Calendar.MINUTE, 0);  
  686.                 this.set(Calendar.SECOND, 0);  
  687.                 this.set(Calendar.MILLISECOND, 0);  
  688.                 this.add(Calendar.WEEK_OF_YEAR, 1);  
  689.                 break;  
  690.             case AdvancedDailyRollingFileAppender.TOP_OF_MONTH:  
  691.                 this.set(Calendar.DATE, 1);  
  692.                 this.set(Calendar.HOUR_OF_DAY, 0);  
  693.                 this.set(Calendar.MINUTE, 0);  
  694.                 this.set(Calendar.SECOND, 0);  
  695.                 this.set(Calendar.MILLISECOND, 0);  
  696.                 this.add(Calendar.MONTH, 1);  
  697.                 break;  
  698.             default:  
  699.                 throw new IllegalStateException("Unknown periodicity type.");  
  700.         }  
  701.         return getTime();  
  702.     }  
  703. }  



注:原作者的实现代码有两个bug: 如果设置7天, 结果只留下了6天的日志;另外一个就是在我的应用中发现删除文件的目录指定不对.另外一个就是删除只跟文件的名(比如这里的default.log)相关, 而跟生成的具体rotate log文件的格式(比如default.log.2012-01-12)是无关. 比如default.log.bak这样的文件也认为是7天文件中的一个. 

第二种实现方案: 
http://www.codeproject.com/KB/java/CustomDailyRollingFileApp.aspx 

Java代码  收藏代码
  1. /* 
  2. * Licensed to the Apache Software Foundation (ASF) under one or more 
  3. * contributor license agreements. See the NOTICE file distributed with 
  4. * this work for additional information regarding copyright ownership. 
  5. * The ASF licenses this file to You under the Apache License, Version 2.0 
  6. * (the "License"); you may not use this file except in compliance with 
  7. * the License. You may obtain a copy of the License at 
  8. * http://www.apache.org/licenses/LICENSE-2.0 
  9. * Unless required by applicable law or agreed to in writing, software 
  10. * distributed under the License is distributed on an "AS IS" BASIS, 
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  12. * See the License for the specific language governing permissions and 
  13. * limitations under the License. 
  14. */  
  15.   
  16. package logger;  
  17.   
  18. import java.io.File;  
  19. import java.io.FilenameFilter;  
  20. import java.io.IOException;  
  21. import java.io.InterruptedIOException;  
  22. import java.io.Serializable;  
  23. import java.net.URI;  
  24. import java.text.SimpleDateFormat;  
  25. import java.util.ArrayList;  
  26. import java.util.Calendar;  
  27. import java.util.Collections;  
  28. import java.util.Date;  
  29. import java.util.GregorianCalendar;  
  30. import java.util.List;  
  31. import java.util.Locale;  
  32. import java.util.TimeZone;  
  33.   
  34. import org.apache.log4j.FileAppender;  
  35. import org.apache.log4j.Layout;  
  36. import org.apache.log4j.helpers.LogLog;  
  37. import org.apache.log4j.spi.LoggingEvent;  
  38.   
  39. /** 
  40. DailyRollingFileAppender extends {@link FileAppender} so that the 
  41. underlying file is rolled over at a user chosen frequency. 
  42.  
  43. DailyRollingFileAppender has been observed to exhibit 
  44. synchronization issues and data loss.  The log4j extras 
  45. companion includes alternatives which should be considered 
  46. for new deployments and which are discussed in the documentation 
  47. for org.apache.log4j.rolling.RollingFileAppender. 
  48.  
  49. <p>The rolling schedule is specified by the <b>DatePattern</b> 
  50. option. This pattern should follow the {@link SimpleDateFormat} 
  51. conventions. In particular, you <em>must</em> escape literal text 
  52. within a pair of single quotes. A formatted version of the date 
  53. pattern is used as the suffix for the rolled file name. 
  54.  
  55. <p>For example, if the <b>File</b> option is set to 
  56. <code>/foo/bar.log</code> and the <b>DatePattern</b> set to 
  57. <code>'.'yyyy-MM-dd</code>, on 2001-02-16 at midnight, the logging 
  58. file <code>/foo/bar.log</code> will be copied to 
  59. <code>/foo/bar.log.2001-02-16</code> and logging for 2001-02-17 
  60. will continue in <code>/foo/bar.log</code> until it rolls over 
  61. the next day. 
  62.  
  63. <p>Is is possible to specify monthly, weekly, half-daily, daily, 
  64. hourly, or minutely rollover schedules. 
  65.  
  66. <p><table border="1" cellpadding="2"> 
  67. <tr> 
  68. <th>DatePattern</th> 
  69. <th>Rollover schedule</th> 
  70. <th>Example</th> 
  71.  
  72. <tr> 
  73. <td><code>'.'yyyy-MM</code> 
  74. <td>Rollover at the beginning of each month</td> 
  75.  
  76. <td>At midnight of May 31st, 2002 <code>/foo/bar.log</code> will be 
  77. copied to <code>/foo/bar.log.2002-05</code>. Logging for the month 
  78. of June will be output to <code>/foo/bar.log</code> until it is 
  79. also rolled over the next month. 
  80.  
  81. <tr> 
  82. <td><code>'.'yyyy-ww</code> 
  83.  
  84. <td>Rollover at the first day of each week. The first day of the 
  85. week depends on the locale.</td> 
  86.  
  87. <td>Assuming the first day of the week is Sunday, on Saturday 
  88. midnight, June 9th 2002, the file <i>/foo/bar.log</i> will be 
  89. copied to <i>/foo/bar.log.2002-23</i>.  Logging for the 24th week 
  90. of 2002 will be output to <code>/foo/bar.log</code> until it is 
  91. rolled over the next week. 
  92.  
  93. <tr> 
  94. <td><code>'.'yyyy-MM-dd</code> 
  95.  
  96. <td>Rollover at midnight each day.</td> 
  97.  
  98. <td>At midnight, on March 8th, 2002, <code>/foo/bar.log</code> will 
  99. be copied to <code>/foo/bar.log.2002-03-08</code>. Logging for the 
  100. 9th day of March will be output to <code>/foo/bar.log</code> until 
  101. it is rolled over the next day. 
  102.  
  103. <tr> 
  104. <td><code>'.'yyyy-MM-dd-a</code> 
  105.  
  106. <td>Rollover at midnight and midday of each day.</td> 
  107.  
  108. <td>At noon, on March 9th, 2002, <code>/foo/bar.log</code> will be 
  109. copied to <code>/foo/bar.log.2002-03-09-AM</code>. Logging for the 
  110. afternoon of the 9th will be output to <code>/foo/bar.log</code> 
  111. until it is rolled over at midnight. 
  112.  
  113. <tr> 
  114. <td><code>'.'yyyy-MM-dd-HH</code> 
  115.  
  116. <td>Rollover at the top of every hour.</td> 
  117.  
  118. <td>At approximately 11:00.000 o'clock on March 9th, 2002, 
  119. <code>/foo/bar.log</code> will be copied to 
  120. <code>/foo/bar.log.2002-03-09-10</code>. Logging for the 11th hour 
  121. of the 9th of March will be output to <code>/foo/bar.log</code> 
  122. until it is rolled over at the beginning of the next hour. 
  123.  
  124.  
  125. <tr> 
  126. <td><code>'.'yyyy-MM-dd-HH-mm</code> 
  127.  
  128. <td>Rollover at the beginning of every minute.</td> 
  129.  
  130. <td>At approximately 11:23,000, on March 9th, 2001, 
  131. <code>/foo/bar.log</code> will be copied to 
  132. <code>/foo/bar.log.2001-03-09-10-22</code>. Logging for the minute 
  133. of 11:23 (9th of March) will be output to 
  134. <code>/foo/bar.log</code> until it is rolled over the next minute. 
  135.  
  136. </table> 
  137.  
  138. <p>Do not use the colon ":" character in anywhere in the 
  139. <b>DatePattern</b> option. The text before the colon is interpeted 
  140. as the protocol specificaion of a URL which is probably not what 
  141. you want. 
  142.  
  143.  
  144. @author Eirik Lygre 
  145. @author Ceki G&uuml;lc&uuml; 
  146. <br/> <br/> 
  147. <b>Important Note:</b> 
  148. This is modified version of <code>DailyRollingFileAppender</code>. I have just added <code>maxBackupIndex</code>. So, if your number of log files increased more than <code>maxBackupIndex</code> it will delete the older log files. 
  149. The modified code only tested on Windows Operating System. If it have any issue on any other platform please modified it accordingly. 
  150. @ModifiedBy: Bikash Shaw 
  151. */  
  152. public class CustomDailyRollingFileAppender extends FileAppender {  
  153.   
  154.     // The code assumes that the following constants are in a increasing  
  155.     // sequence.  
  156.     static final int TOP_OF_TROUBLE = -1;  
  157.     static final int TOP_OF_MINUTE = 0;  
  158.     static final int TOP_OF_HOUR = 1;  
  159.     static final int HALF_DAY = 2;  
  160.     static final int TOP_OF_DAY = 3;  
  161.     static final int TOP_OF_WEEK = 4;  
  162.     static final int TOP_OF_MONTH = 5;  
  163.   
  164.     /** 
  165.        The date pattern. By default, the pattern is set to 
  166.        "'.'yyyy-MM-dd" meaning daily rollover. 
  167.      */  
  168.     private String datePattern = "'.'yyyy-MM-dd";  
  169.     /** 
  170.     There is one backup file by default. 
  171.      */  
  172.     protected int maxBackupIndex = 1;  
  173.   
  174.     /** 
  175.        The log file will be renamed to the value of the 
  176.        scheduledFilename variable when the next interval is entered. For 
  177.        example, if the rollover period is one hour, the log file will be 
  178.        renamed to the value of "scheduledFilename" at the beginning of 
  179.        the next hour. 
  180.  
  181.        The precise time when a rollover occurs depends on logging 
  182.        activity. 
  183.      */  
  184.     private String scheduledFilename;  
  185.   
  186.     /** 
  187.        The next time we estimate a rollover should occur. */  
  188.     private long nextCheck = System.currentTimeMillis() - 1;  
  189.   
  190.     Date now = new Date();  
  191.   
  192.     SimpleDateFormat sdf;  
  193.   
  194.     RollingCalendar rc = new RollingCalendar();  
  195.   
  196.     int checkPeriod = TOP_OF_TROUBLE;  
  197.   
  198.     // The gmtTimeZone is used only in computeCheckPeriod() method.  
  199.     static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");  
  200.   
  201.     /** 
  202.        The default constructor does nothing. */  
  203.     public CustomDailyRollingFileAppender() {  
  204.     }  
  205.   
  206.     /** 
  207.       Instantiate a <code>DailyRollingFileAppender</code> and open the 
  208.       file designated by <code>filename</code>. The opened filename will 
  209.       become the ouput destination for this appender. 
  210.  
  211.      */  
  212.     public CustomDailyRollingFileAppender(Layout layout, String filename,  
  213.             String datePattern) throws IOException {  
  214.         super(layout, filename, true);  
  215.         this.datePattern = datePattern;  
  216.         activateOptions();  
  217.     }  
  218.   
  219.     /** 
  220.        The <b>DatePattern</b> takes a string in the same format as 
  221.        expected by {@link SimpleDateFormat}. This options determines the 
  222.        rollover schedule. 
  223.      */  
  224.     public void setDatePattern(String pattern) {  
  225.         datePattern = pattern;  
  226.     }  
  227.   
  228.     /** 
  229.        Set the maximum number of backup files to keep around. 
  230.  
  231.        <p>The <b>MaxBackupIndex</b> option determines how many backup 
  232.        files are kept before the oldest is erased. This option takes 
  233.        a positive integer value. If set to zero, then there will be no 
  234.        backup files and the log file will be truncated when it reaches 
  235.        <code>MaxFileSize</code>. 
  236.      */  
  237.     public void setMaxBackupIndex(int maxBackups) {  
  238.         this.maxBackupIndex = maxBackups;  
  239.     }  
  240.   
  241.     /** 
  242.     Returns the value of the <b>MaxBackupIndex</b> option. 
  243.      */  
  244.     public int getMaxBackupIndex() {  
  245.         return maxBackupIndex;  
  246.     }  
  247.   
  248.     /** Returns the value of the <b>DatePattern</b> option. */  
  249.     public String getDatePattern() {  
  250.         return datePattern;  
  251.     }  
  252.   
  253.     @Override  
  254.     public void activateOptions() {  
  255.         super.activateOptions();  
  256.         if (datePattern != null && fileName != null) {  
  257.             now.setTime(System.currentTimeMillis());  
  258.             sdf = new SimpleDateFormat(datePattern);  
  259.             int type = computeCheckPeriod();  
  260.             printPeriodicity(type);  
  261.             rc.setType(type);  
  262.             File file = new File(fileName);  
  263.             scheduledFilename = fileName  
  264.                     + sdf.format(new Date(file.lastModified()));  
  265.   
  266.         } else {  
  267.             LogLog  
  268.                     .error("Either File or DatePattern options are not set for appender ["  
  269.                             + name + "].");  
  270.         }  
  271.     }  
  272.   
  273.     void printPeriodicity(int type) {  
  274.         switch (type) {  
  275.             case TOP_OF_MINUTE:  
  276.                 LogLog.debug("Appender [" + name + "] to be rolled every minute.");  
  277.                 break;  
  278.             case TOP_OF_HOUR:  
  279.                 LogLog.debug("Appender [" + name  
  280.                         + "] to be rolled on top of every hour.");  
  281.                 break;  
  282.             case HALF_DAY:  
  283.                 LogLog.debug("Appender [" + name  
  284.                         + "] to be rolled at midday and midnight.");  
  285.                 break;  
  286.             case TOP_OF_DAY:  
  287.                 LogLog.debug("Appender [" + name + "] to be rolled at midnight.");  
  288.                 break;  
  289.             case TOP_OF_WEEK:  
  290.                 LogLog.debug("Appender [" + name  
  291.                         + "] to be rolled at start of week.");  
  292.                 break;  
  293.             case TOP_OF_MONTH:  
  294.                 LogLog.debug("Appender [" + name  
  295.                         + "] to be rolled at start of every month.");  
  296.                 break;  
  297.             default:  
  298.                 LogLog.warn("Unknown periodicity for appender [" + name + "].");  
  299.         }  
  300.     }  
  301.   
  302.     // This method computes the roll over period by looping over the  
  303.     // periods, starting with the shortest, and stopping when the r0 is  
  304.     // different from from r1, where r0 is the epoch formatted according  
  305.     // the datePattern (supplied by the user) and r1 is the  
  306.     // epoch+nextMillis(i) formatted according to datePattern. All date  
  307.     // formatting is done in GMT and not local format because the test  
  308.     // logic is based on comparisons relative to 1970-01-01 00:00:00  
  309.     // GMT (the epoch).  
  310.   
  311.     int computeCheckPeriod() {  
  312.         RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone,  
  313.                 Locale.getDefault());  
  314.         // set sate to 1970-01-01 00:00:00 GMT  
  315.         Date epoch = new Date(0);  
  316.         if (datePattern != null) {  
  317.             for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {  
  318.                 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(  
  319.                         datePattern);  
  320.                 simpleDateFormat.setTimeZone(gmtTimeZone); // do all date  
  321.                                                            // formatting in GMT  
  322.                 String r0 = simpleDateFormat.format(epoch);  
  323.                 rollingCalendar.setType(i);  
  324.                 Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));  
  325.                 String r1 = simpleDateFormat.format(next);  
  326.                 // System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);  
  327.                 if (r0 != null && r1 != null && !r0.equals(r1)) {  
  328.                     return i;  
  329.                 }  
  330.             }  
  331.         }  
  332.         return TOP_OF_TROUBLE; // Deliberately head for trouble...  
  333.     }  
  334.   
  335.     /** 
  336.        Rollover the current file to a new file. 
  337.      */  
  338.     void rollOver() throws IOException {  
  339.   
  340.         List<ModifiedTimeSortableFile> files = getAllFiles();  
  341.         Collections.sort(files);  
  342.         if (files.size() >= maxBackupIndex) {  
  343.             int index = 0;  
  344.             int diff = files.size() - (maxBackupIndex - 1);  
  345.             for (ModifiedTimeSortableFile file : files) {  
  346.                 if (index >= diff)  
  347.                     break;  
  348.   
  349.                 file.delete();  
  350.                 index++;  
  351.             }  
  352.         }  
  353.   
  354.         /* Compute filename, but only if datePattern is specified */  
  355.         if (datePattern == null) {  
  356.             errorHandler.error("Missing DatePattern option in rollOver().");  
  357.             return;  
  358.         }  
  359.         LogLog.debug("maxBackupIndex=" + maxBackupIndex);  
  360.   
  361.         String datedFilename = fileName + sdf.format(now);  
  362.         // It is too early to roll over because we are still within the  
  363.         // bounds of the current interval. Rollover will occur once the  
  364.         // next interval is reached.  
  365.         if (scheduledFilename.equals(datedFilename)) {  
  366.             return;  
  367.         }  
  368.   
  369.         // close current file, and rename it to datedFilename  
  370.         this.closeFile();  
  371.   
  372.         File target = new File(scheduledFilename);  
  373.         if (target.exists()) {  
  374.             target.delete();  
  375.         }  
  376.   
  377.         File file = new File(fileName);  
  378.         boolean result = file.renameTo(target);  
  379.         if (result) {  
  380.             LogLog.debug(fileName + " -> " + scheduledFilename);  
  381.         } else {  
  382.             LogLog.error("Failed to rename [" + fileName + "] to ["  
  383.                     + scheduledFilename + "].");  
  384.         }  
  385.   
  386.         try {  
  387.             // This will also close the file. This is OK since multiple  
  388.             // close operations are safe.  
  389.             this.setFile(fileName, truethis.bufferedIO, this.bufferSize);  
  390.         } catch (IOException e) {  
  391.             errorHandler.error("setFile(" + fileName + ", true) call failed.");  
  392.         }  
  393.         scheduledFilename = datedFilename;  
  394.     }  
  395.   
  396.     /** 
  397.      * This method differentiates DailyRollingFileAppender from its 
  398.      * super class. 
  399.      * 
  400.      * <p>Before actually logging, this method will check whether it is 
  401.      * time to do a rollover. If it is, it will schedule the next 
  402.      * rollover time and then rollover. 
  403.      * */  
  404.     @Override  
  405.     protected void subAppend(LoggingEvent event) {  
  406.         long n = System.currentTimeMillis();  
  407.         if (n >= nextCheck) {  
  408.             now.setTime(n);  
  409.             nextCheck = rc.getNextCheckMillis(now);  
  410.             try {  
  411.                 rollOver();  
  412.             } catch (IOException ioe) {  
  413.                 if (ioe instanceof InterruptedIOException) {  
  414.                     Thread.currentThread().interrupt();  
  415.                 }  
  416.                 LogLog.error("rollOver() failed.", ioe);  
  417.             }  
  418.         }  
  419.         super.subAppend(event);  
  420.     }  
  421.   
  422.     /** 
  423.      * This method searches list of log files 
  424.      * based on the pattern given in the log4j configuration file 
  425.      * and returns a collection  
  426.      * @return List&lt;ModifiedTimeSortableFile&gt; 
  427.      */  
  428.     private List<ModifiedTimeSortableFile> getAllFiles() {  
  429.         List<ModifiedTimeSortableFile> files = new ArrayList<ModifiedTimeSortableFile>();  
  430.         FilenameFilter filter = new FilenameFilter() {  
  431.             @Override  
  432.             public boolean accept(File dir, String name) {  
  433.                 String directoryName = dir.getPath();  
  434.                 LogLog.debug("directory name: " + directoryName);  
  435.                 File file = new File(fileName);  
  436.                 String perentDirectory = file.getParent();  
  437.                 if (perentDirectory != null)  
  438.                 {  
  439.                     String localFile = fileName.substring(directoryName.length());  
  440.                     return name.startsWith(localFile);  
  441.                 }  
  442.                 return name.startsWith(fileName);  
  443.             }  
  444.         };  
  445.         File file = new File(fileName);  
  446.         String perentDirectory = file.getParent();  
  447.         if (file.exists()) {  
  448.             if (file.getParent() == null) {  
  449.                 String absolutePath = file.getAbsolutePath();  
  450.                 perentDirectory = absolutePath.substring(0, absolutePath.lastIndexOf(fileName));  
  451.   
  452.             }  
  453.         }  
  454.         File dir = new File(perentDirectory);  
  455.         String[] names = dir.list(filter);  
  456.   
  457.         for (int i = 0; i < names.length; i++) {  
  458.             files.add(new ModifiedTimeSortableFile(dir + System.getProperty("file.separator") + names[i]));  
  459.         }  
  460.         return files;  
  461.     }  
  462. }  
  463.   
  464. /** 
  465. * The Class ModifiedTimeSortableFile extends java.io.File class and 
  466. * implements Comparable to sort files list based upon their modified date 
  467. */  
  468. class ModifiedTimeSortableFile extends File implements Serializable, Comparable<File> {  
  469.     private static final long serialVersionUID = 1373373728209668895L;  
  470.   
  471.     public ModifiedTimeSortableFile(String parent, String child) {  
  472.         super(parent, child);  
  473.         // TODO Auto-generated constructor stub  
  474.     }  
  475.   
  476.     public ModifiedTimeSortableFile(URI uri) {  
  477.         super(uri);  
  478.         // TODO Auto-generated constructor stub  
  479.     }  
  480.   
  481.     public ModifiedTimeSortableFile(File parent, String child) {  
  482.         super(parent, child);  
  483.     }  
  484.   
  485.     public ModifiedTimeSortableFile(String string) {  
  486.         super(string);  
  487.     }  
  488.   
  489.     @Override  
  490.     public int compareTo(File anotherPathName) {  
  491.         long thisVal = this.lastModified();  
  492.         long anotherVal = anotherPathName.lastModified();  
  493.         return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1));  
  494.     }  
  495. }  
  496.   
  497. /** 
  498. *  RollingCalendar is a helper class to DailyRollingFileAppender. 
  499. *  Given a periodicity type and the current time, it computes the 
  500. *  start of the next interval.  
  501. * */  
  502. class RollingCalendar extends GregorianCalendar {  
  503.     private static final long serialVersionUID = -3560331770601814177L;  
  504.   
  505.     int type = CustomDailyRollingFileAppender.TOP_OF_TROUBLE;  
  506.   
  507.     RollingCalendar() {  
  508.         super();  
  509.     }  
  510.   
  511.     RollingCalendar(TimeZone tz, Locale locale) {  
  512.         super(tz, locale);  
  513.     }  
  514.   
  515.     void setType(int type) {  
  516.         this.type = type;  
  517.     }  
  518.   
  519.     public long getNextCheckMillis(Date now) {  
  520.         return getNextCheckDate(now).getTime();  
  521.     }  
  522.   
  523.     public Date getNextCheckDate(Date now) {  
  524.         this.setTime(now);  
  525.   
  526.         switch (type) {  
  527.             case CustomDailyRollingFileAppender.TOP_OF_MINUTE:  
  528.                 this.set(Calendar.SECOND, 0);  
  529.                 this.set(Calendar.MILLISECOND, 0);  
  530.                 this.add(Calendar.MINUTE, 1);  
  531.                 break;  
  532.             case CustomDailyRollingFileAppender.TOP_OF_HOUR:  
  533.                 this.set(Calendar.MINUTE, 0);  
  534.                 this.set(Calendar.SECOND, 0);  
  535.                 this.set(Calendar.MILLISECOND, 0);  
  536.                 this.add(Calendar.HOUR_OF_DAY, 1);  
  537.                 break;  
  538.             case CustomDailyRollingFileAppender.HALF_DAY:  
  539.                 this.set(Calendar.MINUTE, 0);  
  540.                 this.set(Calendar.SECOND, 0);  
  541.                 this.set(Calendar.MILLISECOND, 0);  
  542.                 int hour = get(Calendar.HOUR_OF_DAY);  
  543.                 if (hour < 12) {  
  544.                     this.set(Calendar.HOUR_OF_DAY, 12);  
  545.                 } else {  
  546.                     this.set(Calendar.HOUR_OF_DAY, 0);  
  547.                     this.add(Calendar.DAY_OF_MONTH, 1);  
  548.                 }  
  549.                 break;  
  550.             case CustomDailyRollingFileAppender.TOP_OF_DAY:  
  551.                 this.set(Calendar.HOUR_OF_DAY, 0);  
  552.                 this.set(Calendar.MINUTE, 0);  
  553.                 this.set(Calendar.SECOND, 0);  
  554.                 this.set(Calendar.MILLISECOND, 0);  
  555.                 this.add(Calendar.DATE, 1);  
  556.                 break;  
  557.             case CustomDailyRollingFileAppender.TOP_OF_WEEK:  
  558.                 this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());  
  559.                 this.set(Calendar.HOUR_OF_DAY, 0);  
  560.                 this.set(Calendar.MINUTE, 0);  
  561.                 this.set(Calendar.SECOND, 0);  
  562.                 this.set(Calendar.MILLISECOND, 0);  
  563.                 this.add(Calendar.WEEK_OF_YEAR, 1);  
  564.                 break;  
  565.             case CustomDailyRollingFileAppender.TOP_OF_MONTH:  
  566.                 this.set(Calendar.DATE, 1);  
  567.                 this.set(Calendar.HOUR_OF_DAY, 0);  
  568.                 this.set(Calendar.MINUTE, 0);  
  569.                 this.set(Calendar.SECOND, 0);  
  570.                 this.set(Calendar.MILLISECOND, 0);  
  571.                 this.add(Calendar.MONTH, 1);  
  572.                 break;  
  573.             default:  
  574.                 throw new IllegalStateException("Unknown periodicity type.");  
  575.         }  
  576.         return getTime();  
  577.     }  
  578.   
  579. }  


这个解决方案就跟名字一样, 具有更多的高级功能, 比如压缩归档, 但是我不需要:( 不过它解决了第一种解决方案的问题, 比如只保留某种格式的文件. 

=http://wiki.apache.org/logging-log4j/DailyRollingFileAppender这个是log4j自带的定制的支持MaxBackupIndex的DailyRollingFileAppender 

分享到:
评论

相关推荐

    log4j删除前N天日志

    本话题将深入探讨如何使用Log4j中的DailyRollingFileAppender配置来自动删除前N天的日志,以便保持日志文件的大小和数量在可控范围内。 首先,DailyRollingFileAppender是Log4j中的一个Appender实现,它按照日期...

    log4j2 自动删除过期日志文件的配置及实现原理

    Log4j2 自动删除过期日志文件的配置及实现原理 Log4j2 是一个流行的日志记录工具,能够记录程序的运行日志,以便于程序员对程序进行调试和优化。然而,随着日志文件的增长,日志文件的管理变得越来越复杂。因此,...

    log4j配置和加载方法

    Log4j是一款由Apache出品的日志记录工具,它提供了灵活的日志级别控制和多样化的日志输出方式,广泛应用于Java应用的开发中。本文将深入解析log4j的配置与加载机制,帮助开发者更好地理解和应用log4j。 #### Log4j...

    log4j漏洞扫描工具

    1. **Log4j漏洞(Log4Shell)**:这是一个存在于Apache Log4j 2.x版本中的远程代码执行漏洞,由于日志框架允许攻击者通过特定的日志格式注入恶意代码,导致服务器被控制,影响广泛且严重。 2. **影响范围**:任何...

    log4j-1.2.16

    2. **日志拦截器**:Hibernate允许自定义事件监听器,我们可以创建一个实现了`org.hibernate.event.def.AbstractLogEventListener`的类,通过Log4j记录特定的事件,如对象持久化、更新或删除。 3. **日志级别控制**...

    Linux tomcat下catalina.out日志文件分割

    tomcat支持采用log4j进行日志记录,配置方法如下: 1.更新最新的tomcat_juli.jar包到./bin/目录下; 2.拷贝log4j.jar,lo4j.properties到./lib目录下; 3.删除./conf/logging.properties 4.重启 log4j配置样本 实例...

    myBaits所有jar包,包括log4j所需jar包,mysql所需jar包,导入后可以直接使用

    在Maven项目中,MyBatis、log4j和MySQL的依赖通常会以XML格式声明在pom.xml文件中,Maven会自动下载并管理这些依赖。Maven是一个项目管理和综合工具,它可以帮助开发者构建、测试、部署和管理Java项目,通过依赖管理...

    封装的log4cplus的日志库

    log4cplus是基于Apache log4j理念的一个C++日志库,它的设计目标是提供与log4j相似的功能,但针对C++语言进行了优化。log4cplus提供了灵活的日志级别,包括DEBUG、INFO、WARN、ERROR和FATAL,允许开发者控制不同级别...

    delphi xe5 下的日志类 log4d

    开源的log4d的日志功能很强大,可支持多线程并发记日志。...(3)可自动删除指定天数前的LOG文件。 有DEMO,有源码,log4d\test 就是DEMO。 注意:log4d\test\Win32\Debug\log4d.props 文件的配置。

    Log4jToRollingFileAppender.zip

    在Log4j中,`RollingFileAppender`是一个非常实用的组件,它能够自动管理日志文件的大小并进行滚动,以避免单一日志文件过大导致的问题。本文将深入探讨`RollingFileAppender`的使用方法及其配置细节。 1. **...

    10 reasons to use logback !------log4j他爹告诉你为何要使用新的日志包logback

    标题中的“10 reasons to use logback”是一个讨论日志框架选择的主题,它提出了使用logback而非其他日志工具(如log4j)的十个理由。logback是log4j的作者Ceki Gülcü创建的一个更现代、性能更优的日志框架。在...

    Log4j笔记.doc

    Log4j是一个开源的日志框架,由Apache Software Foundation开发。它允许开发者根据需要控制日志信息的输出等级及去向,使得日志记录变得非常灵活。Log4j的核心组件包括Logger、Appender和Layout。 #### 二、Logger:...

    idea 14 ssm 全注解框架+log4j+事物控制+mybatis基础Dao配置

    通过配置log4j.properties或log4j.xml文件,我们可以设置日志级别(DEBUG、INFO、WARN、ERROR等),选择日志输出目的地(控制台、文件、邮件等),并自定义日志格式。 事务控制在数据库操作中至关重要,确保数据的...

    log4j漏洞排查小工具

    扫描完成后,根据工具的指导进行必要的修复,如更新Log4j,修改配置文件,或者删除不必要的引用。同时,对整个网络环境进行一次全面的安全审查,确保其他可能存在的弱点也被妥善处理。 总之,“log4j漏洞排查小工具...

    log4j The Complete Manual

    ### Log4j完整手册知识点概览 ...综上所述,《完整的Log4j手册》为用户提供了关于Log4j的全面介绍,涵盖了从基本概念到高级特性的详细说明,旨在帮助用户更好地理解和使用Log4j进行高效、灵活的日志记录。

    轻量、易集成、易使用,有时甚至可以不需写代码的HarmonyOS log系统,灵感来自log4j

    格式化日志输出,借鉴log4j,贴合使用习惯。Logger统一管理,降低内存占用。支持格式化打印对象。通过设置日志级别,提供日志过滤服务。支持日志加密写出到文件。支持配置日志文件最大容量,溢出后新建日志文件。...

    搭建struts hibernate log4j spring(好东西)

    - 删除旧版本的`log4j.jar`文件,并替换为新版本。 - 在项目的`src`目录下创建`log4j.properties`文件,配置日志级别及输出格式。 #### 三、具体步骤 1. **Struts配置**: - 创建`struts-config.xml`文件,配置...

    c++开源日志log4cplus使用开发文档

    log4cplus是C++编写的开源日志系统,前身是java编写的log4j日志系统。log4cplus具有线程安全、灵活、以及多粒度控制的特点,通过将信息划分优先级使其可以面向程序调试、运行、测试、和维护等全生命周期; 你可以...

    log4j_appender:带有MaxBackupIndex的DailyRollingFileAppender

    在Java日志处理领域,Log4j是一个广泛使用的开源库,它为应用程序提供灵活的日志记录功能。在Log4j中,`DailyRollingFileAppender`是一个非常实用的组件,它能按照日期滚动生成日志文件,确保日志文件不会无限增长。...

Global site tag (gtag.js) - Google Analytics