This patch fixes bug #1905 by overriding writeHeader and checking to see if the file is empty before writing the header. Patched source file and CVS diff output files are attached. /mike -- ****************************************** Mike Dougherty -- Java Software Engineer ******************************************
/* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software * License version 1.1, a copy of which has been included with this * distribution in the LICENSE.APL file. */ package org.apache.log4j; import java.io.IOException; import java.io.Writer; import java.io.FileWriter; import java.io.File; import java.io.OutputStream; import java.io.OutputStreamWriter; import org.apache.log4j.spi.ErrorHandler; import org.apache.log4j.spi.ErrorCode; import org.apache.log4j.spi.LoggingEvent; import org.apache.log4j.helpers.OptionConverter; import org.apache.log4j.helpers.QuietWriter; import org.apache.log4j.helpers.LogLog; //import org.apache.log4j.helpers.TracerPrintWriter; // Contibutors: Jens Uwe Pipka <[EMAIL PROTECTED]> /** FileAppender appends log events to a file. <b>Support for java.io.Writer and console appending has been deprecated and will be removed in the near future.</b> You are strongly encouraged to use the replacement solutions: {@link WriterAppender} and {@link ConsoleAppender}. @author Ceki Gülcü */ public class FileAppender extends WriterAppender { /** A string constant used in naming the option for setting the output file. Current value of this string constant is <b>File</b>. <p>Note that all option keys are case sensitive. @deprecated We now use JavaBeans introspection to configure components. Options strings are no longer needed. */ public static final String FILE_OPTION = "File"; /** A string constant used in naming the option that determines whether the output file will be truncated or appended to. Current value of this string constant is <b>Append</b>. <p>Note that all option keys are case sensitive. @deprecated We now use JavaBeans introspection to configure components. Options strings are no longer needed. */ public static final String APPEND_OPTION = "Append"; /** Append to or truncate the file? The default value for this variable is <code>true</code>, meaning that by default a <code>FileAppender</code> will append to an existing file and not truncate it. <p>This option is meaningful only if the FileAppender opens the file. */ protected boolean fileAppend = true; /** The name of the log file. */ protected String fileName = null; /** Is the QuietWriter ours or was it created and passed by the user? @deprecated FileAppender will not support streams passed by the user in the future. */ protected boolean qwIsOurs = false; /** The default constructor does not do anything. */ public FileAppender() { } /** Instantiate a FileAppender and set the output destination to a new {@link OutputStreamWriter} initialized with <code>os</code> as its {@link OutputStream}. @deprecated <b>The functionality of this constructor form has been replaced by the {@link WriterAppender}. This constructor will be removed in the <em>near</em> term.</b> */ public FileAppender(Layout layout, OutputStream os) { super(layout, os); } /** Instantiate a FileAppender and set the output destination to <code>writer</code>. <p>The <code>writer</code> must have been opened by the user. @deprecated <b>The functionality of constructor form has been replaced by the {@link WriterAppender}. This constructor will be removed in the <em>near</em> term.</b> */ public FileAppender(Layout layout, Writer writer) { super(layout, writer); } /** Instantiate a FileAppender and open the file designated by <code>filename</code>. The opened filename will become the output destination for this appender. <p>If the <code>append</code> parameter is true, the file will be appended to. Otherwise, the file designated by <code>filename</code> will be truncated before being opened. */ public FileAppender(Layout layout, String filename, boolean append) throws IOException { this.layout = layout; this.setFile(filename, append); } /** Instantiate a FileAppender and open the file designated by <code>filename</code>. The opened filename will become the output destination for this appender. <p>The file will be appended to. */ public FileAppender(Layout layout, String filename) throws IOException { this(layout, filename, true); } /** The <b>File</b> option takes a string value which should be the name of the file to append to. Special values "System.out" or "System.err" are interpreted as the standard out and standard error streams. <p><font color="#DD0044"><b>Note that the "System.out" or "System.err" options are deprecated. Use {@link ConsoleAppender} instead.</b></font> <p>If the option is set to "System.out" or "System.err" the output will go to the corresponding stream. Otherwise, if the option is set to the name of a file, then the file will be opened and output will go there. <p>Note: Actual opening of the file is made when {@link #activateOptions} is called, not when the options are set. */ public void setFile(String file) { // Trim spaces from both ends. The users probably does not want // trailing spaces in file names. String val = file.trim(); if(val.equalsIgnoreCase("System.out")) { setWriter(new OutputStreamWriter(System.out)); } else if(val.equalsIgnoreCase("System.err")) { setWriter(new OutputStreamWriter(System.err)); } else { fileName = val; } } /** Returns the value of the <b>Append</b> option. */ public boolean getAppend() { return fileAppend; } /** Returns the value of the <b>File</b> option. */ public String getFile() { return fileName; } /** Returns the option names for this component, namely the string array {@link #FILE_OPTION}, {@link #APPEND_OPTION}} in addition to the options of its super class {@link WriterAppender}. @deprecated We now use JavaBeans introspection to configure components. Options strings are no longer needed. */ public String[] getOptionStrings() { return OptionConverter.concatanateArrays(super.getOptionStrings(), new String[] {FILE_OPTION, APPEND_OPTION}); } /** The <b>Append</b> option takes a boolean value. It is set to <code>true</code> by default. If true, then <code>File</code> will be opened in append mode by {@link #setFile setFile} (see above). Otherwise, {@link #setFile setFile} will open <code>File</code> in truncate mode. <p>Note: Actual opening of the file is made when {@link #activateOptions} is called, not when the options are set. */ public void setAppend(boolean flag) { fileAppend = flag; } /** If the value of {@link #FILE_OPTION} is not <code>null</code>, then {@link #setFile} is called with the values of {@link #FILE_OPTION} and {@link #APPEND_OPTION}. @since 0.8.1 */ public void activateOptions() { if(fileName != null) { try { setFile(fileName, fileAppend); } catch(java.io.IOException e) { errorHandler.error("setFile("+fileName+","+fileAppend+") call failed.", e, ErrorCode.FILE_OPEN_FAILURE); } } else { //LogLog.error("File option not set for appender ["+name+"]."); LogLog.warn("File option not set for appender ["+name+"]."); LogLog.warn("Are you using FileAppender instead of ConsoleAppender?"); } } /** Closes the previously opened file. */ protected void closeFile() { // FIXME (remove qwIsOurs) if(this.qw != null && this.qwIsOurs) { try { this.qw.close(); } catch(java.io.IOException e) { // Exceptionally, it does not make sense to delegate to an // ErrorHandler. Since a closed appender is basically dead. LogLog.error("Could not close " + qw, e); } } } /** <p>Sets and <i>opens</i> the file where the log output will go. The specified file must be writable. <p>If there was already an opened file, then the previous file is closed first. @param fileName The path to the log file. @param append If true will append to fileName. Otherwise will truncate fileName. */ public synchronized void setFile(String fileName, boolean append) throws IOException { reset(); this.setQWForFiles(new FileWriter(fileName, append)); //this.tp = new TracerPrintWriter(qw); this.fileName = fileName; this.fileAppend = append; this.qwIsOurs = true; writeHeader(); } /** @deprecated Use the setter method for the option directly instead of the generic <code>setOption</code> method. */ public void setOption(String key, String value) { if(value == null) return; super.setOption(key, value); if(key.equalsIgnoreCase(FILE_OPTION)) { // Trim spaces from both ends. The users probably does not want // trailing spaces in file names. String val = value.trim(); if(val.equalsIgnoreCase("System.out")) { setWriter(new OutputStreamWriter(System.out)); } else if(val.equalsIgnoreCase("System.err")) { setWriter(new OutputStreamWriter(System.err)); } else { fileName = val; } } else if (key.equalsIgnoreCase(APPEND_OPTION)) { fileAppend = OptionConverter.toBoolean(value, fileAppend); } } /** Sets the quiet writer being used. This method is overriden by {@link RollingFileAppender}. */ protected void setQWForFiles(Writer writer) { this.qw = new QuietWriter(writer, errorHandler); } /** Close any previously opened file and call the parent's <code>reset</code>. */ protected void reset() { closeFile(); this.fileName = null; if(qwIsOurs) { super.reset(); } else { this.qw = null; //this.tp = null; } } /** Write a header as produced by the embedded layout's {@link Layout#getHeader} method. */ protected void writeHeader() { // Create a File object and check to see // if there is anything in it before writing // the header. File file = new File( fileName ); if( file.length() == 0 ) { // if the file length is zero // then write the header. super.writeHeader(); } } }
Index: FileAppender.java =================================================================== RCS file: /home/cvspublic/jakarta-log4j/src/java/org/apache/log4j/FileAppender.java,v retrieving revision 1.21 diff -r1.21 FileAppender.java 12a13 > import java.io.File; 342a344,359 > > /** > Write a header as produced by the embedded layout's {@link > Layout#getHeader} method. */ > protected > void writeHeader() { > // Create a File object and check to see > // if there is anything in it before writing > // the header. > File file = new File( fileName ); > if( file.length() == 0 ) { > // if the file length is zero > // then write the header. > super.writeHeader(); > } > }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]