nicko 2004/09/18 09:34:16
Modified: src/Appender FileAppender.cs RollingFileAppender.cs
TextWriterAppender.cs
Log:
Added Doug de la Torre's updates to make the FileAppender and
RollingFileAppender more robust.
The TextWriterAppender.PrepareWriter method is called for each message logged
if the Writer has not been set.
FileAppender uses PrepareWriter to attempt to open the file for each message
rather than just once at configuration. Once the file has been opened a write
lock is held.
RollingFileAppender moves files before deleting them as this reduces the
number of situations where a file cannot be rolled.
Revision Changes Path
1.6 +85 -33 logging-log4net/src/Appender/FileAppender.cs
Index: FileAppender.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Appender/FileAppender.cs,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- FileAppender.cs 1 Jun 2004 18:34:40 -0000 1.5
+++ FileAppender.cs 18 Sep 2004 16:34:16 -0000 1.6
@@ -31,16 +31,35 @@
/// </summary>
/// <remarks>
/// <para>
- /// Logging events are sent to the specified file.
+ /// Logging events are sent to the file specified by
+ /// the <see cref="File"/> property.
/// </para>
/// <para>
- /// The file can be opened in either append or
- /// overwrite mode.
+ /// The file can be opened in either append or overwrite mode
+ /// by specifying the <see cref="AppendToFile"/> property.
+ /// If the file path is relative it is taken as relative from
+ /// the application base directory. The file encoding can be
+ /// specified by setting the <see cref="Encoding"/> property.
+ /// </para>
+ /// <para>
+ /// The layout's <see cref="ILayout.Header"/> and <see
cref="ILayout.Footer"/>
+ /// values will be written each time the file is opened and closed
+ /// respectively. If the <see cref="AppendToFile"/> property is <see
langword="true"/>
+ /// then the file may contain multiple copies of the header and footer.
+ /// </para>
+ /// <para>
+ /// This appender will first try to open the file for writing when <see
cref="ActivateOptions"/>
+ /// is called. This will typically be during configuration.
+ /// If the file cannot be opened for writing the appender will attempt
+ /// to open the file again each time a message is logged to the
appender.
+ /// If the file cannot be opened for writing when a message is logged
then
+ /// the message will be discarded by this appender.
/// </para>
/// </remarks>
/// <author>Nicko Cadell</author>
/// <author>Gert Driesen</author>
/// <author>Rodrigo B. de Oliveira</author>
+ /// <author>Douglas de la Torre</author>
public class FileAppender : TextWriterAppender
{
#region Public Instance Constructors
@@ -62,7 +81,7 @@
public FileAppender(ILayout layout, string filename, bool
append)
{
Layout = layout;
- OpenFile(filename, append);
+ SafeOpenFile(filename, append);
}
/// <summary>
@@ -71,7 +90,7 @@
/// </summary>
/// <param name="layout">the layout to use with this
appender</param>
/// <param name="filename">the full path to the file to write
to</param>
- [Obsolete("Instead use the default constructor and set the
Layout & File propertes")]
+ [Obsolete("Instead use the default constructor and set the
Layout & File properties")]
public FileAppender(ILayout layout, string filename) :
this(layout, filename, true)
{
}
@@ -124,6 +143,12 @@
/// <value>
/// The <see cref="Encoding"/> used to write to the file.
/// </value>
+ /// <remarks>
+ /// <para>
+ /// The default encoding set is <see
cref="System.Text.Encoding.Default"/>
+ /// which is the encoding for the system's current ANSI code
page.
+ /// </para>
+ /// </remarks>
public Encoding Encoding
{
get { return m_encoding; }
@@ -158,21 +183,7 @@
base.ActivateOptions();
if (m_fileName != null)
{
- // We must cache the params locally because
OpenFile will call
- // Reset which will clear the class fields. We
need to remember the
- // values in case of an error.
-
- string fileName = m_fileName;
- bool appendToFile = m_appendToFile;
-
- try
- {
- OpenFile(fileName, appendToFile);
- }
- catch(Exception e)
- {
-
ErrorHandler.Error("OpenFile("+fileName+","+appendToFile+") call failed.", e,
ErrorCode.FileOpenFailure);
- }
+ SafeOpenFile(m_fileName, m_appendToFile);
}
else
{
@@ -194,6 +205,20 @@
m_fileName = null;
}
+ /// <summary>
+ /// Called to initialize the file writer
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// Will be called for each logged message until the file is
+ /// successfully opened.
+ /// </para>
+ /// </remarks>
+ override protected void PrepareWriter()
+ {
+ SafeOpenFile(m_fileName, m_appendToFile);
+ }
+
#endregion Override implementation of TextWriterAppender
#region Public Instance Methods
@@ -211,17 +236,42 @@
#region Protected Instance Methods
/// <summary>
- /// Sets and <i>opens</i> the file where the log output will
- /// go. The specified file must be writable.
+ /// Sets and <i>opens</i> the file where the log output will
go. The specified file must be writable.
+ /// </summary>
+ /// <param name="fileName">The path to the log file</param>
+ /// <param name="append">If true will append to fileName.
Otherwise will truncate fileName</param>
+ /// <remarks>
+ /// <para>
+ /// Calls <see cref="OpenFile"/> but guarantees not to throw an
exception.
+ /// Errors are passed to the <see
cref="TextWriterAppender.ErrorHandler"/>.
+ /// </para>
+ /// </remarks>
+ virtual protected void SafeOpenFile(string fileName, bool
append)
+ {
+ try
+ {
+ OpenFile(fileName, append);
+ }
+ catch(Exception e)
+ {
+
ErrorHandler.Error("OpenFile("+fileName+","+append+") call failed.", e,
ErrorCode.FileOpenFailure);
+ }
+ }
+
+ /// <summary>
+ /// Sets and <i>opens</i> the file where the log output will
go. The specified file must be writable.
/// </summary>
/// <param name="fileName">The path to the log file</param>
/// <param name="append">If true will append to fileName.
Otherwise will truncate fileName</param>
/// <remarks>
- /// <para>If there was already an opened file, then the
previous file
- /// is closed first.</para>
- ///
- /// <para>This method will ensure that the directory structure
- /// for the <paramref name="fileName"/> specified exists.</para>
+ /// <para>
+ /// If there was already an opened file, then the previous file
+ /// is closed first.
+ /// </para>
+ /// <para>
+ /// This method will ensure that the directory structure
+ /// for the <paramref name="fileName"/> specified exists.
+ /// </para>
/// </remarks>
virtual protected void OpenFile(string fileName, bool append)
{
@@ -231,8 +281,12 @@
LogLog.Debug("FileAppender: Opening file for
writing ["+fileName+"] append ["+append+"]");
+ // Save these for later, allowing retries if
file open fails
+ m_fileName = fileName;
+ m_appendToFile = append;
+
// Ensure that the directory structure exists
- string directoryFullName = (new
FileInfo(fileName)).DirectoryName;
+ string directoryFullName =
Path.GetDirectoryName(fileName);
// Only create the directory if it does not
exist
// doing this check here resolves some
permissions failures
@@ -243,9 +297,6 @@
SetQWForFiles(new StreamWriter(fileName,
append, m_encoding));
- m_fileName = fileName;
- m_appendToFile = append;
-
WriteHeader();
}
}
@@ -287,10 +338,11 @@
throw new ArgumentNullException("path");
}
- if (SystemInfo.ApplicationBaseDirectory != null)
+ string applicationBaseDirectory =
SystemInfo.ApplicationBaseDirectory;
+ if (applicationBaseDirectory != null)
{
// Note that Path.Combine will return the
second path if it is rooted
- return
Path.GetFullPath(Path.Combine(SystemInfo.ApplicationBaseDirectory, path));
+ return
Path.GetFullPath(Path.Combine(applicationBaseDirectory, path));
}
return Path.GetFullPath(path);
}
1.8 +165 -96 logging-log4net/src/Appender/RollingFileAppender.cs
Index: RollingFileAppender.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Appender/RollingFileAppender.cs,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- RollingFileAppender.cs 7 Jun 2004 01:09:38 -0000 1.7
+++ RollingFileAppender.cs 18 Sep 2004 16:34:16 -0000 1.8
@@ -33,31 +33,81 @@
/// </summary>
/// <remarks>
/// <para>
- /// RollingFileAppender can function as either or and do both
- /// at the same time (making size based rolling files until a data/time
- /// boundary is crossed at which time it rolls all of those files
- /// based on the setting for <see cref="RollingStyle"/>.
+ /// RollingFileAppender can roll log files based on size or date or both
+ /// depending on the setting of the <see cref="RollingStyle"/> property.
+ /// When set to <see cref="RollingMode.Size"/> the log file will be
rolled
+ /// once its size exceeds the <see cref="MaximumFileSize"/>.
+ /// When set to <see cref="RollingMode.Date"/> the log file will be
rolled
+ /// once the date boundary specified in the <see cref="DatePattern"/>
property
+ /// is crossed.
+ /// When set to <see cref="RollingMode.Composite"/> the log file will be
+ /// rolled once the date boundary specified in the <see
cref="DatePattern"/> property
+ /// is crossed, but within a date boundary the file will also be rolled
+ /// once its size exceeds the <see cref="MaximumFileSize"/>.
/// </para>
/// <para>
- /// A of few additional optional features have been added:<br/>
- /// -- Attach date pattern for current log file <see
cref="StaticLogFileName"/><br/>
- /// -- Backup number increments for newer files <see
cref="CountDirection"/><br/>
- /// -- Infinite number of backups by file size <see
cref="MaxSizeRollBackups"/>
+ /// A of few additional optional features have been added:
+ /// <list type="bullet">
+ /// <item>Attach date pattern for current log file <see
cref="StaticLogFileName"/></item>
+ /// <item>Backup number increments for newer files <see
cref="CountDirection"/></item>
+ /// <item>Infinite number of backups by file size <see
cref="MaxSizeRollBackups"/></item>
+ /// </list>
/// </para>
+ ///
+ /// <note>
/// <para>
- /// A few notes and warnings: For large or infinite number of backups
- /// countDirection > 0 is highly recommended, with staticLogFileName
= false if
- /// time based rolling is also used -- this will reduce the number of
file renamings
- /// to few or none. Changing staticLogFileName or countDirection
without clearing
- /// the directory could have nasty side effects. If Date/Time based
rolling
- /// is enabled, CompositeRollingAppender will attempt to roll existing
files
- /// in the directory without a date/time tag based on the last modified
date
- /// of the base log files last modification.
+ /// For large or infinite numbers of backup files a <see
cref="CountDirection"/>
+ /// greater than zero is highly recommended, otherwise all the backup
files need
+ /// to be renamed each time a new backup is created.
/// </para>
/// <para>
- /// A maximum number of backups based on date/time boundaries would be
nice
- /// but is not yet implemented.
+ /// When Date/Time based rolling is used setting <see
cref="StaticLogFileName"/>
+ /// to <see langword="true"/> will reduce the number of file renamings
to few or none.
/// </para>
+ /// </note>
+ ///
+ /// <note type="caution">
+ /// <para>
+ /// Changing <see cref="StaticLogFileName"/> or <see
cref="CountDirection"/> without clearing
+ /// the log file directory of backup files will cause unexpected and
unwanted side effects.
+ /// </para>
+ /// </note>
+ ///
+ /// <para>
+ /// If Date/Time based rolling is enabled this appender will attempt to
roll existing files
+ /// in the directory without a Date/Time tag based on the last write
date of the base log file.
+ /// The appender only rolls the log file when a message is logged. If
Date/Time based rolling
+ /// is enabled then the appender will not roll the log file at the
Date/Time boundary but
+ /// at the point when the next message is logged after the boundary has
been crossed.
+ /// </para>
+ ///
+ /// <para>
+ /// The <see cref="RollingFileAppender"/> extends the <see
cref="FileAppender"/> and
+ /// has the same behavior when opening the log file.
+ /// The appender will first try to open the file for writing when <see
cref="ActivateOptions"/>
+ /// is called. This will typically be during configuration.
+ /// If the file cannot be opened for writing the appender will attempt
+ /// to open the file again each time a message is logged to the
appender.
+ /// If the file cannot be opened for writing when a message is logged
then
+ /// the message will be discarded by this appender.
+ /// </para>
+ /// <para>
+ /// When rolling a backup file necessitates deleting an older backup
file the
+ /// file to be deleted is moved to a temporary name before being
deleted.
+ /// On the Windows platform if another process has a write lock on the
file
+ /// that is to be deleted, but allows shared read access to the file
then the
+ /// file can be moved, but cannot be deleted. If the other process also
allows
+ /// shared delete access to the file then the file will be deleted once
that
+ /// process closes the file. If it is necessary to open the log file or
any
+ /// of the backup files outside of this appender for either read or
+ /// write access please ensure that read and delete share modes are
enabled.
+ /// </para>
+ ///
+ /// <note type="caution">
+ /// <para>
+ /// A maximum number of backup files when rolling on date/time
boundaries is not supported.
+ /// </para>
+ /// </note>
/// </remarks>
/// <author>Nicko Cadell</author>
/// <author>Gert Driesen</author>
@@ -212,7 +262,7 @@
/// before being rolled over to backup files.
/// </summary>
/// <value>
- /// The maximum size that the output file is allowed to reach
before being
+ /// The maximum size in bytes that the output file is allowed
to reach before being
/// rolled over to backup files.
/// </value>
/// <remarks>
@@ -223,7 +273,7 @@
/// argument.
/// </para>
/// <para>
- /// The default maximum file size is 10MB.
+ /// The default maximum file size is 10MB (10*1024*1024).
/// </para>
/// </remarks>
public long MaxFileSize
@@ -247,11 +297,16 @@
/// expressed respectively in kilobytes, megabytes or
gigabytes.
/// </para>
/// <para>
- /// For example, the value "10KB" will be interpreted as 10240.
+ /// For example, the value "10KB" will be interpreted as 10240
bytes.
/// </para>
/// <para>
/// The default maximum file size is 10MB.
/// </para>
+ /// <para>
+ /// If you have the option to set the maximum file size
programmatically
+ /// consider using the <see cref="MaxFileSize"/> property
instead as this
+ /// allows you to set the size in bytes as a <see
cref="Int64"/>.
+ /// </para>
/// </remarks>
public string MaximumFileSize
{
@@ -359,8 +414,7 @@
/// </para>
/// <para>
/// This will make time based rollovers with a large number of
backups
- /// much faster -- it won't have to
- /// rename all the backups!
+ /// much faster as the appender it won't have to rename all the
backups!
/// </para>
/// </remarks>
public bool StaticLogFileName
@@ -450,10 +504,9 @@
long currentCount = 0;
if (append)
{
- FileInfo fileInfo = new
FileInfo(fileName);
- if (fileInfo.Exists)
+ if (System.IO.File.Exists(fileName))
{
- currentCount = fileInfo.Length;
+ currentCount = (new
FileInfo(fileName)).Length;
}
}
@@ -486,13 +539,11 @@
sName = m_scheduledFilename;
}
- FileInfo fileInfo = new FileInfo(sName);
- if (null != fileInfo)
- {
- ArrayList arrayFiles =
GetExistingFiles(fileInfo.FullName);
- InitializeRollBackups((new
FileInfo(m_baseFileName)).Name, arrayFiles);
+ string fullPath = System.IO.Path.GetFullPath(sName);
+ string fileName = System.IO.Path.GetFileName(fullPath);
- }
+ ArrayList arrayFiles = GetExistingFiles(fullPath);
+ InitializeRollBackups(fileName, arrayFiles);
LogLog.Debug("RollingFileAppender: curSizeRollBackups
starts at ["+m_curSizeRollBackups+"]");
}
@@ -518,21 +569,20 @@
{
ArrayList alFiles = new ArrayList();
- FileInfo fileInfo = new FileInfo(baseFilePath);
- DirectoryInfo dirInfo = fileInfo.Directory;
- LogLog.Debug("RollingFileAppender: Searching for
existing files in ["+dirInfo+"]");
+ string directory = Path.GetDirectoryName(baseFilePath);
+ LogLog.Debug("RollingFileAppender: Searching for
existing files in ["+directory+"]");
- if (dirInfo.Exists)
+ if (Directory.Exists(directory))
{
- string baseFileName = fileInfo.Name;
+ string baseFileName =
Path.GetFileName(baseFilePath);
- FileInfo[] files =
dirInfo.GetFiles(GetWildcardPatternForFile(baseFileName));
+ string[] files = Directory.GetFiles(directory,
GetWildcardPatternForFile(baseFileName));
if (files != null)
{
for (int i = 0; i < files.Length; i++)
{
- string curFileName =
files[i].Name;
+ string curFileName =
Path.GetFileName(files[i]);
if
(curFileName.StartsWith(baseFileName))
{
alFiles.Add(curFileName);
@@ -550,10 +600,9 @@
{
if (m_staticLogFileName && m_rollDate)
{
- FileInfo old = new FileInfo(m_baseFileName);
- if (old.Exists)
+ if (System.IO.File.Exists(m_baseFileName))
{
- DateTime last = old.LastWriteTime;
+ DateTime last =
System.IO.File.GetLastWriteTime(m_baseFileName);
LogLog.Debug("RollingFileAppender:
["+last.ToString(m_datePattern,System.Globalization.DateTimeFormatInfo.InvariantInfo)+"]
vs.
["+m_now.ToString(m_datePattern,System.Globalization.DateTimeFormatInfo.InvariantInfo)+"]");
if
(!(last.ToString(m_datePattern,System.Globalization.DateTimeFormatInfo.InvariantInfo).Equals(m_now.ToString(m_datePattern,
System.Globalization.DateTimeFormatInfo.InvariantInfo))))
@@ -568,11 +617,18 @@
}
/// <summary>
- /// <para>Initializes based on existing conditions at time of
<see cref="ActivateOptions"/>.
- /// The following is done:</para>
- /// A) determine curSizeRollBackups (only within
the current roll point)
- /// B) initiates a roll over if needed for crossing
a date boundary since the last run.
+ /// Initializes based on existing conditions at time of <see
cref="ActivateOptions"/>.
/// </summary>
+ /// <remarks>
+ /// <para>
+ /// Initializes based on existing conditions at time of <see
cref="ActivateOptions"/>.
+ /// The following is done
+ /// <list type="bullet">
+ /// <item>determine curSizeRollBackups (only within the
current roll point)</item>
+ /// <item>initiates a roll over if needed for crossing a
date boundary since the last run.</item>
+ /// </list>
+ /// </para>
+ /// </remarks>
protected void ExistingInit()
{
DetermineCurSizeRollBackups();
@@ -663,7 +719,7 @@
LogLog.Debug("RollingFileAppender: File
name ["+curFileName+"] moves current count to ["+m_curSizeRollBackups+"]");
}
}
- catch (FormatException /*e*/)
+ catch(FormatException)
{
//this happens when file.log ->
file.log.yyyy-mm-dd which is normal
//when staticLogFileName == false
@@ -694,7 +750,7 @@
/// <summary>
/// Calculates the RollPoint for the datePattern supplied.
/// </summary>
- /// <param name="datePattern">the date pattern to caluculate
the check period for</param>
+ /// <param name="datePattern">the date pattern to calculate the
check period for</param>
/// <returns>The RollPoint that is most accurate for the date
pattern supplied</returns>
/// <remarks>
/// Essentially the date pattern is examined to determine what
the
@@ -706,19 +762,18 @@
/// </remarks>
private RollPoint ComputeCheckPeriod(string datePattern)
{
- // set date to 1970-01-01 00:00:00 this is
UniversalSortableDateTimePattern
+ // s_date1970 is 1970-01-01 00:00:00 this is
UniversalSortableDateTimePattern
// (based on ISO 8601) using universal time. This date
is used for reference
// purposes to calculate the resolution of the date
pattern.
- DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
// Get string representation of base line date
- string r0 = epoch.ToString(datePattern,
System.Globalization.DateTimeFormatInfo.InvariantInfo);
+ string r0 = s_date1970.ToString(datePattern,
System.Globalization.DateTimeFormatInfo.InvariantInfo);
// Check each type of rolling mode starting with the
smallest increment.
for(int i = (int)RollPoint.TopOfMinute; i <=
(int)RollPoint.TopOfMonth; i++)
{
// Get string representation of next pattern
- string r1 = NextCheckDate(epoch,
(RollPoint)i).ToString(datePattern,
System.Globalization.DateTimeFormatInfo.InvariantInfo);
+ string r1 = NextCheckDate(s_date1970,
(RollPoint)i).ToString(datePattern,
System.Globalization.DateTimeFormatInfo.InvariantInfo);
LogLog.Debug("RollingFileAppender: Type =
["+i+"], r0 = ["+r0+"], r1 = ["+r1+"]");
@@ -799,7 +854,7 @@
{
if (m_staticLogFileName)
{
- /* Compute filename, but only if datePattern is
specified */
+ // Compute filename, but only if datePattern is
specified
if (m_datePattern == null)
{
ErrorHandler.Error("Missing DatePattern
option in rollOver().");
@@ -831,22 +886,14 @@
RollFile(File, m_scheduledFilename);
}
- try
- {
- //We've cleared out the old date and are ready
for the new
- m_curSizeRollBackups = 0;
-
- //new scheduled name
- m_scheduledFilename = File +
m_now.ToString(m_datePattern,
System.Globalization.DateTimeFormatInfo.InvariantInfo);
+ //We've cleared out the old date and are ready for the
new
+ m_curSizeRollBackups = 0;
+
+ //new scheduled name
+ m_scheduledFilename = File +
m_now.ToString(m_datePattern,
System.Globalization.DateTimeFormatInfo.InvariantInfo);
- // This will also close the file. This is OK
since multiple
- // close operations are safe.
- this.OpenFile(m_baseFileName, false);
- }
- catch(Exception e)
- {
- ErrorHandler.Error("setFile(" + File + ",
false) call failed.", e, ErrorCode.FileOpenFailure);
- }
+ // This will also close the file. This is OK since
multiple close operations are safe.
+ SafeOpenFile(m_baseFileName, false);
}
/// <summary>
@@ -857,25 +904,20 @@
/// <param name="toFile">New name for file.</param>
protected void RollFile(string fromFile, string toFile)
{
- FileInfo target = new FileInfo(toFile);
- if (target.Exists)
- {
- LogLog.Debug("RollingFileAppender: Deleting
existing target file ["+target+"]");
- target.Delete();
- }
-
- FileInfo file = new FileInfo(fromFile);
- if (file.Exists)
+ if (System.IO.File.Exists(fromFile))
{
+ // Delete the toFile if it exists
+ DeleteFile(toFile);
+
// We may not have permission to move the file,
or the file may be locked
try
{
- file.MoveTo(toFile);
- LogLog.Debug("RollingFileAppender:
Moved [" + fromFile + "] -> [" + toFile + "]");
+ LogLog.Debug("RollingFileAppender:
Moving [" + fromFile + "] -> [" + toFile + "]");
+ System.IO.File.Move(fromFile, toFile);
}
- catch(Exception ex)
+ catch(Exception moveEx)
{
- ErrorHandler.Error("Exception while
rolling file [" + fromFile + "] -> [" + toFile + "]", ex,
ErrorCode.GenericFailure);
+ ErrorHandler.Error("Exception while
rolling file [" + fromFile + "] -> [" + toFile + "]", moveEx,
ErrorCode.GenericFailure);
}
}
else
@@ -890,18 +932,44 @@
/// <param name="fileName">The file to delete.</param>
protected void DeleteFile(string fileName)
{
- FileInfo file = new FileInfo(fileName);
- if (file.Exists)
+ if (System.IO.File.Exists(fileName))
{
// We may not have permission to delete the
file, or the file may be locked
+
+ string fileToDelete = fileName;
+
+ // Try to move the file to temp name.
+ // If the file is locked we should still be
able to move it
+ string tempFileName = fileName + "." +
Environment.TickCount + ".DeletePending";
+ try
+ {
+ System.IO.File.Move(fileName,
tempFileName);
+ fileToDelete = tempFileName;
+ }
+ catch(Exception moveEx)
+ {
+ LogLog.Debug("RollingFileAppender:
Exception while moving file to be deleted [" + fileName + "] -> [" +
tempFileName + "]", moveEx);
+ }
+
+ // Try to delete the file (either the original
or the moved file)
try
{
- file.Delete();
+ System.IO.File.Delete(fileToDelete);
LogLog.Debug("RollingFileAppender:
Deleted file [" + fileName + "]");
}
- catch(Exception ex)
+ catch(Exception deleteEx)
{
- ErrorHandler.Error("Exception while
deleting file [" + fileName + "]", ex, ErrorCode.GenericFailure);
+ if (fileToDelete == fileName)
+ {
+ // Unable to move or delete the
file
+ ErrorHandler.Error("Exception
while deleting file [" + fileToDelete + "]", deleteEx,
ErrorCode.GenericFailure);
+ }
+ else
+ {
+ // Moved the file, but the
delete failed. File is probably locked.
+ // The file should
automatically be deleted when the lock is released.
+
LogLog.Debug("RollingFileAppender: Exception while deleting temp file [" +
fileToDelete + "]", deleteEx);
+ }
}
}
}
@@ -976,16 +1044,8 @@
}
}
- try
- {
- // This will also close the file. This is OK
since multiple
- // close operations are safe.
- this.OpenFile(m_baseFileName, false);
- }
- catch(Exception e)
- {
- ErrorHandler.Error("OpenFile
["+m_baseFileName+"] call failed.", e);
- }
+ // This will also close the file. This is OK since
multiple close operations are safe.
+ SafeOpenFile(m_baseFileName, false);
}
#endregion
@@ -1150,6 +1210,15 @@
private string m_baseFileName;
#endregion Private Instance Fields
+
+ #region Static Members
+
+ /// <summary>
+ /// The 1st of January 1970 in UTC
+ /// </summary>
+ private static readonly DateTime s_date1970 = new
DateTime(1970, 1, 1);
+
+ #endregion
#region DateTime
1.5 +37 -6 logging-log4net/src/Appender/TextWriterAppender.cs
Index: TextWriterAppender.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Appender/TextWriterAppender.cs,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- TextWriterAppender.cs 1 Jun 2004 18:34:40 -0000 1.4
+++ TextWriterAppender.cs 18 Sep 2004 16:34:16 -0000 1.5
@@ -29,10 +29,18 @@
/// Sends logging events to a <see cref="TextWriter"/>.
/// </summary>
/// <remarks>
+ /// <para>
/// An Appender that writes to a <see cref="TextWriter"/>.
+ /// </para>
+ /// <para>
+ /// This appender may be used stand alone if initialized with an
appropriate
+ /// writer, however it is typically used as a base class for an
appender that
+ /// can open a <see cref="TextWriter"/> to write to.
+ /// </para>
/// </remarks>
/// <author>Nicko Cadell</author>
/// <author>Gert Driesen</author>
+ /// <author>Douglas de la Torre</author>
public class TextWriterAppender : AppenderSkeleton
{
#region Public Instance Constructors
@@ -128,8 +136,11 @@
lock(this)
{
Reset();
- m_qtw = new QuietTextWriter(value,
ErrorHandler);
- WriteHeader();
+ if (value != null)
+ {
+ m_qtw = new
QuietTextWriter(value, ErrorHandler);
+ WriteHeader();
+ }
}
}
}
@@ -157,15 +168,21 @@
if (m_qtw == null)
{
- ErrorHandler.Error("No output stream or file
set for the appender named ["+ Name +"].");
- return false;
+ // Allow subclass to lazily create the writer
+ PrepareWriter();
+
+ if (m_qtw == null)
+ {
+ ErrorHandler.Error("No output stream or
file set for the appender named ["+ Name +"].");
+ return false;
+ }
}
if (m_qtw.Closed)
{
ErrorHandler.Error("Output stream for appender
named ["+ Name +"] has been closed.");
return false;
}
-
+
return true;
}
@@ -320,7 +337,21 @@
m_qtw.Write(h);
}
}
- }
+ }
+
+ /// <summary>
+ /// Called to allow a subclass to lazily initialize the writer
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// This method is called when an event is logged and the <see
cref="Writer"/> or
+ /// <see cref="QuietWriter"/> have not been set. This allows a
subclass to
+ /// attempt to initialize the writer multiple times.
+ /// </para>
+ /// </remarks>
+ virtual protected void PrepareWriter()
+ {
+ }
#endregion Protected Instance Methods