Hi Nicko,
It's been a while since I've been able to contribute to log4net. Glad
to see the project is still alive and well.
Here are some changes that harden the FileAppender and
RollingFileAppender so that they can (re)try to open the file if it
fails. I've hand-tested this in the debugger by setting the log file
read-only attribute, and using logging, and it seems to work.
Changes:
1) File open no longer occurs in the constructor - instead it happens
before append to allow retries
2) The file Open operation will retry if it fails
3) The Delete operation of the RollingFileAppender is wrapped with
try...finally, to allow rolling to continue even if some files are
inacessible
4) File name and append state are saved before Open attempt in case
they are needed later
Hopefully the changes look good and you can merge this into the current
code base. Let me know if you need more info, or if you prefer me to
send you the source files with the modifications.
-Doug
cvs diff TextWriterAppender.cs (in directory
C:\Temp\log4net\src\Appender\)
Index: TextWriterAppender.cs
===================================================================
RCS file: /cvsroot/log4net/log4net/src/Appender/TextWriterAppender.cs,v
retrieving revision 1.39
diff -r1.39 TextWriterAppender.cs
148a149,163
> if( HasWriter() )
> {
> return true;
> }
>
> if( PrepareWriter() )
> {
> return HasWriter();
> }
>
> return false;
> }
>
> protected virtual bool HasWriter()
> {
153a169
>
159a176,182
> LogLog.Debug( "TextWriterAppender: HasWriter
returning true" );
> return true;
> }
>
> protected virtual bool PrepareWriter()
> {
> LogLog.Debug( "TextWriterAppender: PrepareWriter
returning true" );
*****CVS exited normally with code 1*****
cvs diff RollingFileAppender.cs (in directory
C:\Temp\log4net\src\Appender\)
Index: RollingFileAppender.cs
===================================================================
RCS file: /cvsroot/log4net/log4net/src/Appender/RollingFileAppender.cs,v
retrieving revision 1.47
diff -r1.47 RollingFileAppender.cs
418,419c418
<
< /// <summary>
---
> /// <summary>
823c822
< this.OpenFile(m_baseFileName, false);
---
> PrepareFile( m_baseFileName, false );
839,845d837
< FileInfo target = new FileInfo(toFile);
< if (target.Exists)
< {
< LogLog.Debug("RollingFileAppender:
Deleting existing target file ["+target+"]");
< target.Delete();
< }
<
849a842,859
>
> try
> {
> // Trap exceptions during delete
to make rolling more robust (if one file
> // is temporarily locked while
someone is reading it, for example). The
> // rolling process should not be
stopped because of a single failure...
> FileInfo target = new
FileInfo(toFile);
> if (target.Exists)
> {
>
LogLog.Debug("RollingFileAppender: Deleting existing target file
["+target+"]");
> target.Delete();
> }
> }
> catch(Exception ex)
> {
> ErrorHandler.Error("Exception
while deleting target file [" + toFile + "]", ex,
ErrorCode.GenericFailure);
> }
>
851a862,864
> //
> // Try the move separately,
since it may succeed even though delete doesn't
> //
958,967c971,981
< 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);
< }
---
> PrepareFile( m_baseFileName, false );
> }
>
> private void PrepareFile( string fileName, bool append )
> {
> m_fileName = m_baseFileName;
> m_appendToFile = false;
>
> LogLog.Debug( string.Format(
"RollingFileAppender: PrepareWriter called for file {0} and append {1}",
m_fileName, m_appendToFile ) );
>
> PrepareWriter();
*****CVS exited normally with code 1*****
cvs diff FileAppender.cs (in directory C:\Temp\log4net\src\Appender\)
Index: FileAppender.cs
===================================================================
RCS file: /cvsroot/log4net/log4net/src/Appender/FileAppender.cs,v
retrieving revision 1.30
diff -r1.30 FileAppender.cs
57d56
< OpenFile(filename, append);
137,151c136
< // 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);
< }
---
> PrepareWriter();
159a145,171
> /// <summary>
> /// Called to get ready for logging, when the file is
not already open.
> /// </summary>
> /// <returns>true if the open was successful, or false
otherwise</returns>
> protected override bool PrepareWriter()
> {
> LogLog.Debug( string.Format( "FileAppender:
PrepareWriter called for file {0} and append {1}", m_fileName,
m_appendToFile ) );
>
> // 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);
> return true;
> }
> catch(Exception e)
> {
>
ErrorHandler.Error("OpenFile("+fileName+","+appendToFile+") call
failed.", e, ErrorCode.FileOpenFailure);
> }
> return false;
> }
>
205a218,219
> LogLog.Debug("FileAppender: Opening file
for writing ["+fileName+"] append ["+append+"]");
>
208c222,224
< 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;
222,224d237
< m_fileName = fileName;
< m_appendToFile = append;
<
282c295
< private bool m_appendToFile = true;
---
> protected bool m_appendToFile = true;
287c300
< private string m_fileName = null;
---
> protected string m_fileName = null;
*****CVS exited normally with code 1*****