View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.rolling;
15  
16  import java.io.File;
17  import java.util.Date;
18  import java.util.concurrent.Future;
19  
20  import ch.qos.logback.core.CoreConstants;
21  import ch.qos.logback.core.rolling.helper.*;
22  
23  /**
24   * <code>TimeBasedRollingPolicy</code> is both easy to configure and quite
25   * powerful. It allows the roll over to be made based on time. It is possible to
26   * specify that the roll over occur once per day, per week or per month.
27   * 
28   * <p>For more information, please refer to the online manual at
29   * http://logback.qos.ch/manual/appenders.html#TimeBasedRollingPolicy
30   * 
31   * @author Ceki G&uuml;lc&uuml;
32   */
33  public class TimeBasedRollingPolicy<E> extends RollingPolicyBase implements
34      TriggeringPolicy<E> {
35    static final String FNP_NOT_SET = "The FileNamePattern option must be set before using TimeBasedRollingPolicy. ";
36    static final int NO_DELETE_HISTORY = 0;
37  
38    // WCS: without compression suffix
39    FileNamePattern fileNamePatternWCS;
40  
41    private Compressor compressor;
42    private RenameUtil renameUtil = new RenameUtil();
43    Future<?> future;
44  
45    private int maxHistory = NO_DELETE_HISTORY;
46    private ArchiveRemover archiveRemover;
47  
48    TimeBasedFileNamingAndTriggeringPolicy<E> timeBasedFileNamingAndTriggeringPolicy;
49  
50    public void start() {
51      // set the LR for our utility object
52      renameUtil.setContext(this.context);
53  
54      // find out period from the filename pattern
55      if (fileNamePatternStr != null) {
56        fileNamePattern = new FileNamePattern(fileNamePatternStr, this.context);
57        determineCompressionMode();
58      } else {
59        addWarn(FNP_NOT_SET);
60        addWarn(CoreConstants.SEE_FNP_NOT_SET);
61        throw new IllegalStateException(FNP_NOT_SET
62            + CoreConstants.SEE_FNP_NOT_SET);
63      }
64  
65      compressor = new Compressor(compressionMode);
66      compressor.setContext(context);
67  
68      // wcs : without compression suffix
69      fileNamePatternWCS = new FileNamePattern(Compressor.computeFileNameStr_WCS(
70              fileNamePatternStr, compressionMode), this.context);
71  
72      addInfo("Will use the pattern " + fileNamePatternWCS
73          + " for the active file");
74  
75       if(compressionMode == CompressionMode.ZIP) {
76        String zipEntryFileNamePatternStr = transformFileNamePattern2ZipEntry(fileNamePatternStr);
77        zipEntryFileNamePattern = new FileNamePattern(zipEntryFileNamePatternStr, context);
78      }
79  
80      if (timeBasedFileNamingAndTriggeringPolicy == null) {
81        timeBasedFileNamingAndTriggeringPolicy = new DefaultTimeBasedFileNamingAndTriggeringPolicy<E>();
82      }
83      timeBasedFileNamingAndTriggeringPolicy.setContext(context);
84      timeBasedFileNamingAndTriggeringPolicy.setTimeBasedRollingPolicy(this);
85      timeBasedFileNamingAndTriggeringPolicy.start();
86  
87      // the maxHistory property is given to TimeBasedRollingPolicy instead of to
88      // the TimeBasedFileNamingAndTriggeringPolicy. This makes it more convenient
89      // for the user at the cost of inconsistency here.
90      if (maxHistory != NO_DELETE_HISTORY) {
91        archiveRemover = timeBasedFileNamingAndTriggeringPolicy.getArchiveRemover();
92        archiveRemover.setMaxHistory(maxHistory);
93      }
94  
95      super.start();
96    }
97  
98    private String transformFileNamePattern2ZipEntry(String fileNamePatternStr) {
99      String slashified = FileFilterUtil.slashify(fileNamePatternStr);
100     return FileFilterUtil.afterLastSlash(slashified);
101   }
102 
103   public void setTimeBasedFileNamingAndTriggeringPolicy(
104       TimeBasedFileNamingAndTriggeringPolicy<E> timeBasedTriggering) {
105     this.timeBasedFileNamingAndTriggeringPolicy = timeBasedTriggering;
106   }
107 
108   public TimeBasedFileNamingAndTriggeringPolicy<E> getTimeBasedFileNamingAndTriggeringPolicy() {
109     return timeBasedFileNamingAndTriggeringPolicy;
110   }
111 
112   public void rollover() throws RolloverFailure {
113 
114     // when rollover is called the elapsed period's file has
115     // been already closed. This is a working assumption of this method.
116 
117     String elapsedPeriodsFileName = timeBasedFileNamingAndTriggeringPolicy
118         .getElapsedPeriodsFileName();
119 
120     String elpasedPeriodStem = FileFilterUtil.afterLastSlash(elapsedPeriodsFileName);
121 
122 
123     if (compressionMode == CompressionMode.NONE) {
124       if (getParentsRawFileProperty() != null) {
125         renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName);
126       } // else { nothing to do if CompressionMode == NONE and parentsRawFileProperty == null }
127     } else {
128       if (getParentsRawFileProperty() == null) {
129         future = asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elpasedPeriodStem);
130       } else {
131         future = renamedRawAndAsyncCompress(elapsedPeriodsFileName, elpasedPeriodStem);
132       }
133     }
134 
135     if (archiveRemover != null) {
136       archiveRemover.clean(new Date(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime()));
137     }
138   }
139 
140   Future asyncCompress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName)
141       throws RolloverFailure {
142     AsynchronousCompressor ac = new AsynchronousCompressor(compressor);
143     return ac.compressAsynchronously(nameOfFile2Compress, nameOfCompressedFile, innerEntryName);
144   }
145 
146   Future renamedRawAndAsyncCompress(String nameOfCompressedFile, String innerEntryName)
147       throws RolloverFailure {
148     String parentsRawFile = getParentsRawFileProperty();
149     String tmpTarget = parentsRawFile + System.nanoTime() + ".tmp";
150     renameUtil.rename(parentsRawFile, tmpTarget);
151     return asyncCompress(tmpTarget, nameOfCompressedFile, innerEntryName);
152   }
153 
154   /**
155    * 
156    * The active log file is determined by the value of the parent's filename
157    * option. However, in case the file name is left blank, then, the active log
158    * file equals the file name for the current period as computed by the
159    * <b>FileNamePattern</b> option.
160    * 
161    * <p>The RollingPolicy must know whether it is responsible for changing the
162    * name of the active file or not. If the active file name is set by the user
163    * via the configuration file, then the RollingPolicy must let it like it is.
164    * If the user does not specify an active file name, then the RollingPolicy
165    * generates one.
166    * 
167    * <p> To be sure that the file name used by the parent class has been
168    * generated by the RollingPolicy and not specified by the user, we keep track
169    * of the last generated name object and compare its reference to the parent
170    * file name. If they match, then the RollingPolicy knows it's responsible for
171    * the change of the file name.
172    * 
173    */
174   public String getActiveFileName() {
175     String parentsRawFileProperty = getParentsRawFileProperty();
176     if (parentsRawFileProperty != null) {
177       return parentsRawFileProperty;
178     } else {
179       return timeBasedFileNamingAndTriggeringPolicy
180           .getCurrentPeriodsFileNameWithoutCompressionSuffix();
181     }
182   }
183 
184   public boolean isTriggeringEvent(File activeFile, final E event) {
185     return timeBasedFileNamingAndTriggeringPolicy.isTriggeringEvent(activeFile, event);
186   }
187 
188   /**
189    * Get the number of archive files to keep.
190    * 
191    * @return number of archive files to keep
192    */
193   public int getMaxHistory() {
194     return maxHistory;
195   }
196 
197   /**
198    * Set the maximum number of archive files to keep.
199    * 
200    * @param maxHistory
201    *                number of archive files to keep
202    */
203   public void setMaxHistory(int maxHistory) {
204     this.maxHistory = maxHistory;
205   }
206 
207   @Override
208   public String toString() {
209     return "c.q.l.core.rolling.TimeBasedRollingPolicy";
210   }
211 }