logging-log4j-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jim Moore <jim.mo...@veritas.com>
Subject RE: DailyRollingFileAppender
Date Mon, 02 Apr 2001 17:12:47 GMT
The way it's written, if the server is down and you restart it after the
roll-over time, then it does not do the roll-over.

Here's a version that acts more as expected:

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

import org.apache.log4j.*;
import org.apache.log4j.spi.*;
import org.apache.log4j.helpers.*;


/**
 * DailyRollingFileAppender extends {@link FileAppender} so that the
 * underlying file is rolled over at a user chosen frequency.
 * 
 * <p>The rolling schedule is specified by the <b>DatePattern</b>
 * option. This pattern should follow the {@link SimpleDateFormat}
 * conventions. In particular, you <em>must</em> escape literal text
 * within a pair of single quotes. A formatted version of the date
 * pattern is used as the suffix for the rolled file name.
 * 
 * <p>For example, if the <b>File</b> option is set to
 * <code>/foo/bar.log</code> and the <b>DatePattern</b> set to
 * <code>'.'yyyy-MM-dd</code>, on 2001-02-16 at midnight, the logging
 * file <code>/foo/bar.log</code> will be copied to
 * <code>/foo/bar.log.2001-02-16</code> and logging for 2001-02-17
 * will continue in <code>/foo/bar.log</code> until it is rolled over
 * itself the next day.
 * 
 * <p>Is is possible to specify monthly, weekly, half-daily, daily,
 * hourly, or minutely rollover schedules.
 * 
 * <p><table border="1">
 * <tr>
 * <th>DatePattern</th>
 * <th>Rollover schedule</th>
 * <th>Example</th>
 * 
 * <tr>
 * <td><code>'.'yyyy-MM</code>
 * <td>Rollover at the beginning of each month</td>
 * 
 * <td>Assuming the first day of the week is Sunday, at Sunday 00:00,
 * March 25th, 2001, <code>/foo/bar.log</code> will be copied to
 * <code>/foo/bar.log.2001-03</code>. Logging for the month of April
 * will be output to <code>/foo/bar.log</code> until it is rolled over
 * itself at the beginning of May.
 * 
 * <tr>
 * <td><code>'.'yyyy-ww</code>
 * 
 * <td>Rollover at the first day of each week. The first day of the
 * week depends on the locale.</td>
 * 
 * <td>At midnight, on March 31st, 2001, <code>/foo/bar.log</code>
 * will be copied to <code>/foo/bar.log.2001-08</code>. Logging for
 * the 9th week of 2001 will be output to <code>/foo/bar.log</code>
 * until it is rolled over the next week.
 * 
 * <tr>
 * <td><code>'.'yyyy-MM-dd</code>
 * 
 * <td>Rollover at midnight each day.</td>
 * 
 * <td>At midnight, on March 9th, 2001, <code>/foo/bar.log</code> will
 * be copied to <code>/foo/bar.log.2001-03-08</code>. Logging for the
 * 9th day of March will be output to <code>/foo/bar.log</code> until
 * it is rolled over the next day.
 * 
 * <tr>
 * <td><code>'.'yyyy-MM-dd-a</code>
 * 
 * <td>Rollover at midnight and midday of each day.</td>
 * 
 * <td>At noon, on March 9th, 2001, <code>/foo/bar.log</code> will be
 * copied to <code>/foo/bar.log.2001-03-09-AM</code>. Logging for the
 * afternoon of the 9th will be output to <code>/foo/bar.log</code>
 * until it is rolled over the next morning, i.e at midnight 00:00.
 * 
 * <tr>
 * <td><code>'.'yyyy-MM-dd-HH</code>
 * 
 * <td>Rollover at the top of every hour.</td>
 * 
 * <td>At approximately 11:00,000, on March 9th, 2001,
 * <code>/foo/bar.log</code> will be copied to
 * <code>/foo/bar.log.2001-03-09-10</code>. Logging for the 11th hour
 * of of the 9th of March will be output to <code>/foo/bar.log</code>
 * until it is rolled over at the beginning of the next hour.
 * 
 * 
 * <tr>
 * <td><code>'.'yyyy-MM-dd-HH-mm</code>
 * 
 * <td>Rollover at the beginning of every minutue.</td>
 * 
 * <td>At approximately 11:23,000, on March 9th, 2001,
 * <code>/foo/bar.log</code> will be copied to
 * <code>/foo/bar.log.2001-03-09-10-22</code>. Logging for the minutue
 * of 11:23 (9th of March) will be output to
 * <code>/foo/bar.log</code> untill it is rolled over the next minute.
 * 
 * </table>
 * 
 * <p>Do not use the colon ":" character in anywhere in the
 * <b>DatePattern</b> option. The text before the colon is interpeted
 * as the protocol specificaion of a URL which is probably not what
 * you want.
 * 
 * Ripped largely from DailyFileAppender in org.apache.log4j, but that
 *   wasn't written in an extensible way.
 * 
 * @author Jim Moore
 * @author Eirik Lygre
 * @author Ceki G&uuml;lc&uuml;
 */
public class DailyRollingFileAppender extends FileAppender {
  // The code assumes that the following constants are in a increasing
  // sequence.
  public static final int TOP_OF_TROUBLE = -1;
  public static final int TOP_OF_MINUTE = 0;
  public static final int TOP_OF_HOUR = 1;
  public static final int HALF_DAY = 2;
  public static final int TOP_OF_DAY = 3;
  public static final int TOP_OF_WEEK = 4;
  public static final int TOP_OF_MONTH = 5;

  /**
   * A string constant used in naming the option for setting the
   * filename pattern. Current value of this string constant is
   * <strong>DatePattern</strong>.
   */
  public static final String DATE_PATTERN_OPTION = "DatePattern";

  /**
   * The date pattern. By default, the pattern is set to
   * "'.'yyyy-MM-dd" meaning daily rollover.
   */
  private String datePattern = "'.'yyyy-MM-dd";

  /**
   * The actual formatted filename that is currently being written to.
   */
  private String scheduledFilename;

  /**
   * The timestamp when we shall next recompute the filename.
   */
  private long nextCheck = System.currentTimeMillis() - 1;
  private Date now = new Date();
  private SimpleDateFormat sdf;
  private RollingCalendar rc = new RollingCalendar();
  private int checkPeriod = TOP_OF_TROUBLE;


  /**
   * The default constructor does nothing.
   */
  public DailyRollingFileAppender() {
  } 


  /**
   * Instantiate a <code>DailyRollingFileAppender</code> and open the
   * file designated by <code>filename</code>. The opened filename will
   * become the ouput destination for this appender.
   */
  public DailyRollingFileAppender(Layout layout, String filename, 
                                  String datePattern) throws IOException {
    super(layout, filename, true);

    this.datePattern = datePattern;

    activateOptions();
  }


  /**
   * The <b>DatePattern</b> takes a string in the same format as
   * expected by {@link SimpleDateFormat}. This options determines the
   * rollover schedule.
   */
  public void setDatePattern(String pattern) {
    datePattern = pattern;
  } 


  /**
   * Returns the value of the <b>DatePattern</b> option.
   */
  public String getDatePattern() {
    return datePattern;
  } 


  public void activateOptions() {
    if (datePattern != null && fileName != null) {
      sdf = new SimpleDateFormat(datePattern);
  
      int type = computeCheckPeriod(datePattern);
  
      printPeriodicity(type);
      rc.setType(type);
  
      long currentTimeMillis = System.currentTimeMillis();
      
      String fileName = getFile();
      File file = new File(fileName);
  
      now.setTime(currentTimeMillis);
      nextCheck = rc.getNextCheckMillis(now);
      LogLog.debug("nextCheck = "+nextCheck);
      
      scheduledFilename = fileName + sdf.format(now);
      
      // determine if this needs to override the "append" setting
      if (getAppend()) {
        if ( currentTimeMillis >= rc.getNextCheckMillis(new
Date(file.lastModified())) ) {
          LogLog.debug(fileName+" is old or doesn't exist");
          setAppend(false);
          
          try {
            rollOver();
          }
          catch (IOException exp) {
            LogLog.error("Could not do a rollover", exp);
            return;
          }
        }
        else {
          LogLog.debug("the current log file is for today");
          setAppend(true);
        }
      }
  
      super.activateOptions();
    }
    else {
      LogLog.error("Either Filename or DatePattern options are not set for
[" 
                   + name + "].");
    } 
  } 


  protected void printPeriodicity(int type) {
    switch (type) {
      
      case TOP_OF_MINUTE:
        LogLog.debug("Appender [" + name + "] to be rolled every minute.");

        break;

      case TOP_OF_HOUR:
        LogLog.debug("Appender [" + name 
                     + "] to be rolled on top of every hour.");

        break;

      case HALF_DAY:
        LogLog.debug("Appender [" + name 
                     + "] to be rolled at midday and midnight.");

        break;

      case TOP_OF_DAY:
        LogLog.debug("Appender [" + name + "] to be rolled at midnight.");

        break;

      case TOP_OF_WEEK:
        LogLog.debug("Appender [" + name + "] to be rolled at start of
week.");

        break;

      case TOP_OF_MONTH:
        LogLog.debug("Appender [" + name 
                     + "] to be rolled at start of every month.");

        break;

      default:
        LogLog.warn("Unknown periodicity for appender [" + name + "].");
    }
  } 


  protected int computeCheckPeriod(String datePattern) {
    RollingCalendar c = new RollingCalendar();

    // set sate to 1970-01-01 00:00:00 GMT
    final Date epoch = new Date(0);

    if (datePattern != null) {
      for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
        String r0 = sdf.format(epoch);

        c.setType(i);

        Date next = new Date(c.getNextCheckMillis(epoch));
        String r1 = sdf.format(next);

        LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1);
        if ( r0 != null && r1 != null && !r0.equals(r1) ) {
          return i;
        }
      }
    }

    return TOP_OF_TROUBLE;  // Deliberately head for trouble...
  } 


  /**
   * Rollover the current file to a new file.
   */
  protected void rollOver() throws IOException {
    // Compute filename, but only if datePattern is specified
    if (datePattern == null) {
      errorHandler.error("Missing DatePattern option in rollOver().");
      return;
    }

    String fileName = getFile();
    File file = new File(fileName);

    String datedFilename = fileName + sdf.format(new
Date(file.lastModified()));

    // close current file, and rename it to datedFilename
    this.closeFile();

    File target = new File(datedFilename);

    if (target.exists()) {
      target.delete();
    }

    file.renameTo(target);
    LogLog.debug(fileName + " -> " + datedFilename);

    try {
      // This will also close the file. This is OK since multiple
      // close operations are safe.
      this.setFile(fileName, false);
    }
    catch (IOException e) {
      errorHandler.error("setFile("+scheduledFilename+", false) call
failed.");
    }

    scheduledFilename = fileName + sdf.format(rc.getNextCheckDate(now));
  } 


  /**
   * This method differentiates DailyRollingFileAppender from its
   *   super class.
   */
  protected void subAppend(LoggingEvent event) {
    long n = System.currentTimeMillis();

    if (n >= nextCheck) {
      now.setTime(n);

      nextCheck = rc.getNextCheckMillis(now);

      try {
        rollOver();
      }
      catch (IOException ioe) {
        LogLog.error("rollOver() failed.", ioe);
      }
    }

    super.subAppend(event);
  }


  /**
   * RollingCalendar is a helper class to
   * DailyRollingFileAppender. Using this class, it is easy to compute
   * and access the next Millis().
   * 
   * It subclasses the standard {@link GregorianCalendar}-object, to
   * allow access to the protected function getTimeInMillis(), which it
   * then exports.
   * 
   * @author <a HREF="mailto:eirik.lygre@evita.no">Eirik Lygre</a>
   */
  protected static class RollingCalendar extends GregorianCalendar {
    int type = DailyRollingFileAppender.TOP_OF_TROUBLE;

    /**
     * Method declaration
     *
     * @param type
     */
    void setType(int type) {
      this.type = type;
    } 


    public long getNextCheckMillis(Date now) {
      return getNextCheckDate(now).getTime();
    } 


    public Date getNextCheckDate(Date now) {
      this.setTime(now);

      switch (type) {
        
        case DailyRollingFileAppender.TOP_OF_MINUTE:
          this.set(Calendar.SECOND, 0);
          this.set(Calendar.MILLISECOND, 0);
          this.add(Calendar.MINUTE, 1);

          break;

        case DailyRollingFileAppender.TOP_OF_HOUR:
          this.set(Calendar.MINUTE, 0);
          this.set(Calendar.SECOND, 0);
          this.set(Calendar.MILLISECOND, 0);
          this.add(Calendar.HOUR_OF_DAY, 1);

          break;

        case DailyRollingFileAppender.HALF_DAY:
          this.set(Calendar.MINUTE, 0);
          this.set(Calendar.SECOND, 0);
          this.set(Calendar.MILLISECOND, 0);

          int hour = get(Calendar.HOUR_OF_DAY);

          if (hour < 12) {
            this.set(Calendar.HOUR_OF_DAY, 0);
          }
          else {
            this.set(Calendar.HOUR_OF_DAY, 12);
          } 

          break;

        case DailyRollingFileAppender.TOP_OF_DAY:
          this.set(Calendar.HOUR_OF_DAY, 0);
          this.set(Calendar.MINUTE, 0);
          this.set(Calendar.SECOND, 0);
          this.set(Calendar.MILLISECOND, 0);
          this.add(Calendar.DATE, 1);

          break;

        case DailyRollingFileAppender.TOP_OF_WEEK:
          this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
          this.set(Calendar.HOUR_OF_DAY, 0);
          this.set(Calendar.SECOND, 0);
          this.set(Calendar.MILLISECOND, 0);
          this.add(Calendar.WEEK_OF_YEAR, 1);

          break;

        case DailyRollingFileAppender.TOP_OF_MONTH:
          this.set(Calendar.DATE, 1);
          this.set(Calendar.HOUR_OF_DAY, 0);
          this.set(Calendar.SECOND, 0);
          this.set(Calendar.MILLISECOND, 0);
          this.add(Calendar.MONTH, 1);

          break;

        default:
          throw new IllegalStateException("Unknown periodicity type.");
      }

      return getTime();
    } 

  }  // class RollingCalendar

}


-Jim Moore
"I think so, Brain; but if we gave peas a chance, won't the lima beans get
jealous?" - Pinky



-----Original Message-----
From: root [mailto:root]On Behalf Of Arturo Martinez
Sent: Monday, April 02, 2001 12:47 PM
To: log4j-user@jakarta.apache.org
Subject: DailyRollingFileAppender


Where can I find more information about DailyRollingFileAppender.
When does it write the new file? what means at midnight? What happens if
the server is down at midnigth?
Thanks

I have this configuration file:


<?xml version="1.0" encoding="UTF-8" ?>
<!--<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-->

  <log4j:configuration>

    <appender name="A1"
class="org.apache.log4j.DailyRollingFileAppender">
      <param name="File"
value="/usr/local/home/root/devel/deployment/cms/WEB-INF/logs/cms.log"
/>
      <param name="DatePattern"   value="'.'yyyy-MM-dd" />
      <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%t %-5p %c{2} - %m\n"/>
      </layout>
    </appender>

    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
      <param name="File" value="System.out" />

      <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern"
          value="%d %-5p [%t] %C{2} (%F:%L) - %m\n"/>
      </layout>
    </appender>

    <category name="es.nmp">
      <priority value="debug" />
      <appender-ref ref="A1" />
    </category>

    <root>
      <priority value ="debug" />
      <appender-ref ref="STDOUT" />
    </root>

</log4j:configuration>


---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-user-help@jakarta.apache.org

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-user-help@jakarta.apache.org


Mime
View raw message