Configuration Example

<appender name="FlatFileAppender" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="append" value="true" />
        <param name="encoding" value="UTF-8" />
        <param name="file" value="mylogfile.log" />
        <param name="DatePattern" value="'.'yyyy-MM-dd" />
        <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="[%-25d{ISO8601}] %-5p %x %C{1} -- %m\n" />
        </layout>
</appender>

Custom DailyRollingFileAppender with MaxBackupIndex

I've change the DailyRollingFileAppender to support the MaxBackupIndex, this is the class to add to the jar that contains the log4j library:

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

I'll hope can be usefull. MSC Recruitment Indonesia & MSC Crewing Indonesia | Building Signage | Anti Rayap | Pintu dan Jendela

DailyRollingFileAppender (last edited 2013-03-07 03:15:37 by tonyguards)