The version of Apache log4j used by SoundHelix.
Clone
HTTPS:
git clone https://vervis.peers.community/repos/aEp6o
SSH:
git clone USERNAME@vervis.peers.community:aEp6o
Branches
Tags
- 1.3alpha-7
- CHAINSAW_2_SANDBOX_MERGE
- CORE_VERSION
- LEVEL_REPLACES_PRIORITY
- PREALPHA_1_3_AS_OF_2004_05_12
- PRE_CHAINSAW_MODEL_CONVERSION
- PRE_UGLI_MOVE
- TAG_CHAINSAW2_MOVE
- log4j-1.2.17
- log4j-1.2.17-rc1
- v1.3alpha8
- v1.3alpha8-temp
- v1_2_1
- v1_2_10-recalled
- v1_2_11
- v1_2_11_rc1
- v1_2_11rc3
- v1_2_12
- v1_2_12_rc1
- v1_2_12_rc2
- v1_2_12_rc3
- v1_2_12_rc4
- v1_2_12_rc5
- v1_2_12_rc6
- v1_2_13
- v1_2_13_rc1
- v1_2_13_rc2
- v1_2_13_site_update
- v1_2_14
- v1_2_14_maven
- v1_2_14_rc1
- v1_2_14_site_update
- v1_2_15
- v1_2_15_rc1
- v1_2_15_rc2
- v1_2_15_rc3
- v1_2_15_rc4
- v1_2_15_rc5
- v1_2_15_rc6
- v1_2_16
- v1_2_16_rc1
- v1_2_16_rc2
- v1_2_17
- v1_2_17-rc1
- v1_2_17_rc1
- v1_2_17_rc2
- v1_2_17_rc3
- v1_2_2
- v1_2_3
- v1_2_4
- v1_2_6
- v1_2_7
- v1_2_9
- v1_2_alpha0
- v1_2_alpha7
- v1_2beta1
- v1_2final
- v1_3alpha_1
- v1_3alpha_6
- v_1_0
- v_1_0_1
- v_1_0_4
- v_1_1
- v_1_1_1
- v_1_1_2
- v_1_1_3
- v_1_1_b1
- v_1_1b2
- v_1_1b3
- v_1_1b5
- v_1_1b6
- v_1_1b7
- v_1_2beta3
FileAppender.java
/*
* 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.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 <jens.pipka@gmx.de>
/**
FileAppender appends log events to the console, to a file, to a
{@link java.io.Writer} or an {@link java.io.OutputStream} depending
on the user's choice.
@author Ceki Gülcü
*/
public class FileAppender extends AppenderSkeleton {
/**
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.
*/
public static final String FILE_OPTION = "File";
/**
A string constant used in naming the option for immediate
flushing of the output stream at the end of each append
operation. Current value of this string constant is
<b>ImmediateFlush</b>.
<p>Note that all option keys are case sensitive.
@since 0.9.1
*/
public static final String IMMEDIATE_FLUSH_OPTION = "ImmediateFlush";
/**
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.
*/
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;
/**
Immediate flush means that the undelying writer or stream will be
flushed at the end of each append operation. Immediate flush is
slower but ensures that each append request is actually
written. If <code>immediateFlush</code> is set to
<code>false</code>, then there is a good chance that the last few
logs events are not actually written to persistent media when the
application crashes.
<p>The <code>immediateFlush</code> variable is set to
<code>true</code> by default.
@since 0.9.1 */
protected boolean immediateFlush = true;
/**
This is the {@link QuietWriter quietWriter} where we will write
to.
*/
protected QuietWriter qw;
/**
{@link TracerPrintWriter} is specialized in optimized printing
of stack traces (obtained from throwables) to a Writer.
*/
protected TracerPrintWriter tp;
/**
The name of the log file. */
protected String fileName = null;
/**
Is the QuietWriter ours or was it created and passed by the user?
*/
protected boolean qwIsOurs = false;
/**
The default constructor does no longer set a default layout nor a
default output target. */
public
FileAppender() {
}
/**
Instantiate a FileAppender and set the output destination to a
new {@link OutputStreamWriter} initialized with <code>os</code>
as its {@link OutputStream}. */
public
FileAppender(Layout layout, OutputStream os) {
this(layout, new OutputStreamWriter(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. */
public
FileAppender(Layout layout, Writer writer) {
this.layout = layout;
this.setWriter(writer);
}
/**
Instantiate a FileAppender and open the file designated by
<code>filename</code>. The opened filename will become the ouput
destination for this appender.
<p>If the <code>append</code> parameter is true, the file will be
appended to. Otherwise, the file desginated 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);
}
/**
If the a value for {@link #FILE_OPTION} is non-null, 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);
}
}
}
/**
This method called by {@link AppenderSkeleton#doAppend}
method.
<p>If the output stream exists an is writable then write a log
statement to the output stream. Otherwise, write a single warning
message to <code>System.err</code>.
<p>The format of the output will depend on this appender's
layout.
*/
public
void append(LoggingEvent event) {
// Reminder: the nesting of calls is:
//
// doAppend()
// - check threshold
// - filter
// - append();
// - checkEntryConditions();
// - subAppend();
if(!checkEntryConditions()) {
return;
}
subAppend(event);
}
/**
This method determines if there is a sense in attempting to append.
<p>It checks whether there is a set output target and also if
there is a set layout. If these checks fail, then the boolean
value <code>false</code> is returned. */
protected
boolean checkEntryConditions() {
if(this.qw == null) {
errorHandler.error("No output target set for appender named \""+
name+"\".");
return false;
}
if(this.layout == null) {
errorHandler.error("No layout set for appender named \""+ name+"\".");
return false;
}
return true;
}
/**
Will close the stream opened by a previos {@link #setFile}
call. If the writer is owned by the user it remains untouched.
@see #setFile
@see #setWriter
@since 0.8.4
*/
public
void close() {
this.closed = true;
reset();
}
/**
Close this.writer if opened by setFile or FileAppend(filename..)
*/
protected
void closeWriterIfOurs() {
if(this.qwIsOurs && this.qw != null) {
try {
this.qw.close();
}
catch(java.io.IOException e) {
LogLog.error("Could not close output stream " + qw, e);
}
}
}
/**
Retuns 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 AppenderSkeleton}. */
public
String[] getOptionStrings() {
return OptionConverter.concatanateArrays(super.getOptionStrings(),
new String[] {FILE_OPTION, APPEND_OPTION, IMMEDIATE_FLUSH_OPTION});
}
/**
Set the {@link ErrorHandler} for this FileAppender and also the
undelying {@link QuietWriter} if any. */
public
synchronized
void setErrorHandler(ErrorHandler eh) {
this.errorHandler = eh;
if(this.qwIsOurs && this.qw != null) {
this.qw.setErrorHandler(eh);
}
}
/**
<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 stream opened through this
method, then the previous stream is closed first. If the stream
was opened by the user and passed to {@link #setWriter
setWriter}, then the previous stream remains
untouched. It is the users responsability to close it.
@param fileName The path to the log file.
@param boolean 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.qwIsOurs = true;
}
/**
<p>Sets and <i>opens</i> the file where the log output will
go. The specified file must be writable.
<p>The open mode (append/truncate) will depend on the value of
FileAppend option. If undefined, append mode is used.
@param fileName The name of the log file.
*/
public
void setFile(String fileName) throws IOException {
this.setFile(fileName, fileAppend);
}
/**
Set FileAppender specific options.
The recognized options are <b>File</b> and <b>Append</b>,
i.e. the values of the string constants {@link #FILE_OPTION} and
respectively {@link #APPEND_OPTION}. The options of the super
class {@link AppenderSkeleton} are also recognized.
<p>The <b>File</b> option takes a string value which should be
one of the strings "System.out" or "System.err" or the name of a
file.
<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>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.
@since 0.8.1 */
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.
value = value.trim();
if(value.equalsIgnoreCase("System.out"))
setWriter(new OutputStreamWriter(System.out));
else if(value.equalsIgnoreCase("System.err"))
setWriter(new OutputStreamWriter(System.err));
else {
fileName = value;
}
}
else if (key.equalsIgnoreCase(APPEND_OPTION)) {
fileAppend = OptionConverter.toBoolean(value, fileAppend);
}
else if (key.equalsIgnoreCase(IMMEDIATE_FLUSH_OPTION)) {
immediateFlush = OptionConverter.toBoolean(value, immediateFlush);
}
}
/**
<p>Sets the Writer where the log output will go. The
specified Writer must be opened by the user and be
writable.
<p>If there was already an opened stream opened through the {@link
#setFile setFile} method, then the previous stream is closed
first. If the stream was opened by the user and passed to this
method, then the previous stream remains untouched. It is the
user's responsability to close it.
<p><b>WARNING:</b> Logging to an unopened Writer will fail.
<p>
@param Writer An already opened Writer.
@return Writer The previously attached Writer.
*/
public
synchronized
void setWriter(Writer writer) {
reset();
this.qw = new QuietWriter(writer, errorHandler);
this.tp = new TracerPrintWriter(qw);
this.qwIsOurs = false;
}
protected
void setQWForFiles(Writer writer) {
this.qw = new QuietWriter(writer, errorHandler);
}
/**
Actual writing occurs here.
<p>Most sub-classes of <code>FileAppender</code> will need to
override this method.
@since 0.9.0 */
protected
void subAppend(LoggingEvent event) {
this.qw.write(this.layout.format(event));
if(layout.ignoresThrowable()) {
if(event.throwable != null) {
event.throwable.printStackTrace(this.tp);
}
// in case we received this event from a remote client
else if (event.throwableInformation != null) {
this.qw.write(event.throwableInformation);
}
}
if(this.immediateFlush) {
this.qw.flush();
}
}
/**
The FileAppender requires a layout. Hence, this method returns
<code>true</code>.
@since 0.8.4 */
public
boolean requiresLayout() {
return true;
}
protected
void reset() {
closeWriterIfOurs();
this.fileName = null;
this.qw = null;
this.tp = null;
}
}