JAL-3048 test updated for AlignExportSettings changes
[jalview.git] / srcjar / org / apache / log4j / RollingFileAppender.java
1 /*
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
8  * 
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  * 
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.
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 java.io.InterruptedIOException;
26
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;
31
32 /**
33    RollingFileAppender extends FileAppender to backup the log files when
34    they reach a certain size.
35    
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.
39    
40
41    @author Heinz Richter
42    @author Ceki Gülcü
43
44 */
45 public class RollingFileAppender extends FileAppender {
46
47   /**
48      The default maximum file size is 10MB.
49   */
50   protected long maxFileSize = 10*1024*1024;
51
52   /**
53      There is one backup file by default.
54    */
55   protected int  maxBackupIndex  = 1;
56
57   private long nextRollover = 0;
58
59   /**
60      The default constructor simply calls its {@link
61      FileAppender#FileAppender parents constructor}.  */
62   public
63   RollingFileAppender() {
64     super();
65   }
66
67   /**
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.
71
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.
75   */
76   public
77   RollingFileAppender(Layout layout, String filename, boolean append)
78                                       throws IOException {
79     super(layout, filename, append);
80   }
81
82   /**
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.
86
87     <p>The file will be appended to.  */
88   public
89   RollingFileAppender(Layout layout, String filename) throws IOException {
90     super(layout, filename);
91   }
92
93   /**
94      Returns the value of the <b>MaxBackupIndex</b> option.
95    */
96   public
97   int getMaxBackupIndex() {
98     return maxBackupIndex;
99   }
100
101  /**
102     Get the maximum size that the output file is allowed to reach
103     before being rolled over to backup files.
104
105     @since 1.1
106  */
107   public
108   long getMaximumFileSize() {
109     return maxFileSize;
110   }
111
112   /**
113      Implements the usual roll over behaviour.
114
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.
121
122      <p>If <code>MaxBackupIndex</code> is equal to zero, then the
123      <code>File</code> is truncated with no backup files created.
124
125    */
126   public // synchronization not necessary since doAppend is alreasy synched
127   void rollOver() {
128     File target;
129     File file;
130
131     if (qw != null) {
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;
137     }
138     LogLog.debug("maxBackupIndex="+maxBackupIndex);
139
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);
145       if (file.exists()) {
146         renameSucceeded = file.delete();
147     }
148
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);
152         if (file.exists()) {
153           target = new File(fileName + '.' + (i + 1));
154           LogLog.debug("Renaming file " + file + " to " + target);
155           renameSucceeded = file.renameTo(target);
156         }
157       }
158
159     if(renameSucceeded) {
160       // Rename fileName to fileName.1
161       target = new File(fileName + "." + 1);
162
163       this.closeFile(); // keep windows happy.
164
165       file = new File(fileName);
166       LogLog.debug("Renaming file " + file + " to " + target);
167       renameSucceeded = file.renameTo(target);
168       //
169       //   if file rename failed, reopen file with append = true
170       //
171       if (!renameSucceeded) {
172           try {
173             this.setFile(fileName, true, bufferedIO, bufferSize);
174           }
175           catch(IOException e) {
176               if (e instanceof InterruptedIOException) {
177                   Thread.currentThread().interrupt();
178               }
179               LogLog.error("setFile("+fileName+", true) call failed.", e);
180           }
181       }
182     }
183     }
184
185     //
186     //   if all renames were successful, then
187     //
188     if (renameSucceeded) {
189     try {
190       // This will also close the file. This is OK since multiple
191       // close operations are safe.
192       this.setFile(fileName, false, bufferedIO, bufferSize);
193       nextRollover = 0;
194     }
195     catch(IOException e) {
196         if (e instanceof InterruptedIOException) {
197             Thread.currentThread().interrupt();
198         }
199         LogLog.error("setFile("+fileName+", false) call failed.", e);
200     }
201     }
202   }
203
204   public
205   synchronized
206   void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
207                                                                  throws IOException {
208     super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
209     if(append) {
210       File f = new File(fileName);
211       ((CountingQuietWriter) qw).setCount(f.length());
212     }
213   }
214
215
216   /**
217      Set the maximum number of backup files to keep around.
218
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>.
224    */
225   public
226   void setMaxBackupIndex(int maxBackups) {
227     this.maxBackupIndex = maxBackups;
228   }
229
230   /**
231      Set the maximum size that the output file is allowed to reach
232      before being rolled over to backup files.
233
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}.
239
240      @see #setMaxFileSize(String)
241  */
242   public
243   void setMaximumFileSize(long maxFileSize) {
244     this.maxFileSize = maxFileSize;
245   }
246
247
248   /**
249      Set the maximum size that the output file is allowed to reach
250      before being rolled over to backup files.
251
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
257      as 10240.
258    */
259   public
260   void setMaxFileSize(String value) {
261     maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
262   }
263
264   protected
265   void setQWForFiles(Writer writer) {
266      this.qw = new CountingQuietWriter(writer, errorHandler);
267   }
268
269   /**
270      This method differentiates RollingFileAppender from its super
271      class.
272
273      @since 0.9.0
274   */
275   protected
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) {
281             rollOver();
282         }
283     }
284    }
285 }