1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.log4j;
21
22 import java.io.IOException;
23 import java.io.Writer;
24 import java.io.File;
25 import org.apache.log4j.helpers.OptionConverter;
26 import org.apache.log4j.helpers.LogLog;
27 import org.apache.log4j.helpers.CountingQuietWriter;
28 import org.apache.log4j.spi.LoggingEvent;
29
30 /***
31 RollingFileAppender extends FileAppender to backup the log files when
32 they reach a certain size.
33
34 @author Heinz Richter
35 @author Ceki Gülcü
36
37 */
38 public class RollingFileAppender extends FileAppender {
39
40 /***
41 The default maximum file size is 10MB.
42 */
43 protected long maxFileSize = 10*1024*1024;
44
45 /***
46 There is one backup file by default.
47 */
48 protected int maxBackupIndex = 1;
49
50 private long nextRollover = 0;
51
52 /***
53 The default constructor simply calls its {@link
54 FileAppender#FileAppender parents constructor}. */
55 public
56 RollingFileAppender() {
57 super();
58 }
59
60 /***
61 Instantiate a RollingFileAppender and open the file designated by
62 <code>filename</code>. The opened filename will become the ouput
63 destination for this appender.
64
65 <p>If the <code>append</code> parameter is true, the file will be
66 appended to. Otherwise, the file desginated by
67 <code>filename</code> will be truncated before being opened.
68 */
69 public
70 RollingFileAppender(Layout layout, String filename, boolean append)
71 throws IOException {
72 super(layout, filename, append);
73 }
74
75 /***
76 Instantiate a FileAppender and open the file designated by
77 <code>filename</code>. The opened filename will become the output
78 destination for this appender.
79
80 <p>The file will be appended to. */
81 public
82 RollingFileAppender(Layout layout, String filename) throws IOException {
83 super(layout, filename);
84 }
85
86 /***
87 Returns the value of the <b>MaxBackupIndex</b> option.
88 */
89 public
90 int getMaxBackupIndex() {
91 return maxBackupIndex;
92 }
93
94 /***
95 Get the maximum size that the output file is allowed to reach
96 before being rolled over to backup files.
97
98 @since 1.1
99 */
100 public
101 long getMaximumFileSize() {
102 return maxFileSize;
103 }
104
105 /***
106 Implements the usual roll over behaviour.
107
108 <p>If <code>MaxBackupIndex</code> is positive, then files
109 {<code>File.1</code>, ..., <code>File.MaxBackupIndex -1</code>}
110 are renamed to {<code>File.2</code>, ...,
111 <code>File.MaxBackupIndex</code>}. Moreover, <code>File</code> is
112 renamed <code>File.1</code> and closed. A new <code>File</code> is
113 created to receive further log output.
114
115 <p>If <code>MaxBackupIndex</code> is equal to zero, then the
116 <code>File</code> is truncated with no backup files created.
117
118 */
119 public
120 void rollOver() {
121 File target;
122 File file;
123
124 if (qw != null) {
125 long size = ((CountingQuietWriter) qw).getCount();
126 LogLog.debug("rolling over count=" + size);
127
128
129 nextRollover = size + maxFileSize;
130 }
131 LogLog.debug("maxBackupIndex="+maxBackupIndex);
132
133 boolean renameSucceeded = true;
134
135 if(maxBackupIndex > 0) {
136
137 file = new File(fileName + '.' + maxBackupIndex);
138 if (file.exists())
139 renameSucceeded = file.delete();
140
141
142 for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
143 file = new File(fileName + "." + i);
144 if (file.exists()) {
145 target = new File(fileName + '.' + (i + 1));
146 LogLog.debug("Renaming file " + file + " to " + target);
147 renameSucceeded = file.renameTo(target);
148 }
149 }
150
151 if(renameSucceeded) {
152
153 target = new File(fileName + "." + 1);
154
155 this.closeFile();
156
157 file = new File(fileName);
158 LogLog.debug("Renaming file " + file + " to " + target);
159 renameSucceeded = file.renameTo(target);
160
161
162
163 if (!renameSucceeded) {
164 try {
165 this.setFile(fileName, true, bufferedIO, bufferSize);
166 }
167 catch(IOException e) {
168 LogLog.error("setFile("+fileName+", true) call failed.", e);
169 }
170 }
171 }
172 }
173
174
175
176
177 if (renameSucceeded) {
178 try {
179
180
181 this.setFile(fileName, false, bufferedIO, bufferSize);
182 nextRollover = 0;
183 }
184 catch(IOException e) {
185 LogLog.error("setFile("+fileName+", false) call failed.", e);
186 }
187 }
188 }
189
190 public
191 synchronized
192 void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
193 throws IOException {
194 super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
195 if(append) {
196 File f = new File(fileName);
197 ((CountingQuietWriter) qw).setCount(f.length());
198 }
199 }
200
201
202 /***
203 Set the maximum number of backup files to keep around.
204
205 <p>The <b>MaxBackupIndex</b> option determines how many backup
206 files are kept before the oldest is erased. This option takes
207 a positive integer value. If set to zero, then there will be no
208 backup files and the log file will be truncated when it reaches
209 <code>MaxFileSize</code>.
210 */
211 public
212 void setMaxBackupIndex(int maxBackups) {
213 this.maxBackupIndex = maxBackups;
214 }
215
216 /***
217 Set the maximum size that the output file is allowed to reach
218 before being rolled over to backup files.
219
220 <p>This method is equivalent to {@link #setMaxFileSize} except
221 that it is required for differentiating the setter taking a
222 <code>long</code> argument from the setter taking a
223 <code>String</code> argument by the JavaBeans {@link
224 java.beans.Introspector Introspector}.
225
226 @see #setMaxFileSize(String)
227 */
228 public
229 void setMaximumFileSize(long maxFileSize) {
230 this.maxFileSize = maxFileSize;
231 }
232
233
234 /***
235 Set the maximum size that the output file is allowed to reach
236 before being rolled over to backup files.
237
238 <p>In configuration files, the <b>MaxFileSize</b> option takes an
239 long integer in the range 0 - 2^63. You can specify the value
240 with the suffixes "KB", "MB" or "GB" so that the integer is
241 interpreted being expressed respectively in kilobytes, megabytes
242 or gigabytes. For example, the value "10KB" will be interpreted
243 as 10240.
244 */
245 public
246 void setMaxFileSize(String value) {
247 maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
248 }
249
250 protected
251 void setQWForFiles(Writer writer) {
252 this.qw = new CountingQuietWriter(writer, errorHandler);
253 }
254
255 /***
256 This method differentiates RollingFileAppender from its super
257 class.
258
259 @since 0.9.0
260 */
261 protected
262 void subAppend(LoggingEvent event) {
263 super.subAppend(event);
264 if(fileName != null && qw != null) {
265 long size = ((CountingQuietWriter) qw).getCount();
266 if (size >= maxFileSize && size >= nextRollover) {
267 rollOver();
268 }
269 }
270 }
271 }