1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.log4j.rolling;
19
20 import java.io.File;
21 import java.util.Date;
22
23 import org.apache.log4j.Appender;
24 import org.apache.log4j.pattern.PatternConverter;
25 import org.apache.log4j.rolling.helper.Action;
26 import org.apache.log4j.rolling.helper.FileRenameAction;
27 import org.apache.log4j.rolling.helper.GZCompressAction;
28 import org.apache.log4j.rolling.helper.ZipCompressAction;
29 import org.apache.log4j.spi.LoggingEvent;
30
31
32 /***
33 * <code>TimeBasedRollingPolicy</code> is both easy to configure and quite
34 * powerful.
35 *
36 * <p>In order to use <code>TimeBasedRollingPolicy</code>, the
37 * <b>FileNamePattern</b> option must be set. It basically specifies the name of the
38 * rolled log files. The value <code>FileNamePattern</code> should consist of
39 * the name of the file, plus a suitably placed <code>%d</code> conversion
40 * specifier. The <code>%d</code> conversion specifier may contain a date and
41 * time pattern as specified by the {@link java.text.SimpleDateFormat} class. If
42 * the date and time pattern is ommitted, then the default pattern of
43 * "yyyy-MM-dd" is assumed. The following examples should clarify the point.
44 *
45 * <p>
46 * <table cellspacing="5px" border="1">
47 * <tr>
48 * <th><code>FileNamePattern</code> value</th>
49 * <th>Rollover schedule</th>
50 * <th>Example</th>
51 * </tr>
52 * <tr>
53 * <td nowrap="true"><code>/wombat/folder/foo.%d</code></td>
54 * <td>Daily rollover (at midnight). Due to the omission of the optional
55 * time and date pattern for the %d token specifier, the default pattern
56 * of "yyyy-MM-dd" is assumed, which corresponds to daily rollover.
57 * </td>
58 * <td>During November 23rd, 2004, logging output will go to
59 * the file <code>/wombat/foo.2004-11-23</code>. At midnight and for
60 * the rest of the 24th, logging output will be directed to
61 * <code>/wombat/foo.2004-11-24</code>.
62 * </td>
63 * </tr>
64 * <tr>
65 * <td nowrap="true"><code>/wombat/foo.%d{yyyy-MM}.log</code></td>
66 * <td>Rollover at the beginning of each month.</td>
67 * <td>During the month of October 2004, logging output will go to
68 * <code>/wombat/foo.2004-10.log</code>. After midnight of October 31st
69 * and for the rest of November, logging output will be directed to
70 * <code>/wombat/foo.2004-11.log</code>.
71 * </td>
72 * </tr>
73 * </table>
74 * <h2>Automatic file compression</h2>
75 * <code>TimeBasedRollingPolicy</code> supports automatic file compression.
76 * This feature is enabled if the value of the <b>FileNamePattern</b> option
77 * ends with <code>.gz</code> or <code>.zip</code>.
78 * <p>
79 * <table cellspacing="5px" border="1">
80 * <tr>
81 * <th><code>FileNamePattern</code> value</th>
82 * <th>Rollover schedule</th>
83 * <th>Example</th>
84 * </tr>
85 * <tr>
86 * <td nowrap="true"><code>/wombat/foo.%d.gz</code></td>
87 * <td>Daily rollover (at midnight) with automatic GZIP compression of the
88 * archived files.</td>
89 * <td>During November 23rd, 2004, logging output will go to
90 * the file <code>/wombat/foo.2004-11-23</code>. However, at midnight that
91 * file will be compressed to become <code>/wombat/foo.2004-11-23.gz</code>.
92 * For the 24th of November, logging output will be directed to
93 * <code>/wombat/folder/foo.2004-11-24</code> until its rolled over at the
94 * beginning of the next day.
95 * </td>
96 * </tr>
97 * </table>
98 *
99 * <h2>Decoupling the location of the active log file and the archived log files</h2>
100 * <p>The <em>active file</em> is defined as the log file for the current period
101 * whereas <em>archived files</em> are those files which have been rolled over
102 * in previous periods.
103 *
104 * <p>By setting the <b>ActiveFileName</b> option you can decouple the location
105 * of the active log file and the location of the archived log files.
106 * <p>
107 * <table cellspacing="5px" border="1">
108 * <tr>
109 * <th><code>FileNamePattern</code> value</th>
110 * <th>ActiveFileName</th>
111 * <th>Rollover schedule</th>
112 * <th>Example</th>
113 * </tr>
114 * <tr>
115 * <td nowrap="true"><code>/wombat/foo.log.%d</code></td>
116 * <td nowrap="true"><code>/wombat/foo.log</code></td>
117 * <td>Daily rollover.</td>
118 *
119 * <td>During November 23rd, 2004, logging output will go to
120 * the file <code>/wombat/foo.log</code>. However, at midnight that file
121 * will archived as <code>/wombat/foo.log.2004-11-23</code>. For the 24th
122 * of November, logging output will be directed to
123 * <code>/wombat/folder/foo.log</code> until its archived as
124 * <code>/wombat/foo.log.2004-11-24</code> at the beginning of the next
125 * day.
126 * </td>
127 * </tr>
128 * </table>
129 * <p>
130 * If configuring programatically, do not forget to call {@link #activateOptions}
131 * method before using this policy. Moreover, {@link #activateOptions} of
132 * <code> TimeBasedRollingPolicy</code> must be called <em>before</em> calling
133 * the {@link #activateOptions} method of the owning
134 * <code>RollingFileAppender</code>.
135 *
136 * @author Ceki Gülcü
137 * @author Curt Arnold
138 */
139 public final class TimeBasedRollingPolicy extends RollingPolicyBase
140 implements TriggeringPolicy {
141
142 /***
143 * Time for next determination if time for rollover.
144 */
145 private long nextCheck = 0;
146
147 /***
148 * File name at last rollover.
149 */
150 private String lastFileName = null;
151
152 /***
153 * Length of any file type suffix (.gz, .zip).
154 */
155 private int suffixLength = 0;
156
157 /***
158 * Constructs a new instance.
159 */
160 public TimeBasedRollingPolicy() {
161 }
162
163 /***
164 * Prepares instance of use.
165 */
166 public void activateOptions() {
167 super.activateOptions();
168
169 PatternConverter dtc = getDatePatternConverter();
170
171 if (dtc == null) {
172 throw new IllegalStateException(
173 "FileNamePattern [" + getFileNamePattern()
174 + "] does not contain a valid date format specifier");
175 }
176
177 long n = System.currentTimeMillis();
178 StringBuffer buf = new StringBuffer();
179 formatFileName(new Date(n), buf);
180 lastFileName = buf.toString();
181
182 suffixLength = 0;
183
184 if (lastFileName.endsWith(".gz")) {
185 suffixLength = 3;
186 } else if (lastFileName.endsWith(".zip")) {
187 suffixLength = 4;
188 }
189 }
190
191 /***
192 * {@inheritDoc}
193 */
194 public RolloverDescription initialize(
195 final String currentActiveFile, final boolean append) {
196 long n = System.currentTimeMillis();
197 nextCheck = ((n / 1000) + 1) * 1000;
198
199 StringBuffer buf = new StringBuffer();
200 formatFileName(new Date(n), buf);
201 lastFileName = buf.toString();
202
203
204
205
206
207 if (activeFileName != null) {
208 return new RolloverDescriptionImpl(activeFileName, append, null, null);
209 } else if (currentActiveFile != null) {
210 return new RolloverDescriptionImpl(
211 currentActiveFile, append, null, null);
212 } else {
213 return new RolloverDescriptionImpl(
214 lastFileName.substring(0, lastFileName.length() - suffixLength), append,
215 null, null);
216 }
217 }
218
219 /***
220 * {@inheritDoc}
221 */
222 public RolloverDescription rollover(final String currentActiveFile) {
223 long n = System.currentTimeMillis();
224 nextCheck = ((n / 1000) + 1) * 1000;
225
226 StringBuffer buf = new StringBuffer();
227 formatFileName(new Date(n), buf);
228
229 String newFileName = buf.toString();
230
231
232
233
234 if (newFileName.equals(lastFileName)) {
235 return null;
236 }
237
238 Action renameAction = null;
239 Action compressAction = null;
240 String lastBaseName =
241 lastFileName.substring(0, lastFileName.length() - suffixLength);
242 String nextActiveFile =
243 newFileName.substring(0, newFileName.length() - suffixLength);
244
245
246
247
248
249 if (!currentActiveFile.equals(lastBaseName)) {
250 renameAction =
251 new FileRenameAction(
252 new File(currentActiveFile), new File(lastBaseName), true);
253 nextActiveFile = currentActiveFile;
254 }
255
256 if (suffixLength == 3) {
257 compressAction =
258 new GZCompressAction(
259 new File(lastBaseName), new File(lastFileName), true);
260 }
261
262 if (suffixLength == 4) {
263 compressAction =
264 new ZipCompressAction(
265 new File(lastBaseName), new File(lastFileName), true);
266 }
267
268 lastFileName = newFileName;
269
270 return new RolloverDescriptionImpl(
271 nextActiveFile, false, renameAction, compressAction);
272 }
273
274 /***
275 * {@inheritDoc}
276 */
277 public boolean isTriggeringEvent(
278 final Appender appender, final LoggingEvent event, final String filename,
279 final long fileLength) {
280 return System.currentTimeMillis() >= nextCheck;
281 }
282 }