1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.log4j;
19
20 import java.io.IOException;
21 import java.io.Writer;
22 import java.io.FileOutputStream;
23 import java.io.BufferedWriter;
24 import java.io.FileNotFoundException;
25 import java.io.File;
26
27 import org.apache.log4j.spi.ErrorCode;
28 import org.apache.log4j.helpers.QuietWriter;
29 import org.apache.log4j.helpers.LogLog;
30
31
32
33
34 /***
35 * FileAppender appends log events to a file.
36 *
37 * <p>Support for <code>java.io.Writer</code> and console appending
38 * has been deprecated and then removed. See the replacement
39 * solutions: {@link WriterAppender} and {@link ConsoleAppender}.
40 *
41 * @author Ceki Gülcü
42 * */
43 public class FileAppender extends WriterAppender {
44
45 /*** Controls file truncatation. The default value for this variable
46 * is <code>true</code>, meaning that by default a
47 * <code>FileAppender</code> will append to an existing file and not
48 * truncate it.
49 *
50 * <p>This option is meaningful only if the FileAppender opens the
51 * file.
52 */
53 protected boolean fileAppend = true;
54
55 /***
56 The name of the log file. */
57 protected String fileName = null;
58
59 /***
60 Do we do bufferedIO? */
61 protected boolean bufferedIO = false;
62
63 /***
64 * Determines the size of IO buffer be. Default is 8K.
65 */
66 protected int bufferSize = 8*1024;
67
68
69 /***
70 The default constructor does not do anything.
71 */
72 public
73 FileAppender() {
74 }
75
76 /***
77 Instantiate a <code>FileAppender</code> and open the file
78 designated by <code>filename</code>. The opened filename will
79 become the output destination for this appender.
80
81 <p>If the <code>append</code> parameter is true, the file will be
82 appended to. Otherwise, the file designated by
83 <code>filename</code> will be truncated before being opened.
84
85 <p>If the <code>bufferedIO</code> parameter is <code>true</code>,
86 then buffered IO will be used to write to the output file.
87
88 */
89 public
90 FileAppender(Layout layout, String filename, boolean append, boolean bufferedIO,
91 int bufferSize) throws IOException {
92 this.layout = layout;
93 this.setFile(filename, append, bufferedIO, bufferSize);
94 }
95
96 /***
97 Instantiate a FileAppender and open the file designated by
98 <code>filename</code>. The opened filename will become the output
99 destination for this appender.
100
101 <p>If the <code>append</code> parameter is true, the file will be
102 appended to. Otherwise, the file designated by
103 <code>filename</code> will be truncated before being opened.
104 */
105 public
106 FileAppender(Layout layout, String filename, boolean append)
107 throws IOException {
108 this.layout = layout;
109 this.setFile(filename, append, false, bufferSize);
110 }
111
112 /***
113 Instantiate a FileAppender and open the file designated by
114 <code>filename</code>. The opened filename will become the output
115 destination for this appender.
116
117 <p>The file will be appended to. */
118 public
119 FileAppender(Layout layout, String filename) throws IOException {
120 this(layout, filename, true);
121 }
122
123 /***
124 The <b>File</b> property takes a string value which should be the
125 name of the file to append to.
126
127 <p><font color="#DD0044"><b>Note that the special values
128 "System.out" or "System.err" are no longer honored.</b></font>
129
130 <p>Note: Actual opening of the file is made when {@link
131 #activateOptions} is called, not when the options are set. */
132 public void setFile(String file) {
133
134
135 String val = file.trim();
136 fileName = val;
137 }
138
139 /***
140 Returns the value of the <b>Append</b> option.
141 */
142 public
143 boolean getAppend() {
144 return fileAppend;
145 }
146
147
148 /*** Returns the value of the <b>File</b> option. */
149 public
150 String getFile() {
151 return fileName;
152 }
153
154 /***
155 If the value of <b>File</b> is not <code>null</code>, then {@link
156 #setFile} is called with the values of <b>File</b> and
157 <b>Append</b> properties.
158
159 @since 0.8.1 */
160 public
161 void activateOptions() {
162 if(fileName != null) {
163 try {
164 setFile(fileName, fileAppend, bufferedIO, bufferSize);
165 }
166 catch(java.io.IOException e) {
167 errorHandler.error("setFile("+fileName+","+fileAppend+") call failed.",
168 e, ErrorCode.FILE_OPEN_FAILURE);
169 }
170 } else {
171
172 LogLog.warn("File option not set for appender ["+name+"].");
173 LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");
174 }
175 }
176
177 /***
178 Closes the previously opened file.
179 */
180 protected
181 void closeFile() {
182 if(this.qw != null) {
183 try {
184 this.qw.close();
185 }
186 catch(java.io.IOException e) {
187
188
189 LogLog.error("Could not close " + qw, e);
190 }
191 }
192 }
193
194 /***
195 Get the value of the <b>BufferedIO</b> option.
196
197 <p>BufferedIO will significatnly increase performance on heavily
198 loaded systems.
199
200 */
201 public
202 boolean getBufferedIO() {
203 return this.bufferedIO;
204 }
205
206
207 /***
208 Get the size of the IO buffer.
209 */
210 public
211 int getBufferSize() {
212 return this.bufferSize;
213 }
214
215
216
217 /***
218 The <b>Append</b> option takes a boolean value. It is set to
219 <code>true</code> by default. If true, then <code>File</code>
220 will be opened in append mode by {@link #setFile setFile} (see
221 above). Otherwise, {@link #setFile setFile} will open
222 <code>File</code> in truncate mode.
223
224 <p>Note: Actual opening of the file is made when {@link
225 #activateOptions} is called, not when the options are set.
226 */
227 public
228 void setAppend(boolean flag) {
229 fileAppend = flag;
230 }
231
232 /***
233 The <b>BufferedIO</b> option takes a boolean value. It is set to
234 <code>false</code> by default. If true, then <code>File</code>
235 will be opened and the resulting {@link java.io.Writer} wrapped
236 around a {@link BufferedWriter}.
237
238 BufferedIO will significatnly increase performance on heavily
239 loaded systems.
240
241 */
242 public
243 void setBufferedIO(boolean bufferedIO) {
244 this.bufferedIO = bufferedIO;
245 if(bufferedIO) {
246 immediateFlush = false;
247 }
248 }
249
250
251 /***
252 Set the size of the IO buffer.
253 */
254 public
255 void setBufferSize(int bufferSize) {
256 this.bufferSize = bufferSize;
257 }
258
259 /***
260 <p>Sets and <i>opens</i> the file where the log output will
261 go. The specified file must be writable.
262
263 <p>If there was already an opened file, then the previous file
264 is closed first.
265
266 <p><b>Do not use this method directly. To configure a FileAppender
267 or one of its subclasses, set its properties one by one and then
268 call activateOptions.</b>
269
270 @param fileName The path to the log file.
271 @param append If true will append to fileName. Otherwise will
272 truncate fileName. */
273 public
274 synchronized
275 void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
276 throws IOException {
277 LogLog.debug("setFile called: "+fileName+", "+append);
278
279
280 if(bufferedIO) {
281 setImmediateFlush(false);
282 }
283
284 reset();
285 FileOutputStream ostream = null;
286 try {
287
288
289
290 ostream = new FileOutputStream(fileName, append);
291 } catch(FileNotFoundException ex) {
292
293
294
295
296
297 String parentName = new File(fileName).getParent();
298 if (parentName != null) {
299 File parentDir = new File(parentName);
300 if(!parentDir.exists() && parentDir.mkdirs()) {
301 ostream = new FileOutputStream(fileName, append);
302 } else {
303 throw ex;
304 }
305 } else {
306 throw ex;
307 }
308 }
309 Writer fw = createWriter(ostream);
310 if(bufferedIO) {
311 fw = new BufferedWriter(fw, bufferSize);
312 }
313 this.setQWForFiles(fw);
314 this.fileName = fileName;
315 this.fileAppend = append;
316 this.bufferedIO = bufferedIO;
317 this.bufferSize = bufferSize;
318 writeHeader();
319 LogLog.debug("setFile ended");
320 }
321
322
323 /***
324 Sets the quiet writer being used.
325
326 This method is overriden by {@link RollingFileAppender}.
327 */
328 protected
329 void setQWForFiles(Writer writer) {
330 this.qw = new QuietWriter(writer, errorHandler);
331 }
332
333
334 /***
335 Close any previously opened file and call the parent's
336 <code>reset</code>. */
337 protected
338 void reset() {
339 closeFile();
340 this.fileName = null;
341 super.reset();
342 }
343 }
344