2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 package org.apache.log4j;
22 import java.io.IOException;
23 import java.io.Writer;
25 import java.io.InterruptedIOException;
27 import org.apache.log4j.helpers.OptionConverter;
28 import org.apache.log4j.helpers.LogLog;
29 import org.apache.log4j.helpers.CountingQuietWriter;
30 import org.apache.log4j.spi.LoggingEvent;
33 RollingFileAppender extends FileAppender to backup the log files when
34 they reach a certain size.
36 The log4j extras companion includes alternatives which should be considered
37 for new deployments and which are discussed in the documentation
38 for org.apache.log4j.rolling.RollingFileAppender.
42 @author Ceki Gülcü
45 public class RollingFileAppender extends FileAppender {
48 The default maximum file size is 10MB.
50 protected long maxFileSize = 10*1024*1024;
53 There is one backup file by default.
55 protected int maxBackupIndex = 1;
57 private long nextRollover = 0;
60 The default constructor simply calls its {@link
61 FileAppender#FileAppender parents constructor}. */
63 RollingFileAppender() {
68 Instantiate a RollingFileAppender and open the file designated by
69 <code>filename</code>. The opened filename will become the ouput
70 destination for this appender.
72 <p>If the <code>append</code> parameter is true, the file will be
73 appended to. Otherwise, the file desginated by
74 <code>filename</code> will be truncated before being opened.
77 RollingFileAppender(Layout layout, String filename, boolean append)
79 super(layout, filename, append);
83 Instantiate a FileAppender and open the file designated by
84 <code>filename</code>. The opened filename will become the output
85 destination for this appender.
87 <p>The file will be appended to. */
89 RollingFileAppender(Layout layout, String filename) throws IOException {
90 super(layout, filename);
94 Returns the value of the <b>MaxBackupIndex</b> option.
97 int getMaxBackupIndex() {
98 return maxBackupIndex;
102 Get the maximum size that the output file is allowed to reach
103 before being rolled over to backup files.
108 long getMaximumFileSize() {
113 Implements the usual roll over behaviour.
115 <p>If <code>MaxBackupIndex</code> is positive, then files
116 {<code>File.1</code>, ..., <code>File.MaxBackupIndex -1</code>}
117 are renamed to {<code>File.2</code>, ...,
118 <code>File.MaxBackupIndex</code>}. Moreover, <code>File</code> is
119 renamed <code>File.1</code> and closed. A new <code>File</code> is
120 created to receive further log output.
122 <p>If <code>MaxBackupIndex</code> is equal to zero, then the
123 <code>File</code> is truncated with no backup files created.
126 public // synchronization not necessary since doAppend is alreasy synched
132 long size = ((CountingQuietWriter) qw).getCount();
133 LogLog.debug("rolling over count=" + size);
134 // if operation fails, do not roll again until
135 // maxFileSize more bytes are written
136 nextRollover = size + maxFileSize;
138 LogLog.debug("maxBackupIndex="+maxBackupIndex);
140 boolean renameSucceeded = true;
141 // If maxBackups <= 0, then there is no file renaming to be done.
142 if(maxBackupIndex > 0) {
143 // Delete the oldest file, to keep Windows happy.
144 file = new File(fileName + '.' + maxBackupIndex);
146 renameSucceeded = file.delete();
149 // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
150 for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
151 file = new File(fileName + "." + i);
153 target = new File(fileName + '.' + (i + 1));
154 LogLog.debug("Renaming file " + file + " to " + target);
155 renameSucceeded = file.renameTo(target);
159 if(renameSucceeded) {
160 // Rename fileName to fileName.1
161 target = new File(fileName + "." + 1);
163 this.closeFile(); // keep windows happy.
165 file = new File(fileName);
166 LogLog.debug("Renaming file " + file + " to " + target);
167 renameSucceeded = file.renameTo(target);
169 // if file rename failed, reopen file with append = true
171 if (!renameSucceeded) {
173 this.setFile(fileName, true, bufferedIO, bufferSize);
175 catch(IOException e) {
176 if (e instanceof InterruptedIOException) {
177 Thread.currentThread().interrupt();
179 LogLog.error("setFile("+fileName+", true) call failed.", e);
186 // if all renames were successful, then
188 if (renameSucceeded) {
190 // This will also close the file. This is OK since multiple
191 // close operations are safe.
192 this.setFile(fileName, false, bufferedIO, bufferSize);
195 catch(IOException e) {
196 if (e instanceof InterruptedIOException) {
197 Thread.currentThread().interrupt();
199 LogLog.error("setFile("+fileName+", false) call failed.", e);
206 void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
208 super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
210 File f = new File(fileName);
211 ((CountingQuietWriter) qw).setCount(f.length());
217 Set the maximum number of backup files to keep around.
219 <p>The <b>MaxBackupIndex</b> option determines how many backup
220 files are kept before the oldest is erased. This option takes
221 a positive integer value. If set to zero, then there will be no
222 backup files and the log file will be truncated when it reaches
223 <code>MaxFileSize</code>.
226 void setMaxBackupIndex(int maxBackups) {
227 this.maxBackupIndex = maxBackups;
231 Set the maximum size that the output file is allowed to reach
232 before being rolled over to backup files.
234 <p>This method is equivalent to {@link #setMaxFileSize} except
235 that it is required for differentiating the setter taking a
236 <code>long</code> argument from the setter taking a
237 <code>String</code> argument by the JavaBeans {@link
238 java.beans.Introspector Introspector}.
240 @see #setMaxFileSize(String)
243 void setMaximumFileSize(long maxFileSize) {
244 this.maxFileSize = maxFileSize;
249 Set the maximum size that the output file is allowed to reach
250 before being rolled over to backup files.
252 <p>In configuration files, the <b>MaxFileSize</b> option takes an
253 long integer in the range 0 - 2^63. You can specify the value
254 with the suffixes "KB", "MB" or "GB" so that the integer is
255 interpreted being expressed respectively in kilobytes, megabytes
256 or gigabytes. For example, the value "10KB" will be interpreted
260 void setMaxFileSize(String value) {
261 maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
265 void setQWForFiles(Writer writer) {
266 this.qw = new CountingQuietWriter(writer, errorHandler);
270 This method differentiates RollingFileAppender from its super
276 void subAppend(LoggingEvent event) {
277 super.subAppend(event);
278 if(fileName != null && qw != null) {
279 long size = ((CountingQuietWriter) qw).getCount();
280 if (size >= maxFileSize && size >= nextRollover) {