You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by bo...@apache.org on 2016/08/13 16:06:25 UTC

svn commit: r1756281 - /logging/log4net/trunk/src/Appender/FileAppender.cs

Author: bodewig
Date: Sat Aug 13 16:06:24 2016
New Revision: 1756281

URL: http://svn.apache.org/viewvc?rev=1756281&view=rev
Log:
apply missed patch of #16

Modified:
    logging/log4net/trunk/src/Appender/FileAppender.cs

Modified: logging/log4net/trunk/src/Appender/FileAppender.cs
URL: http://svn.apache.org/viewvc/logging/log4net/trunk/src/Appender/FileAppender.cs?rev=1756281&r1=1756280&r2=1756281&view=diff
==============================================================================
--- logging/log4net/trunk/src/Appender/FileAppender.cs (original)
+++ logging/log4net/trunk/src/Appender/FileAppender.cs Sat Aug 13 16:06:24 2016
@@ -1,1466 +1,1485 @@
-#region Apache License
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more 
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership. 
-// The ASF licenses this file to you under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with 
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#endregion
-
-using System;
-using System.IO;
-using System.Text;
-using System.Threading;
-using log4net.Util;
-using log4net.Layout;
-using log4net.Core;
-
-namespace log4net.Appender
-{
-#if !NETCF
-	/// <summary>
-	/// Appends logging events to a file.
-	/// </summary>
-	/// <remarks>
-	/// <para>
-	/// 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 
-	/// 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>
-	/// <para>
-	/// The <see cref="FileAppender"/> supports pluggable file locking models via
-	/// the <see cref="LockingModel"/> property.
-	/// The default behavior, implemented by <see cref="FileAppender.ExclusiveLock"/> 
-	/// is to obtain an exclusive write lock on the file until this appender is closed.
-	/// The alternative models only hold a
-	/// write lock while the appender is writing a logging event (<see cref="FileAppender.MinimalLock"/>)
-	/// or synchronize by using a named system wide Mutex (<see cref="FileAppender.InterProcessLock"/>).
-	/// </para>
-	/// <para>
-	/// All locking strategies have issues and you should seriously consider using a different strategy that
-	/// avoids having multiple processes logging to the same file.
-	/// </para>
-	/// </remarks>
-	/// <author>Nicko Cadell</author>
-	/// <author>Gert Driesen</author>
-	/// <author>Rodrigo B. de Oliveira</author>
-	/// <author>Douglas de la Torre</author>
-	/// <author>Niall Daley</author>
-#else
-	/// <summary>
-	/// Appends logging events to a file.
-	/// </summary>
-	/// <remarks>
-	/// <para>
-	/// 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 
-	/// 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>
-	/// <para>
-	/// The <see cref="FileAppender"/> supports pluggable file locking models via
-	/// the <see cref="LockingModel"/> property.
-	/// The default behavior, implemented by <see cref="FileAppender.ExclusiveLock"/> 
-	/// is to obtain an exclusive write lock on the file until this appender is closed.
-	/// The alternative model only holds a
-    /// write lock while the appender is writing a logging event (<see cref="FileAppender.MinimalLock"/>).
-	/// </para>
-    /// <para>
-    /// All locking strategies have issues and you should seriously consider using a different strategy that
-    /// avoids having multiple processes logging to the same file.
-    /// </para>
-	/// </remarks>
-	/// <author>Nicko Cadell</author>
-	/// <author>Gert Driesen</author>
-	/// <author>Rodrigo B. de Oliveira</author>
-	/// <author>Douglas de la Torre</author>
-	/// <author>Niall Daley</author>
-#endif
-	public class FileAppender : TextWriterAppender
-	{
-		#region LockingStream Inner Class
-
-		/// <summary>
-		/// Write only <see cref="Stream"/> that uses the <see cref="LockingModelBase"/> 
-		/// to manage access to an underlying resource.
-		/// </summary>
-		private sealed class LockingStream : Stream, IDisposable
-		{
-			public sealed class LockStateException : LogException
-			{
-				public LockStateException(string message)
-					: base(message)
-				{
-				}
-			}
-
-			private Stream m_realStream = null;
-			private LockingModelBase m_lockingModel = null;
-			private int m_readTotal = -1;
-			private int m_lockLevel = 0;
-
-			public LockingStream(LockingModelBase locking)
-				: base()
-			{
-				if (locking == null)
-				{
-					throw new ArgumentException("Locking model may not be null", "locking");
-				}
-				m_lockingModel = locking;
-			}
-
-			#region Override Implementation of Stream
-
-			// Methods
-			public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
-			{
-				AssertLocked();
-				IAsyncResult ret = m_realStream.BeginRead(buffer, offset, count, callback, state);
-				m_readTotal = EndRead(ret);
-				return ret;
-			}
-
-			/// <summary>
-			/// True asynchronous writes are not supported, the implementation forces a synchronous write.
-			/// </summary>
-			public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
-			{
-				AssertLocked();
-				IAsyncResult ret = m_realStream.BeginWrite(buffer, offset, count, callback, state);
-				EndWrite(ret);
-				return ret;
-			}
-
-			public override void Close()
-			{
-				m_lockingModel.CloseFile();
-			}
-
-			public override int EndRead(IAsyncResult asyncResult)
-			{
-				AssertLocked();
-				return m_readTotal;
-			}
-			public override void EndWrite(IAsyncResult asyncResult)
-			{
-				//No-op, it has already been handled
-			}
-			public override void Flush()
-			{
-				AssertLocked();
-				m_realStream.Flush();
-			}
-			public override int Read(byte[] buffer, int offset, int count)
-			{
-				return m_realStream.Read(buffer, offset, count);
-			}
-			public override int ReadByte()
-			{
-				return m_realStream.ReadByte();
-			}
-			public override long Seek(long offset, SeekOrigin origin)
-			{
-				AssertLocked();
-				return m_realStream.Seek(offset, origin);
-			}
-			public override void SetLength(long value)
-			{
-				AssertLocked();
-				m_realStream.SetLength(value);
-			}
-			void IDisposable.Dispose()
-			{
-				Close();
-			}
-			public override void Write(byte[] buffer, int offset, int count)
-			{
-				AssertLocked();
-				m_realStream.Write(buffer, offset, count);
-			}
-			public override void WriteByte(byte value)
-			{
-				AssertLocked();
-				m_realStream.WriteByte(value);
-			}
-
-			// Properties
-			public override bool CanRead
-			{
-				get { return false; }
-			}
-			public override bool CanSeek
-			{
-				get
-				{
-					AssertLocked();
-					return m_realStream.CanSeek;
-				}
-			}
-			public override bool CanWrite
-			{
-				get
-				{
-					AssertLocked();
-					return m_realStream.CanWrite;
-				}
-			}
-			public override long Length
-			{
-				get
-				{
-					AssertLocked();
-					return m_realStream.Length;
-				}
-			}
-			public override long Position
-			{
-				get
-				{
-					AssertLocked();
-					return m_realStream.Position;
-				}
-				set
-				{
-					AssertLocked();
-					m_realStream.Position = value;
-				}
-			}
-
-			#endregion Override Implementation of Stream
-
-			#region Locking Methods
-
-			private void AssertLocked()
-			{
-				if (m_realStream == null)
-				{
-					throw new LockStateException("The file is not currently locked");
-				}
-			}
-
-			public bool AcquireLock()
-			{
-				bool ret = false;
-				lock (this)
-				{
-					if (m_lockLevel == 0)
-					{
-						// If lock is already acquired, nop
-						m_realStream = m_lockingModel.AcquireLock();
-					}
-					if (m_realStream != null)
-					{
-						m_lockLevel++;
-						ret = true;
-					}
-				}
-				return ret;
-			}
-
-			public void ReleaseLock()
-			{
-				lock (this)
-				{
-					m_lockLevel--;
-					if (m_lockLevel == 0)
-					{
-						// If already unlocked, nop
-						m_lockingModel.ReleaseLock();
-						m_realStream = null;
-					}
-				}
-			}
-
-			#endregion Locking Methods
-		}
-
-		#endregion LockingStream Inner Class
-
-		#region Locking Models
-
-		/// <summary>
-		/// Locking model base class
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Base class for the locking models available to the <see cref="FileAppender"/> derived loggers.
-		/// </para>
-		/// </remarks>
-		public abstract class LockingModelBase
-		{
-			private FileAppender m_appender = null;
-
-			/// <summary>
-			/// Open the output file
-			/// </summary>
-			/// <param name="filename">The filename to use</param>
-			/// <param name="append">Whether to append to the file, or overwrite</param>
-			/// <param name="encoding">The encoding to use</param>
-			/// <remarks>
-			/// <para>
-			/// Open the file specified and prepare for logging. 
-			/// No writes will be made until <see cref="AcquireLock"/> is called.
-			/// Must be called before any calls to <see cref="AcquireLock"/>,
-			/// <see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
-			/// </para>
-			/// </remarks>
-			public abstract void OpenFile(string filename, bool append, Encoding encoding);
-
-			/// <summary>
-			/// Close the file
-			/// </summary>
-			/// <remarks>
-			/// <para>
-			/// Close the file. No further writes will be made.
-			/// </para>
-			/// </remarks>
-			public abstract void CloseFile();
-
-			/// <summary>
-			/// Initializes all resources used by this locking model.
-			/// </summary>
-			public abstract void ActivateOptions();
-
-			/// <summary>
-			/// Disposes all resources that were initialized by this locking model.
-			/// </summary>
-			public abstract void OnClose();
-
-			/// <summary>
-			/// Acquire the lock on the file
-			/// </summary>
-			/// <returns>A stream that is ready to be written to.</returns>
-			/// <remarks>
-			/// <para>
-			/// Acquire the lock on the file in preparation for writing to it. 
-			/// Return a stream pointing to the file. <see cref="ReleaseLock"/>
-			/// must be called to release the lock on the output file.
-			/// </para>
-			/// </remarks>
-			public abstract Stream AcquireLock();
-
-			/// <summary>
-			/// Release the lock on the file
-			/// </summary>
-			/// <remarks>
-			/// <para>
-			/// Release the lock on the file. No further writes will be made to the 
-			/// stream until <see cref="AcquireLock"/> is called again.
-			/// </para>
-			/// </remarks>
-			public abstract void ReleaseLock();
-
-			/// <summary>
-			/// Gets or sets the <see cref="FileAppender"/> for this LockingModel
-			/// </summary>
-			/// <value>
-			/// The <see cref="FileAppender"/> for this LockingModel
-			/// </value>
-			/// <remarks>
-			/// <para>
-			/// The file appender this locking model is attached to and working on
-			/// behalf of.
-			/// </para>
-			/// <para>
-			/// The file appender is used to locate the security context and the error handler to use.
-			/// </para>
-			/// <para>
-			/// The value of this property will be set before <see cref="OpenFile"/> is
-			/// called.
-			/// </para>
-			/// </remarks>
-			public FileAppender CurrentAppender
-			{
-				get { return m_appender; }
-				set { m_appender = value; }
-			}
-
-			/// <summary>
-			/// Helper method that creates a FileStream under CurrentAppender's SecurityContext.
-			/// </summary>
-			/// <remarks>
-			/// <para>
-			/// Typically called during OpenFile or AcquireLock. 
-			/// </para>
-			/// <para>
-			/// If the directory portion of the <paramref name="filename"/> does not exist, it is created
-			/// via Directory.CreateDirecctory.
-			/// </para>
-			/// </remarks>
-			/// <param name="filename"></param>
-			/// <param name="append"></param>
-			/// <param name="fileShare"></param>
-			/// <returns></returns>
-			protected Stream CreateStream(string filename, bool append, FileShare fileShare)
-			{
-				using (CurrentAppender.SecurityContext.Impersonate(this))
-				{
-					// Ensure that the directory structure exists
-					string directoryFullName = Path.GetDirectoryName(filename);
-
-					// Only create the directory if it does not exist
-					// doing this check here resolves some permissions failures
-					if (!Directory.Exists(directoryFullName))
-					{
-						Directory.CreateDirectory(directoryFullName);
-					}
-
-					FileMode fileOpenMode = append ? FileMode.Append : FileMode.Create;
-					return new FileStream(filename, fileOpenMode, FileAccess.Write, fileShare);
-				}
-			}
-
-			/// <summary>
-			/// Helper method to close <paramref name="stream"/> under CurrentAppender's SecurityContext.
-			/// </summary>
-			/// <remarks>
-			/// Does not set <paramref name="stream"/> to null.
-			/// </remarks>
-			/// <param name="stream"></param>
-			protected void CloseStream(Stream stream)
-			{
-				using (CurrentAppender.SecurityContext.Impersonate(this))
-				{
-					stream.Close();
-				}
-			}
-		}
-
-		/// <summary>
-		/// Hold an exclusive lock on the output file
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Open the file once for writing and hold it open until <see cref="CloseFile"/> is called. 
-		/// Maintains an exclusive lock on the file during this time.
-		/// </para>
-		/// </remarks>
-		public class ExclusiveLock : LockingModelBase
-		{
-			private Stream m_stream = null;
-
-			/// <summary>
-			/// Open the file specified and prepare for logging.
-			/// </summary>
-			/// <param name="filename">The filename to use</param>
-			/// <param name="append">Whether to append to the file, or overwrite</param>
-			/// <param name="encoding">The encoding to use</param>
-			/// <remarks>
-			/// <para>
-			/// Open the file specified and prepare for logging. 
-			/// No writes will be made until <see cref="AcquireLock"/> is called.
-			/// Must be called before any calls to <see cref="AcquireLock"/>,
-			/// <see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
-			/// </para>
-			/// </remarks>
-			public override void OpenFile(string filename, bool append, Encoding encoding)
-			{
-				try
-				{
-					m_stream = CreateStream(filename, append, FileShare.Read);
-				}
-				catch (Exception e1)
-				{
-					CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + filename + ". " + e1.Message);
-				}
-			}
-
-			/// <summary>
-			/// Close the file
-			/// </summary>
-			/// <remarks>
-			/// <para>
-			/// Close the file. No further writes will be made.
-			/// </para>
-			/// </remarks>
-			public override void CloseFile()
-			{
-				CloseStream(m_stream);
-				m_stream = null;
-			}
-
-			/// <summary>
-			/// Acquire the lock on the file
-			/// </summary>
-			/// <returns>A stream that is ready to be written to.</returns>
-			/// <remarks>
-			/// <para>
-			/// Does nothing. The lock is already taken
-			/// </para>
-			/// </remarks>
-			public override Stream AcquireLock()
-			{
-				return m_stream;
-			}
-
-			/// <summary>
-			/// Release the lock on the file
-			/// </summary>
-			/// <remarks>
-			/// <para>
-			/// Does nothing. The lock will be released when the file is closed.
-			/// </para>
-			/// </remarks>
-			public override void ReleaseLock()
-			{
-				//NOP
-			}
-
-			/// <summary>
-			/// Initializes all resources used by this locking model.
-			/// </summary>
-			public override void ActivateOptions()
-			{
-				//NOP
-			}
-
-			/// <summary>
-			/// Disposes all resources that were initialized by this locking model.
-			/// </summary>
-			public override void OnClose()
-			{
-				//NOP
-			}
-		}
-
-		/// <summary>
-		/// Acquires the file lock for each write
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Opens the file once for each <see cref="AcquireLock"/>/<see cref="ReleaseLock"/> cycle, 
-		/// thus holding the lock for the minimal amount of time. This method of locking
-		/// is considerably slower than <see cref="FileAppender.ExclusiveLock"/> but allows 
-		/// other processes to move/delete the log file whilst logging continues.
-		/// </para>
-		/// </remarks>
-		public class MinimalLock : LockingModelBase
-		{
-			private string m_filename;
-			private bool m_append;
-			private Stream m_stream = null;
-
-			/// <summary>
-			/// Prepares to open the file when the first message is logged.
-			/// </summary>
-			/// <param name="filename">The filename to use</param>
-			/// <param name="append">Whether to append to the file, or overwrite</param>
-			/// <param name="encoding">The encoding to use</param>
-			/// <remarks>
-			/// <para>
-			/// Open the file specified and prepare for logging. 
-			/// No writes will be made until <see cref="AcquireLock"/> is called.
-			/// Must be called before any calls to <see cref="AcquireLock"/>,
-			/// <see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
-			/// </para>
-			/// </remarks>
-			public override void OpenFile(string filename, bool append, Encoding encoding)
-			{
-				m_filename = filename;
-				m_append = append;
-			}
-
-			/// <summary>
-			/// Close the file
-			/// </summary>
-			/// <remarks>
-			/// <para>
-			/// Close the file. No further writes will be made.
-			/// </para>
-			/// </remarks>
-			public override void CloseFile()
-			{
-				// NOP
-			}
-
-			/// <summary>
-			/// Acquire the lock on the file
-			/// </summary>
-			/// <returns>A stream that is ready to be written to.</returns>
-			/// <remarks>
-			/// <para>
-			/// Acquire the lock on the file in preparation for writing to it. 
-			/// Return a stream pointing to the file. <see cref="ReleaseLock"/>
-			/// must be called to release the lock on the output file.
-			/// </para>
-			/// </remarks>
-			public override Stream AcquireLock()
-			{
-				if (m_stream == null)
-				{
-					try
-					{
-						m_stream = CreateStream(m_filename, m_append, FileShare.Read);
-						m_append = true;
-					}
-					catch (Exception e1)
-					{
-						CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + m_filename + ". " + e1.Message);
-					}
-				}
-				return m_stream;
-			}
-
-			/// <summary>
-			/// Release the lock on the file
-			/// </summary>
-			/// <remarks>
-			/// <para>
-			/// Release the lock on the file. No further writes will be made to the 
-			/// stream until <see cref="AcquireLock"/> is called again.
-			/// </para>
-			/// </remarks>
-			public override void ReleaseLock()
-			{
-				CloseStream(m_stream);
-				m_stream = null;
-			}
-
-			/// <summary>
-			/// Initializes all resources used by this locking model.
-			/// </summary>
-			public override void ActivateOptions()
-			{
-				//NOP
-			}
-
-			/// <summary>
-			/// Disposes all resources that were initialized by this locking model.
-			/// </summary>
-			public override void OnClose()
-			{
-				//NOP
-			}
-		}
-
-#if !NETCF
-		/// <summary>
-		/// Provides cross-process file locking.
-		/// </summary>
-		/// <author>Ron Grabowski</author>
-		/// <author>Steve Wranovsky</author>
-		public class InterProcessLock : LockingModelBase
-		{
-			private Mutex m_mutex = null;
-			private Stream m_stream = null;
-			private int m_recursiveWatch = 0;
-
-			/// <summary>
-			/// Open the file specified and prepare for logging.
-			/// </summary>
-			/// <param name="filename">The filename to use</param>
-			/// <param name="append">Whether to append to the file, or overwrite</param>
-			/// <param name="encoding">The encoding to use</param>
-			/// <remarks>
-			/// <para>
-			/// Open the file specified and prepare for logging. 
-			/// No writes will be made until <see cref="AcquireLock"/> is called.
-			/// Must be called before any calls to <see cref="AcquireLock"/>,
-			/// -<see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
-			/// </para>
-			/// </remarks>
-#if NET_4_0 || MONO_4_0
-			[System.Security.SecuritySafeCritical]
-#endif
-			public override void OpenFile(string filename, bool append, Encoding encoding)
-			{
-				try
-				{
-					m_stream = CreateStream(filename, append, FileShare.ReadWrite);
-				}
-				catch (Exception e1)
-				{
-					CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + filename + ". " + e1.Message);
-				}
-			}
-
-			/// <summary>
-			/// Close the file
-			/// </summary>
-			/// <remarks>
-			/// <para>
-			/// Close the file. No further writes will be made.
-			/// </para>
-			/// </remarks>
-			public override void CloseFile()
-			{
-				try
-				{
-					CloseStream(m_stream);
-					m_stream = null;
-				}
-				finally
-				{
-					ReleaseLock();
-				}
-			}
-
-			/// <summary>
-			/// Acquire the lock on the file
-			/// </summary>
-			/// <returns>A stream that is ready to be written to.</returns>
-			/// <remarks>
-			/// <para>
-			/// Does nothing. The lock is already taken
-			/// </para>
-			/// </remarks>
-			public override Stream AcquireLock()
-			{
-				if (m_mutex != null)
-				{
-					// TODO: add timeout?
-					m_mutex.WaitOne();
-
-					// increment recursive watch
-					m_recursiveWatch++;
-
-					// should always be true (and fast) for FileStream
-					if (m_stream != null)
-					{
-						if (m_stream.CanSeek)
-						{
-							m_stream.Seek(0, SeekOrigin.End);
-						}
-					}
-					else
-					{
-						// this can happen when the file appender cannot open a file for writing
-					}
-				}
-				else
-				{
-					CurrentAppender.ErrorHandler.Error("Programming error, no mutex available to acquire lock! From here on things will be dangerous!");
-				}
-				return m_stream;
-			}
-
-			/// <summary>
-			/// Releases the lock and allows others to acquire a lock.
-			/// </summary>
-			public override void ReleaseLock()
-			{
-				if (m_mutex != null)
-				{
-					if (m_recursiveWatch > 0)
-					{
-						m_recursiveWatch--;
-						m_mutex.ReleaseMutex();
-					}
-				}
-				else
-				{
-					CurrentAppender.ErrorHandler.Error("Programming error, no mutex available to release the lock!");
-				}
-			}
-
-			/// <summary>
-			/// Initializes all resources used by this locking model.
-			/// </summary>
-			public override void ActivateOptions()
-			{
-				if (m_mutex == null)
-				{
-					string mutexFriendlyFilename = CurrentAppender.File
-							.Replace("\\", "_")
-							.Replace(":", "_")
-							.Replace("/", "_");
-
-					m_mutex = new Mutex(false, mutexFriendlyFilename);
-				}
-				else
-				{
-					CurrentAppender.ErrorHandler.Error("Programming error, mutex already initialized!");
-				}
-			}
-
-			/// <summary>
-			/// Disposes all resources that were initialized by this locking model.
-			/// </summary>
-			public override void OnClose()
-			{
-				if (m_mutex != null)
-				{
-					m_mutex.Close();
-					m_mutex = null;
-				}
-				else
-				{
-					CurrentAppender.ErrorHandler.Error("Programming error, mutex not initialized!");
-				}
-			}
-		}
-#endif
-
-		#endregion Locking Models
-
-		#region Public Instance Constructors
-
-		/// <summary>
-		/// Default constructor
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Default constructor
-		/// </para>
-		/// </remarks>
-		public FileAppender()
-		{
-		}
-
-		/// <summary>
-		/// Construct a new appender using the layout, file and append mode.
-		/// </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>
-		/// <param name="append">flag to indicate if the file should be appended to</param>
-		/// <remarks>
-		/// <para>
-		/// Obsolete constructor.
-		/// </para>
-		/// </remarks>
-		[Obsolete("Instead use the default constructor and set the Layout, File & AppendToFile properties")]
-		public FileAppender(ILayout layout, string filename, bool append)
-		{
-			Layout = layout;
-			File = filename;
-			AppendToFile = append;
-			ActivateOptions();
-		}
-
-		/// <summary>
-		/// Construct a new appender using the layout and file specified.
-		/// The file will be appended to.
-		/// </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>
-		/// <remarks>
-		/// <para>
-		/// Obsolete constructor.
-		/// </para>
-		/// </remarks>
-		[Obsolete("Instead use the default constructor and set the Layout & File properties")]
-		public FileAppender(ILayout layout, string filename)
-			: this(layout, filename, true)
-		{
-		}
-
-		#endregion Public Instance Constructors
-
-		#region Public Instance Properties
-
-		/// <summary>
-		/// Gets or sets the path to the file that logging will be written to.
-		/// </summary>
-		/// <value>
-		/// The path to the file that logging will be written to.
-		/// </value>
-		/// <remarks>
-		/// <para>
-		/// If the path is relative it is taken as relative from 
-		/// the application base directory.
-		/// </para>
-		/// </remarks>
-		virtual public string File
-		{
-			get { return m_fileName; }
-			set { m_fileName = value; }
-		}
-
-		/// <summary>
-		/// Gets or sets a flag that indicates whether the file should be
-		/// appended to or overwritten.
-		/// </summary>
-		/// <value>
-		/// Indicates whether the file should be appended to or overwritten.
-		/// </value>
-		/// <remarks>
-		/// <para>
-		/// If the value is set to false then the file will be overwritten, if 
-		/// it is set to true then the file will be appended to.
-		/// </para>
-		/// The default value is true.
-		/// </remarks>
-		public bool AppendToFile
-		{
-			get { return m_appendToFile; }
-			set { m_appendToFile = value; }
-		}
-
-		/// <summary>
-		/// Gets or sets <see cref="Encoding"/> used to write to the file.
-		/// </summary>
-		/// <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; }
-			set { m_encoding = value; }
-		}
-
-		/// <summary>
-		/// Gets or sets the <see cref="SecurityContext"/> used to write to the file.
-		/// </summary>
-		/// <value>
-		/// The <see cref="SecurityContext"/> used to write to the file.
-		/// </value>
-		/// <remarks>
-		/// <para>
-		/// Unless a <see cref="SecurityContext"/> specified here for this appender
-		/// the <see cref="SecurityContextProvider.DefaultProvider"/> is queried for the
-		/// security context to use. The default behavior is to use the security context
-		/// of the current thread.
-		/// </para>
-		/// </remarks>
-		public SecurityContext SecurityContext
-		{
-			get { return m_securityContext; }
-			set { m_securityContext = value; }
-		}
-
-#if NETCF
-		/// <summary>
-		/// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
-		/// </summary>
-		/// <value>
-		/// The <see cref="FileAppender.LockingModel"/> used to lock the file.
-		/// </value>
-		/// <remarks>
-		/// <para>
-		/// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
-		/// </para>
-		/// <para>
-        /// There are two built in locking models, <see cref="FileAppender.ExclusiveLock"/> and <see cref="FileAppender.MinimalLock"/>.
-		/// The first locks the file from the start of logging to the end, the 
-		/// second locks only for the minimal amount of time when logging each message
-        /// and the last synchronizes processes using a named system wide Mutex.
-		/// </para>
-		/// <para>
-		/// The default locking model is the <see cref="FileAppender.ExclusiveLock"/>.
-		/// </para>
-		/// </remarks>
-#else
-		/// <summary>
-		/// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
-		/// </summary>
-		/// <value>
-		/// The <see cref="FileAppender.LockingModel"/> used to lock the file.
-		/// </value>
-		/// <remarks>
-		/// <para>
-		/// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
-		/// </para>
-		/// <para>
-		/// There are three built in locking models, <see cref="FileAppender.ExclusiveLock"/>, <see cref="FileAppender.MinimalLock"/> and <see cref="FileAppender.InterProcessLock"/> .
-		/// The first locks the file from the start of logging to the end, the 
-		/// second locks only for the minimal amount of time when logging each message
-		/// and the last synchronizes processes using a named system wide Mutex.
-		/// </para>
-		/// <para>
-		/// The default locking model is the <see cref="FileAppender.ExclusiveLock"/>.
-		/// </para>
-		/// </remarks>
-#endif
-		public FileAppender.LockingModelBase LockingModel
-		{
-			get { return m_lockingModel; }
-			set { m_lockingModel = value; }
-		}
-
-		#endregion Public Instance Properties
-
-		#region Override implementation of AppenderSkeleton
-
-		/// <summary>
-		/// Activate the options on the file appender. 
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// This is part of the <see cref="IOptionHandler"/> delayed object
-		/// activation scheme. The <see cref="ActivateOptions"/> method must 
-		/// be called on this object after the configuration properties have
-		/// been set. Until <see cref="ActivateOptions"/> is called this
-		/// object is in an undefined state and must not be used. 
-		/// </para>
-		/// <para>
-		/// If any of the configuration properties are modified then 
-		/// <see cref="ActivateOptions"/> must be called again.
-		/// </para>
-		/// <para>
-		/// This will cause the file to be opened.
-		/// </para>
-		/// </remarks>
-		override public void ActivateOptions()
-		{
-			base.ActivateOptions();
-
-			if (m_securityContext == null)
-			{
-				m_securityContext = SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
-			}
-
-			if (m_lockingModel == null)
-			{
-				m_lockingModel = new FileAppender.ExclusiveLock();
-			}
-
-			m_lockingModel.CurrentAppender = this;
-			m_lockingModel.ActivateOptions();
-
-			if (m_fileName != null)
-			{
-				using (SecurityContext.Impersonate(this))
-				{
-					m_fileName = ConvertToFullPath(m_fileName.Trim());
-				}
-				SafeOpenFile(m_fileName, m_appendToFile);
-			}
-			else
-			{
-				LogLog.Warn(declaringType, "FileAppender: File option not set for appender [" + Name + "].");
-				LogLog.Warn(declaringType, "FileAppender: Are you using FileAppender instead of ConsoleAppender?");
-			}
-		}
-
-		#endregion Override implementation of AppenderSkeleton
-
-		#region Override implementation of TextWriterAppender
-
-		/// <summary>
-		/// Closes any previously opened file and calls the parent's <see cref="TextWriterAppender.Reset"/>.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Resets the filename and the file stream.
-		/// </para>
-		/// </remarks>
-		override protected void Reset()
-		{
-			base.Reset();
-			m_fileName = null;
-		}
-
-		/// <summary>
-		/// Close this appender instance. The underlying stream or writer is also closed.
-		/// </summary>
-		override protected void OnClose()
-		{
-			base.OnClose();
-			m_lockingModel.OnClose();
-		}
-
-		/// <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);
-		}
-
-		/// <summary>
-		/// This method is called by the <see cref="M:AppenderSkeleton.DoAppend(LoggingEvent)"/>
-		/// method. 
-		/// </summary>
-		/// <param name="loggingEvent">The event to log.</param>
-		/// <remarks>
-		/// <para>
-		/// Writes a log statement to the output stream if the output stream exists 
-		/// and is writable.  
-		/// </para>
-		/// <para>
-		/// The format of the output will depend on the appender's layout.
-		/// </para>
-		/// </remarks>
-		override protected void Append(LoggingEvent loggingEvent)
-		{
-			if (m_stream.AcquireLock())
-			{
-				try
-				{
-					base.Append(loggingEvent);
-				}
-				finally
-				{
-					m_stream.ReleaseLock();
-				}
-			}
-		}
-
-		/// <summary>
-		/// This method is called by the <see cref="M:AppenderSkeleton.DoAppend(LoggingEvent[])"/>
-		/// method. 
-		/// </summary>
-		/// <param name="loggingEvents">The array of events to log.</param>
-		/// <remarks>
-		/// <para>
-		/// Acquires the output file locks once before writing all the events to
-		/// the stream.
-		/// </para>
-		/// </remarks>
-		override protected void Append(LoggingEvent[] loggingEvents)
-		{
-			if (m_stream.AcquireLock())
-			{
-				try
-				{
-					base.Append(loggingEvents);
-				}
-				finally
-				{
-					m_stream.ReleaseLock();
-				}
-			}
-		}
-
-		/// <summary>
-		/// Writes a footer as produced by the embedded layout's <see cref="ILayout.Footer"/> property.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Writes a footer as produced by the embedded layout's <see cref="ILayout.Footer"/> property.
-		/// </para>
-		/// </remarks>
-		protected override void WriteFooter()
-		{
-			if (m_stream != null)
-			{
-				//WriteFooter can be called even before a file is opened
-				m_stream.AcquireLock();
-				try
-				{
-					base.WriteFooter();
-				}
-				finally
-				{
-					m_stream.ReleaseLock();
-				}
-			}
-		}
-
-		/// <summary>
-		/// Writes a header produced by the embedded layout's <see cref="ILayout.Header"/> property.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Writes a header produced by the embedded layout's <see cref="ILayout.Header"/> property.
-		/// </para>
-		/// </remarks>
-		protected override void WriteHeader()
-		{
-			if (m_stream != null)
-			{
-				if (m_stream.AcquireLock())
-				{
-					try
-					{
-						base.WriteHeader();
-					}
-					finally
-					{
-						m_stream.ReleaseLock();
-					}
-				}
-			}
-		}
-
-		/// <summary>
-		/// Closes the underlying <see cref="TextWriter"/>.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Closes the underlying <see cref="TextWriter"/>.
-		/// </para>
-		/// </remarks>
-		protected override void CloseWriter()
-		{
-			if (m_stream != null)
-			{
-				m_stream.AcquireLock();
-				try
-				{
-					base.CloseWriter();
-				}
-				finally
-				{
-					m_stream.ReleaseLock();
-				}
-			}
-		}
-
-		#endregion Override implementation of TextWriterAppender
-
-		#region Public Instance Methods
-
-		/// <summary>
-		/// Closes the previously opened file.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Writes the <see cref="ILayout.Footer"/> to the file and then
-		/// closes the file.
-		/// </para>
-		/// </remarks>
-		protected void CloseFile()
-		{
-			WriteFooterAndCloseWriter();
-		}
-
-		#endregion Public Instance Methods
-
-		#region Protected Instance Methods
-
-		/// <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. Must be a fully qualified path.</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. Must be a fully qualified path.</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>
-		/// </remarks>
-		virtual protected void OpenFile(string fileName, bool append)
-		{
-			if (LogLog.IsErrorEnabled)
-			{
-				// Internal check that the fileName passed in is a rooted path
-				bool isPathRooted = false;
-				using (SecurityContext.Impersonate(this))
-				{
-					isPathRooted = Path.IsPathRooted(fileName);
-				}
-				if (!isPathRooted)
-				{
-					LogLog.Error(declaringType, "INTERNAL ERROR. OpenFile(" + fileName + "): File name is not fully qualified.");
-				}
-			}
-
-			lock (this)
-			{
-				Reset();
-
-				LogLog.Debug(declaringType, "Opening file for writing [" + fileName + "] append [" + append + "]");
-
-				// Save these for later, allowing retries if file open fails
-				m_fileName = fileName;
-				m_appendToFile = append;
-
-				LockingModel.CurrentAppender = this;
-				LockingModel.OpenFile(fileName, append, m_encoding);
-				m_stream = new LockingStream(LockingModel);
-
-				if (m_stream != null)
-				{
-					m_stream.AcquireLock();
-					try
-					{
-						SetQWForFiles(new StreamWriter(m_stream, m_encoding));
-					}
-					finally
-					{
-						m_stream.ReleaseLock();
-					}
-				}
-
-				WriteHeader();
-			}
-		}
-
-		/// <summary>
-		/// Sets the quiet writer used for file output
-		/// </summary>
-		/// <param name="fileStream">the file stream that has been opened for writing</param>
-		/// <remarks>
-		/// <para>
-		/// This implementation of <see cref="M:SetQWForFiles(Stream)"/> creates a <see cref="StreamWriter"/>
-		/// over the <paramref name="fileStream"/> and passes it to the 
-		/// <see cref="M:SetQWForFiles(TextWriter)"/> method.
-		/// </para>
-		/// <para>
-		/// This method can be overridden by sub classes that want to wrap the
-		/// <see cref="Stream"/> in some way, for example to encrypt the output
-		/// data using a <c>System.Security.Cryptography.CryptoStream</c>.
-		/// </para>
-		/// </remarks>
-		virtual protected void SetQWForFiles(Stream fileStream)
-		{
-			SetQWForFiles(new StreamWriter(fileStream, m_encoding));
-		}
-
-		/// <summary>
-		/// Sets the quiet writer being used.
-		/// </summary>
-		/// <param name="writer">the writer over the file stream that has been opened for writing</param>
-		/// <remarks>
-		/// <para>
-		/// This method can be overridden by sub classes that want to
-		/// wrap the <see cref="TextWriter"/> in some way.
-		/// </para>
-		/// </remarks>
-		virtual protected void SetQWForFiles(TextWriter writer)
-		{
-			QuietWriter = new QuietTextWriter(writer, ErrorHandler);
-		}
-
-		#endregion Protected Instance Methods
-
-		#region Protected Static Methods
-
-		/// <summary>
-		/// Convert a path into a fully qualified path.
-		/// </summary>
-		/// <param name="path">The path to convert.</param>
-		/// <returns>The fully qualified path.</returns>
-		/// <remarks>
-		/// <para>
-		/// Converts the path specified to a fully
-		/// qualified path. If the path is relative it is
-		/// taken as relative from the application base 
-		/// directory.
-		/// </para>
-		/// </remarks>
-		protected static string ConvertToFullPath(string path)
-		{
-			return SystemInfo.ConvertToFullPath(path);
-		}
-
-		#endregion Protected Static Methods
-
-		#region Private Instance Fields
-
-		/// <summary>
-		/// Flag to indicate if we should append to the file
-		/// or overwrite the file. The default is to append.
-		/// </summary>
-		private bool m_appendToFile = true;
-
-		/// <summary>
-		/// The name of the log file.
-		/// </summary>
-		private string m_fileName = null;
-
-		/// <summary>
-		/// The encoding to use for the file stream.
-		/// </summary>
-		private Encoding m_encoding = Encoding.Default;
-
-		/// <summary>
-		/// The security context to use for privileged calls
-		/// </summary>
-		private SecurityContext m_securityContext;
-
-		/// <summary>
-		/// The stream to log to. Has added locking semantics
-		/// </summary>
-		private FileAppender.LockingStream m_stream = null;
-
-		/// <summary>
-		/// The locking model to use
-		/// </summary>
-		private FileAppender.LockingModelBase m_lockingModel = new FileAppender.ExclusiveLock();
-
-		#endregion Private Instance Fields
-
-		#region Private Static Fields
-
-		/// <summary>
-		/// The fully qualified type of the FileAppender class.
-		/// </summary>
-		/// <remarks>
-		/// Used by the internal logger to record the Type of the
-		/// log message.
-		/// </remarks>
-		private readonly static Type declaringType = typeof(FileAppender);
-
-		#endregion Private Static Fields
-	}
-}
+#region Apache License
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more 
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership. 
+// The ASF licenses this file to you under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with 
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#endregion
+
+using System;
+using System.IO;
+using System.Text;
+using System.Threading;
+using log4net.Util;
+using log4net.Layout;
+using log4net.Core;
+
+namespace log4net.Appender
+{
+#if !NETCF
+	/// <summary>
+	/// Appends logging events to a file.
+	/// </summary>
+	/// <remarks>
+	/// <para>
+	/// 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 
+	/// 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>
+	/// <para>
+	/// The <see cref="FileAppender"/> supports pluggable file locking models via
+	/// the <see cref="LockingModel"/> property.
+	/// The default behavior, implemented by <see cref="FileAppender.ExclusiveLock"/> 
+	/// is to obtain an exclusive write lock on the file until this appender is closed.
+	/// The alternative models only hold a
+	/// write lock while the appender is writing a logging event (<see cref="FileAppender.MinimalLock"/>)
+	/// or synchronize by using a named system wide Mutex (<see cref="FileAppender.InterProcessLock"/>).
+	/// </para>
+	/// <para>
+	/// All locking strategies have issues and you should seriously consider using a different strategy that
+	/// avoids having multiple processes logging to the same file.
+	/// </para>
+	/// </remarks>
+	/// <author>Nicko Cadell</author>
+	/// <author>Gert Driesen</author>
+	/// <author>Rodrigo B. de Oliveira</author>
+	/// <author>Douglas de la Torre</author>
+	/// <author>Niall Daley</author>
+#else
+	/// <summary>
+	/// Appends logging events to a file.
+	/// </summary>
+	/// <remarks>
+	/// <para>
+	/// 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 
+	/// 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>
+	/// <para>
+	/// The <see cref="FileAppender"/> supports pluggable file locking models via
+	/// the <see cref="LockingModel"/> property.
+	/// The default behavior, implemented by <see cref="FileAppender.ExclusiveLock"/> 
+	/// is to obtain an exclusive write lock on the file until this appender is closed.
+	/// The alternative model only holds a
+    /// write lock while the appender is writing a logging event (<see cref="FileAppender.MinimalLock"/>).
+	/// </para>
+    /// <para>
+    /// All locking strategies have issues and you should seriously consider using a different strategy that
+    /// avoids having multiple processes logging to the same file.
+    /// </para>
+	/// </remarks>
+	/// <author>Nicko Cadell</author>
+	/// <author>Gert Driesen</author>
+	/// <author>Rodrigo B. de Oliveira</author>
+	/// <author>Douglas de la Torre</author>
+	/// <author>Niall Daley</author>
+#endif
+	public class FileAppender : TextWriterAppender
+	{
+		#region LockingStream Inner Class
+
+		/// <summary>
+		/// Write only <see cref="Stream"/> that uses the <see cref="LockingModelBase"/> 
+		/// to manage access to an underlying resource.
+		/// </summary>
+		private sealed class LockingStream : Stream, IDisposable
+		{
+			public sealed class LockStateException : LogException
+			{
+				public LockStateException(string message)
+					: base(message)
+				{
+				}
+			}
+
+			private Stream m_realStream = null;
+			private LockingModelBase m_lockingModel = null;
+#if !NETSTANDARD1_3 // only used in unavailable Stream overrides
+			private int m_readTotal = -1;
+#endif
+			private int m_lockLevel = 0;
+
+			public LockingStream(LockingModelBase locking)
+				: base()
+			{
+				if (locking == null)
+				{
+					throw new ArgumentException("Locking model may not be null", "locking");
+				}
+				m_lockingModel = locking;
+			}
+
+			#region Override Implementation of Stream
+
+#if NETSTANDARD1_3
+			protected override void Dispose(bool disposing)
+			{
+				m_lockingModel.CloseFile();
+				base.Dispose(disposing);
+			}
+#else
+			// Methods
+			public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+			{
+				AssertLocked();
+				IAsyncResult ret = m_realStream.BeginRead(buffer, offset, count, callback, state);
+				m_readTotal = EndRead(ret);
+				return ret;
+			}
+
+			/// <summary>
+			/// True asynchronous writes are not supported, the implementation forces a synchronous write.
+			/// </summary>
+			public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+			{
+				AssertLocked();
+				IAsyncResult ret = m_realStream.BeginWrite(buffer, offset, count, callback, state);
+				EndWrite(ret);
+				return ret;
+			}
+
+			public override void Close()
+			{
+				m_lockingModel.CloseFile();
+			}
+
+			public override int EndRead(IAsyncResult asyncResult)
+			{
+				AssertLocked();
+				return m_readTotal;
+			}
+			public override void EndWrite(IAsyncResult asyncResult)
+			{
+				//No-op, it has already been handled
+			}
+#endif
+
+			public override void Flush()
+			{
+				AssertLocked();
+				m_realStream.Flush();
+			}
+			public override int Read(byte[] buffer, int offset, int count)
+			{
+				return m_realStream.Read(buffer, offset, count);
+			}
+			public override int ReadByte()
+			{
+				return m_realStream.ReadByte();
+			}
+			public override long Seek(long offset, SeekOrigin origin)
+			{
+				AssertLocked();
+				return m_realStream.Seek(offset, origin);
+			}
+			public override void SetLength(long value)
+			{
+				AssertLocked();
+				m_realStream.SetLength(value);
+			}
+			void IDisposable.Dispose()
+			{
+#if NETSTANDARD1_3
+				Dispose(true);
+#else
+				Close();
+#endif
+			}
+			public override void Write(byte[] buffer, int offset, int count)
+			{
+				AssertLocked();
+				m_realStream.Write(buffer, offset, count);
+			}
+			public override void WriteByte(byte value)
+			{
+				AssertLocked();
+				m_realStream.WriteByte(value);
+			}
+
+			// Properties
+			public override bool CanRead
+			{
+				get { return false; }
+			}
+			public override bool CanSeek
+			{
+				get
+				{
+					AssertLocked();
+					return m_realStream.CanSeek;
+				}
+			}
+			public override bool CanWrite
+			{
+				get
+				{
+					AssertLocked();
+					return m_realStream.CanWrite;
+				}
+			}
+			public override long Length
+			{
+				get
+				{
+					AssertLocked();
+					return m_realStream.Length;
+				}
+			}
+			public override long Position
+			{
+				get
+				{
+					AssertLocked();
+					return m_realStream.Position;
+				}
+				set
+				{
+					AssertLocked();
+					m_realStream.Position = value;
+				}
+			}
+
+			#endregion Override Implementation of Stream
+
+			#region Locking Methods
+
+			private void AssertLocked()
+			{
+				if (m_realStream == null)
+				{
+					throw new LockStateException("The file is not currently locked");
+				}
+			}
+
+			public bool AcquireLock()
+			{
+				bool ret = false;
+				lock (this)
+				{
+					if (m_lockLevel == 0)
+					{
+						// If lock is already acquired, nop
+						m_realStream = m_lockingModel.AcquireLock();
+					}
+					if (m_realStream != null)
+					{
+						m_lockLevel++;
+						ret = true;
+					}
+				}
+				return ret;
+			}
+
+			public void ReleaseLock()
+			{
+				lock (this)
+				{
+					m_lockLevel--;
+					if (m_lockLevel == 0)
+					{
+						// If already unlocked, nop
+						m_lockingModel.ReleaseLock();
+						m_realStream = null;
+					}
+				}
+			}
+
+			#endregion Locking Methods
+		}
+
+		#endregion LockingStream Inner Class
+
+		#region Locking Models
+
+		/// <summary>
+		/// Locking model base class
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Base class for the locking models available to the <see cref="FileAppender"/> derived loggers.
+		/// </para>
+		/// </remarks>
+		public abstract class LockingModelBase
+		{
+			private FileAppender m_appender = null;
+
+			/// <summary>
+			/// Open the output file
+			/// </summary>
+			/// <param name="filename">The filename to use</param>
+			/// <param name="append">Whether to append to the file, or overwrite</param>
+			/// <param name="encoding">The encoding to use</param>
+			/// <remarks>
+			/// <para>
+			/// Open the file specified and prepare for logging. 
+			/// No writes will be made until <see cref="AcquireLock"/> is called.
+			/// Must be called before any calls to <see cref="AcquireLock"/>,
+			/// <see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
+			/// </para>
+			/// </remarks>
+			public abstract void OpenFile(string filename, bool append, Encoding encoding);
+
+			/// <summary>
+			/// Close the file
+			/// </summary>
+			/// <remarks>
+			/// <para>
+			/// Close the file. No further writes will be made.
+			/// </para>
+			/// </remarks>
+			public abstract void CloseFile();
+
+			/// <summary>
+			/// Initializes all resources used by this locking model.
+			/// </summary>
+			public abstract void ActivateOptions();
+
+			/// <summary>
+			/// Disposes all resources that were initialized by this locking model.
+			/// </summary>
+			public abstract void OnClose();
+
+			/// <summary>
+			/// Acquire the lock on the file
+			/// </summary>
+			/// <returns>A stream that is ready to be written to.</returns>
+			/// <remarks>
+			/// <para>
+			/// Acquire the lock on the file in preparation for writing to it. 
+			/// Return a stream pointing to the file. <see cref="ReleaseLock"/>
+			/// must be called to release the lock on the output file.
+			/// </para>
+			/// </remarks>
+			public abstract Stream AcquireLock();
+
+			/// <summary>
+			/// Release the lock on the file
+			/// </summary>
+			/// <remarks>
+			/// <para>
+			/// Release the lock on the file. No further writes will be made to the 
+			/// stream until <see cref="AcquireLock"/> is called again.
+			/// </para>
+			/// </remarks>
+			public abstract void ReleaseLock();
+
+			/// <summary>
+			/// Gets or sets the <see cref="FileAppender"/> for this LockingModel
+			/// </summary>
+			/// <value>
+			/// The <see cref="FileAppender"/> for this LockingModel
+			/// </value>
+			/// <remarks>
+			/// <para>
+			/// The file appender this locking model is attached to and working on
+			/// behalf of.
+			/// </para>
+			/// <para>
+			/// The file appender is used to locate the security context and the error handler to use.
+			/// </para>
+			/// <para>
+			/// The value of this property will be set before <see cref="OpenFile"/> is
+			/// called.
+			/// </para>
+			/// </remarks>
+			public FileAppender CurrentAppender
+			{
+				get { return m_appender; }
+				set { m_appender = value; }
+			}
+
+			/// <summary>
+			/// Helper method that creates a FileStream under CurrentAppender's SecurityContext.
+			/// </summary>
+			/// <remarks>
+			/// <para>
+			/// Typically called during OpenFile or AcquireLock. 
+			/// </para>
+			/// <para>
+			/// If the directory portion of the <paramref name="filename"/> does not exist, it is created
+			/// via Directory.CreateDirecctory.
+			/// </para>
+			/// </remarks>
+			/// <param name="filename"></param>
+			/// <param name="append"></param>
+			/// <param name="fileShare"></param>
+			/// <returns></returns>
+			protected Stream CreateStream(string filename, bool append, FileShare fileShare)
+			{
+				using (CurrentAppender.SecurityContext.Impersonate(this))
+				{
+					// Ensure that the directory structure exists
+					string directoryFullName = Path.GetDirectoryName(filename);
+
+					// Only create the directory if it does not exist
+					// doing this check here resolves some permissions failures
+					if (!Directory.Exists(directoryFullName))
+					{
+						Directory.CreateDirectory(directoryFullName);
+					}
+
+					FileMode fileOpenMode = append ? FileMode.Append : FileMode.Create;
+					return new FileStream(filename, fileOpenMode, FileAccess.Write, fileShare);
+				}
+			}
+
+			/// <summary>
+			/// Helper method to close <paramref name="stream"/> under CurrentAppender's SecurityContext.
+			/// </summary>
+			/// <remarks>
+			/// Does not set <paramref name="stream"/> to null.
+			/// </remarks>
+			/// <param name="stream"></param>
+			protected void CloseStream(Stream stream)
+			{
+				using (CurrentAppender.SecurityContext.Impersonate(this))
+				{
+					stream.Close();
+				}
+			}
+		}
+
+		/// <summary>
+		/// Hold an exclusive lock on the output file
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Open the file once for writing and hold it open until <see cref="CloseFile"/> is called. 
+		/// Maintains an exclusive lock on the file during this time.
+		/// </para>
+		/// </remarks>
+		public class ExclusiveLock : LockingModelBase
+		{
+			private Stream m_stream = null;
+
+			/// <summary>
+			/// Open the file specified and prepare for logging.
+			/// </summary>
+			/// <param name="filename">The filename to use</param>
+			/// <param name="append">Whether to append to the file, or overwrite</param>
+			/// <param name="encoding">The encoding to use</param>
+			/// <remarks>
+			/// <para>
+			/// Open the file specified and prepare for logging. 
+			/// No writes will be made until <see cref="AcquireLock"/> is called.
+			/// Must be called before any calls to <see cref="AcquireLock"/>,
+			/// <see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
+			/// </para>
+			/// </remarks>
+			public override void OpenFile(string filename, bool append, Encoding encoding)
+			{
+				try
+				{
+					m_stream = CreateStream(filename, append, FileShare.Read);
+				}
+				catch (Exception e1)
+				{
+					CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + filename + ". " + e1.Message);
+				}
+			}
+
+			/// <summary>
+			/// Close the file
+			/// </summary>
+			/// <remarks>
+			/// <para>
+			/// Close the file. No further writes will be made.
+			/// </para>
+			/// </remarks>
+			public override void CloseFile()
+			{
+				CloseStream(m_stream);
+				m_stream = null;
+			}
+
+			/// <summary>
+			/// Acquire the lock on the file
+			/// </summary>
+			/// <returns>A stream that is ready to be written to.</returns>
+			/// <remarks>
+			/// <para>
+			/// Does nothing. The lock is already taken
+			/// </para>
+			/// </remarks>
+			public override Stream AcquireLock()
+			{
+				return m_stream;
+			}
+
+			/// <summary>
+			/// Release the lock on the file
+			/// </summary>
+			/// <remarks>
+			/// <para>
+			/// Does nothing. The lock will be released when the file is closed.
+			/// </para>
+			/// </remarks>
+			public override void ReleaseLock()
+			{
+				//NOP
+			}
+
+			/// <summary>
+			/// Initializes all resources used by this locking model.
+			/// </summary>
+			public override void ActivateOptions()
+			{
+				//NOP
+			}
+
+			/// <summary>
+			/// Disposes all resources that were initialized by this locking model.
+			/// </summary>
+			public override void OnClose()
+			{
+				//NOP
+			}
+		}
+
+		/// <summary>
+		/// Acquires the file lock for each write
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Opens the file once for each <see cref="AcquireLock"/>/<see cref="ReleaseLock"/> cycle, 
+		/// thus holding the lock for the minimal amount of time. This method of locking
+		/// is considerably slower than <see cref="FileAppender.ExclusiveLock"/> but allows 
+		/// other processes to move/delete the log file whilst logging continues.
+		/// </para>
+		/// </remarks>
+		public class MinimalLock : LockingModelBase
+		{
+			private string m_filename;
+			private bool m_append;
+			private Stream m_stream = null;
+
+			/// <summary>
+			/// Prepares to open the file when the first message is logged.
+			/// </summary>
+			/// <param name="filename">The filename to use</param>
+			/// <param name="append">Whether to append to the file, or overwrite</param>
+			/// <param name="encoding">The encoding to use</param>
+			/// <remarks>
+			/// <para>
+			/// Open the file specified and prepare for logging. 
+			/// No writes will be made until <see cref="AcquireLock"/> is called.
+			/// Must be called before any calls to <see cref="AcquireLock"/>,
+			/// <see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
+			/// </para>
+			/// </remarks>
+			public override void OpenFile(string filename, bool append, Encoding encoding)
+			{
+				m_filename = filename;
+				m_append = append;
+			}
+
+			/// <summary>
+			/// Close the file
+			/// </summary>
+			/// <remarks>
+			/// <para>
+			/// Close the file. No further writes will be made.
+			/// </para>
+			/// </remarks>
+			public override void CloseFile()
+			{
+				// NOP
+			}
+
+			/// <summary>
+			/// Acquire the lock on the file
+			/// </summary>
+			/// <returns>A stream that is ready to be written to.</returns>
+			/// <remarks>
+			/// <para>
+			/// Acquire the lock on the file in preparation for writing to it. 
+			/// Return a stream pointing to the file. <see cref="ReleaseLock"/>
+			/// must be called to release the lock on the output file.
+			/// </para>
+			/// </remarks>
+			public override Stream AcquireLock()
+			{
+				if (m_stream == null)
+				{
+					try
+					{
+						m_stream = CreateStream(m_filename, m_append, FileShare.Read);
+						m_append = true;
+					}
+					catch (Exception e1)
+					{
+						CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + m_filename + ". " + e1.Message);
+					}
+				}
+				return m_stream;
+			}
+
+			/// <summary>
+			/// Release the lock on the file
+			/// </summary>
+			/// <remarks>
+			/// <para>
+			/// Release the lock on the file. No further writes will be made to the 
+			/// stream until <see cref="AcquireLock"/> is called again.
+			/// </para>
+			/// </remarks>
+			public override void ReleaseLock()
+			{
+				CloseStream(m_stream);
+				m_stream = null;
+			}
+
+			/// <summary>
+			/// Initializes all resources used by this locking model.
+			/// </summary>
+			public override void ActivateOptions()
+			{
+				//NOP
+			}
+
+			/// <summary>
+			/// Disposes all resources that were initialized by this locking model.
+			/// </summary>
+			public override void OnClose()
+			{
+				//NOP
+			}
+		}
+
+#if !NETCF
+		/// <summary>
+		/// Provides cross-process file locking.
+		/// </summary>
+		/// <author>Ron Grabowski</author>
+		/// <author>Steve Wranovsky</author>
+		public class InterProcessLock : LockingModelBase
+		{
+			private Mutex m_mutex = null;
+			private Stream m_stream = null;
+			private int m_recursiveWatch = 0;
+
+			/// <summary>
+			/// Open the file specified and prepare for logging.
+			/// </summary>
+			/// <param name="filename">The filename to use</param>
+			/// <param name="append">Whether to append to the file, or overwrite</param>
+			/// <param name="encoding">The encoding to use</param>
+			/// <remarks>
+			/// <para>
+			/// Open the file specified and prepare for logging. 
+			/// No writes will be made until <see cref="AcquireLock"/> is called.
+			/// Must be called before any calls to <see cref="AcquireLock"/>,
+			/// -<see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
+			/// </para>
+			/// </remarks>
+#if NET_4_0 || MONO_4_0 || NETSTANDARD1_3
+			[System.Security.SecuritySafeCritical]
+#endif
+			public override void OpenFile(string filename, bool append, Encoding encoding)
+			{
+				try
+				{
+					m_stream = CreateStream(filename, append, FileShare.ReadWrite);
+				}
+				catch (Exception e1)
+				{
+					CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + filename + ". " + e1.Message);
+				}
+			}
+
+			/// <summary>
+			/// Close the file
+			/// </summary>
+			/// <remarks>
+			/// <para>
+			/// Close the file. No further writes will be made.
+			/// </para>
+			/// </remarks>
+			public override void CloseFile()
+			{
+				try
+				{
+					CloseStream(m_stream);
+					m_stream = null;
+				}
+				finally
+				{
+					ReleaseLock();
+				}
+			}
+
+			/// <summary>
+			/// Acquire the lock on the file
+			/// </summary>
+			/// <returns>A stream that is ready to be written to.</returns>
+			/// <remarks>
+			/// <para>
+			/// Does nothing. The lock is already taken
+			/// </para>
+			/// </remarks>
+			public override Stream AcquireLock()
+			{
+				if (m_mutex != null)
+				{
+					// TODO: add timeout?
+					m_mutex.WaitOne();
+
+					// increment recursive watch
+					m_recursiveWatch++;
+
+					// should always be true (and fast) for FileStream
+					if (m_stream != null)
+					{
+						if (m_stream.CanSeek)
+						{
+							m_stream.Seek(0, SeekOrigin.End);
+						}
+					}
+					else
+					{
+						// this can happen when the file appender cannot open a file for writing
+					}
+				}
+				else
+				{
+					CurrentAppender.ErrorHandler.Error("Programming error, no mutex available to acquire lock! From here on things will be dangerous!");
+				}
+				return m_stream;
+			}
+
+			/// <summary>
+			/// Releases the lock and allows others to acquire a lock.
+			/// </summary>
+			public override void ReleaseLock()
+			{
+				if (m_mutex != null)
+				{
+					if (m_recursiveWatch > 0)
+					{
+						m_recursiveWatch--;
+						m_mutex.ReleaseMutex();
+					}
+				}
+				else
+				{
+					CurrentAppender.ErrorHandler.Error("Programming error, no mutex available to release the lock!");
+				}
+			}
+
+			/// <summary>
+			/// Initializes all resources used by this locking model.
+			/// </summary>
+			public override void ActivateOptions()
+			{
+				if (m_mutex == null)
+				{
+					string mutexFriendlyFilename = CurrentAppender.File
+							.Replace("\\", "_")
+							.Replace(":", "_")
+							.Replace("/", "_");
+
+					m_mutex = new Mutex(false, mutexFriendlyFilename);
+				}
+				else
+				{
+					CurrentAppender.ErrorHandler.Error("Programming error, mutex already initialized!");
+				}
+			}
+
+			/// <summary>
+			/// Disposes all resources that were initialized by this locking model.
+			/// </summary>
+			public override void OnClose()
+			{
+				if (m_mutex != null)
+				{
+					m_mutex.Dispose();
+					m_mutex = null;
+				}
+				else
+				{
+					CurrentAppender.ErrorHandler.Error("Programming error, mutex not initialized!");
+				}
+			}
+		}
+#endif
+
+		#endregion Locking Models
+
+		#region Public Instance Constructors
+
+		/// <summary>
+		/// Default constructor
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Default constructor
+		/// </para>
+		/// </remarks>
+		public FileAppender()
+		{
+		}
+
+		/// <summary>
+		/// Construct a new appender using the layout, file and append mode.
+		/// </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>
+		/// <param name="append">flag to indicate if the file should be appended to</param>
+		/// <remarks>
+		/// <para>
+		/// Obsolete constructor.
+		/// </para>
+		/// </remarks>
+		[Obsolete("Instead use the default constructor and set the Layout, File & AppendToFile properties")]
+		public FileAppender(ILayout layout, string filename, bool append)
+		{
+			Layout = layout;
+			File = filename;
+			AppendToFile = append;
+			ActivateOptions();
+		}
+
+		/// <summary>
+		/// Construct a new appender using the layout and file specified.
+		/// The file will be appended to.
+		/// </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>
+		/// <remarks>
+		/// <para>
+		/// Obsolete constructor.
+		/// </para>
+		/// </remarks>
+		[Obsolete("Instead use the default constructor and set the Layout & File properties")]
+		public FileAppender(ILayout layout, string filename)
+			: this(layout, filename, true)
+		{
+		}
+
+		#endregion Public Instance Constructors
+
+		#region Public Instance Properties
+
+		/// <summary>
+		/// Gets or sets the path to the file that logging will be written to.
+		/// </summary>
+		/// <value>
+		/// The path to the file that logging will be written to.
+		/// </value>
+		/// <remarks>
+		/// <para>
+		/// If the path is relative it is taken as relative from 
+		/// the application base directory.
+		/// </para>
+		/// </remarks>
+		virtual public string File
+		{
+			get { return m_fileName; }
+			set { m_fileName = value; }
+		}
+
+		/// <summary>
+		/// Gets or sets a flag that indicates whether the file should be
+		/// appended to or overwritten.
+		/// </summary>
+		/// <value>
+		/// Indicates whether the file should be appended to or overwritten.
+		/// </value>
+		/// <remarks>
+		/// <para>
+		/// If the value is set to false then the file will be overwritten, if 
+		/// it is set to true then the file will be appended to.
+		/// </para>
+		/// The default value is true.
+		/// </remarks>
+		public bool AppendToFile
+		{
+			get { return m_appendToFile; }
+			set { m_appendToFile = value; }
+		}
+
+		/// <summary>
+		/// Gets or sets <see cref="Encoding"/> used to write to the file.
+		/// </summary>
+		/// <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; }
+			set { m_encoding = value; }
+		}
+
+		/// <summary>
+		/// Gets or sets the <see cref="SecurityContext"/> used to write to the file.
+		/// </summary>
+		/// <value>
+		/// The <see cref="SecurityContext"/> used to write to the file.
+		/// </value>
+		/// <remarks>
+		/// <para>
+		/// Unless a <see cref="SecurityContext"/> specified here for this appender
+		/// the <see cref="SecurityContextProvider.DefaultProvider"/> is queried for the
+		/// security context to use. The default behavior is to use the security context
+		/// of the current thread.
+		/// </para>
+		/// </remarks>
+		public SecurityContext SecurityContext
+		{
+			get { return m_securityContext; }
+			set { m_securityContext = value; }
+		}
+
+#if NETCF
+		/// <summary>
+		/// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
+		/// </summary>
+		/// <value>
+		/// The <see cref="FileAppender.LockingModel"/> used to lock the file.
+		/// </value>
+		/// <remarks>
+		/// <para>
+		/// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
+		/// </para>
+		/// <para>
+        /// There are two built in locking models, <see cref="FileAppender.ExclusiveLock"/> and <see cref="FileAppender.MinimalLock"/>.
+		/// The first locks the file from the start of logging to the end, the 
+		/// second locks only for the minimal amount of time when logging each message
+        /// and the last synchronizes processes using a named system wide Mutex.
+		/// </para>
+		/// <para>
+		/// The default locking model is the <see cref="FileAppender.ExclusiveLock"/>.
+		/// </para>
+		/// </remarks>
+#else
+		/// <summary>
+		/// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
+		/// </summary>
+		/// <value>
+		/// The <see cref="FileAppender.LockingModel"/> used to lock the file.
+		/// </value>
+		/// <remarks>
+		/// <para>
+		/// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
+		/// </para>
+		/// <para>
+		/// There are three built in locking models, <see cref="FileAppender.ExclusiveLock"/>, <see cref="FileAppender.MinimalLock"/> and <see cref="FileAppender.InterProcessLock"/> .
+		/// The first locks the file from the start of logging to the end, the 
+		/// second locks only for the minimal amount of time when logging each message
+		/// and the last synchronizes processes using a named system wide Mutex.
+		/// </para>
+		/// <para>
+		/// The default locking model is the <see cref="FileAppender.ExclusiveLock"/>.
+		/// </para>
+		/// </remarks>
+#endif
+		public FileAppender.LockingModelBase LockingModel
+		{
+			get { return m_lockingModel; }
+			set { m_lockingModel = value; }
+		}
+
+		#endregion Public Instance Properties
+
+		#region Override implementation of AppenderSkeleton
+
+		/// <summary>
+		/// Activate the options on the file appender. 
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// This is part of the <see cref="IOptionHandler"/> delayed object
+		/// activation scheme. The <see cref="ActivateOptions"/> method must 
+		/// be called on this object after the configuration properties have
+		/// been set. Until <see cref="ActivateOptions"/> is called this
+		/// object is in an undefined state and must not be used. 
+		/// </para>
+		/// <para>
+		/// If any of the configuration properties are modified then 
+		/// <see cref="ActivateOptions"/> must be called again.
+		/// </para>
+		/// <para>
+		/// This will cause the file to be opened.
+		/// </para>
+		/// </remarks>
+		override public void ActivateOptions()
+		{
+			base.ActivateOptions();
+
+			if (m_securityContext == null)
+			{
+				m_securityContext = SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
+			}
+
+			if (m_lockingModel == null)
+			{
+				m_lockingModel = new FileAppender.ExclusiveLock();
+			}
+
+			m_lockingModel.CurrentAppender = this;
+			m_lockingModel.ActivateOptions();
+
+			if (m_fileName != null)
+			{
+				using (SecurityContext.Impersonate(this))
+				{
+					m_fileName = ConvertToFullPath(m_fileName.Trim());
+				}
+				SafeOpenFile(m_fileName, m_appendToFile);
+			}
+			else
+			{
+				LogLog.Warn(declaringType, "FileAppender: File option not set for appender [" + Name + "].");
+				LogLog.Warn(declaringType, "FileAppender: Are you using FileAppender instead of ConsoleAppender?");
+			}
+		}
+
+		#endregion Override implementation of AppenderSkeleton
+
+		#region Override implementation of TextWriterAppender
+
+		/// <summary>
+		/// Closes any previously opened file and calls the parent's <see cref="TextWriterAppender.Reset"/>.
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Resets the filename and the file stream.
+		/// </para>
+		/// </remarks>
+		override protected void Reset()
+		{
+			base.Reset();
+			m_fileName = null;
+		}
+
+		/// <summary>
+		/// Close this appender instance. The underlying stream or writer is also closed.
+		/// </summary>
+		override protected void OnClose()
+		{
+			base.OnClose();
+			m_lockingModel.OnClose();
+		}
+
+		/// <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);
+		}
+
+		/// <summary>
+		/// This method is called by the <see cref="M:AppenderSkeleton.DoAppend(LoggingEvent)"/>
+		/// method. 
+		/// </summary>
+		/// <param name="loggingEvent">The event to log.</param>
+		/// <remarks>
+		/// <para>
+		/// Writes a log statement to the output stream if the output stream exists 
+		/// and is writable.  
+		/// </para>
+		/// <para>
+		/// The format of the output will depend on the appender's layout.
+		/// </para>
+		/// </remarks>
+		override protected void Append(LoggingEvent loggingEvent)
+		{
+			if (m_stream.AcquireLock())
+			{
+				try
+				{
+					base.Append(loggingEvent);
+				}
+				finally
+				{
+					m_stream.ReleaseLock();
+				}
+			}
+		}
+
+		/// <summary>
+		/// This method is called by the <see cref="M:AppenderSkeleton.DoAppend(LoggingEvent[])"/>
+		/// method. 
+		/// </summary>
+		/// <param name="loggingEvents">The array of events to log.</param>
+		/// <remarks>
+		/// <para>
+		/// Acquires the output file locks once before writing all the events to
+		/// the stream.
+		/// </para>
+		/// </remarks>
+		override protected void Append(LoggingEvent[] loggingEvents)
+		{
+			if (m_stream.AcquireLock())
+			{
+				try
+				{
+					base.Append(loggingEvents);
+				}
+				finally
+				{
+					m_stream.ReleaseLock();
+				}
+			}
+		}
+
+		/// <summary>
+		/// Writes a footer as produced by the embedded layout's <see cref="ILayout.Footer"/> property.
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Writes a footer as produced by the embedded layout's <see cref="ILayout.Footer"/> property.
+		/// </para>
+		/// </remarks>
+		protected override void WriteFooter()
+		{
+			if (m_stream != null)
+			{
+				//WriteFooter can be called even before a file is opened
+				m_stream.AcquireLock();
+				try
+				{
+					base.WriteFooter();
+				}
+				finally
+				{
+					m_stream.ReleaseLock();
+				}
+			}
+		}
+
+		/// <summary>
+		/// Writes a header produced by the embedded layout's <see cref="ILayout.Header"/> property.
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Writes a header produced by the embedded layout's <see cref="ILayout.Header"/> property.
+		/// </para>
+		/// </remarks>
+		protected override void WriteHeader()
+		{
+			if (m_stream != null)
+			{
+				if (m_stream.AcquireLock())
+				{
+					try
+					{
+						base.WriteHeader();
+					}
+					finally
+					{
+						m_stream.ReleaseLock();
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// Closes the underlying <see cref="TextWriter"/>.
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Closes the underlying <see cref="TextWriter"/>.
+		/// </para>
+		/// </remarks>
+		protected override void CloseWriter()
+		{
+			if (m_stream != null)
+			{
+				m_stream.AcquireLock();
+				try
+				{
+					base.CloseWriter();
+				}
+				finally
+				{
+					m_stream.ReleaseLock();
+				}
+			}
+		}
+
+		#endregion Override implementation of TextWriterAppender
+
+		#region Public Instance Methods
+
+		/// <summary>
+		/// Closes the previously opened file.
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Writes the <see cref="ILayout.Footer"/> to the file and then
+		/// closes the file.
+		/// </para>
+		/// </remarks>
+		protected void CloseFile()
+		{
+			WriteFooterAndCloseWriter();
+		}
+
+		#endregion Public Instance Methods
+
+		#region Protected Instance Methods
+
+		/// <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. Must be a fully qualified path.</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. Must be a fully qualified path.</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>
+		/// </remarks>
+		virtual protected void OpenFile(string fileName, bool append)
+		{
+			if (LogLog.IsErrorEnabled)
+			{
+				// Internal check that the fileName passed in is a rooted path
+				bool isPathRooted = false;
+				using (SecurityContext.Impersonate(this))
+				{
+					isPathRooted = Path.IsPathRooted(fileName);
+				}
+				if (!isPathRooted)
+				{
+					LogLog.Error(declaringType, "INTERNAL ERROR. OpenFile(" + fileName + "): File name is not fully qualified.");
+				}
+			}
+
+			lock (this)
+			{
+				Reset();
+
+				LogLog.Debug(declaringType, "Opening file for writing [" + fileName + "] append [" + append + "]");
+
+				// Save these for later, allowing retries if file open fails
+				m_fileName = fileName;
+				m_appendToFile = append;
+
+				LockingModel.CurrentAppender = this;
+				LockingModel.OpenFile(fileName, append, m_encoding);
+				m_stream = new LockingStream(LockingModel);
+
+				if (m_stream != null)
+				{
+					m_stream.AcquireLock();
+					try
+					{
+						SetQWForFiles(new StreamWriter(m_stream, m_encoding));
+					}
+					finally
+					{
+						m_stream.ReleaseLock();
+					}
+				}
+
+				WriteHeader();
+			}
+		}
+
+		/// <summary>
+		/// Sets the quiet writer used for file output
+		/// </summary>
+		/// <param name="fileStream">the file stream that has been opened for writing</param>
+		/// <remarks>
+		/// <para>
+		/// This implementation of <see cref="M:SetQWForFiles(Stream)"/> creates a <see cref="StreamWriter"/>
+		/// over the <paramref name="fileStream"/> and passes it to the 
+		/// <see cref="M:SetQWForFiles(TextWriter)"/> method.
+		/// </para>
+		/// <para>
+		/// This method can be overridden by sub classes that want to wrap the
+		/// <see cref="Stream"/> in some way, for example to encrypt the output
+		/// data using a <c>System.Security.Cryptography.CryptoStream</c>.
+		/// </para>
+		/// </remarks>
+		virtual protected void SetQWForFiles(Stream fileStream)
+		{
+			SetQWForFiles(new StreamWriter(fileStream, m_encoding));
+		}
+
+		/// <summary>
+		/// Sets the quiet writer being used.
+		/// </summary>
+		/// <param name="writer">the writer over the file stream that has been opened for writing</param>
+		/// <remarks>
+		/// <para>
+		/// This method can be overridden by sub classes that want to
+		/// wrap the <see cref="TextWriter"/> in some way.
+		/// </para>
+		/// </remarks>
+		virtual protected void SetQWForFiles(TextWriter writer)
+		{
+			QuietWriter = new QuietTextWriter(writer, ErrorHandler);
+		}
+
+		#endregion Protected Instance Methods
+
+		#region Protected Static Methods
+
+		/// <summary>
+		/// Convert a path into a fully qualified path.
+		/// </summary>
+		/// <param name="path">The path to convert.</param>
+		/// <returns>The fully qualified path.</returns>
+		/// <remarks>
+		/// <para>
+		/// Converts the path specified to a fully
+		/// qualified path. If the path is relative it is
+		/// taken as relative from the application base 
+		/// directory.
+		/// </para>
+		/// </remarks>
+		protected static string ConvertToFullPath(string path)
+		{
+			return SystemInfo.ConvertToFullPath(path);
+		}
+
+		#endregion Protected Static Methods
+
+		#region Private Instance Fields
+
+		/// <summary>
+		/// Flag to indicate if we should append to the file
+		/// or overwrite the file. The default is to append.
+		/// </summary>
+		private bool m_appendToFile = true;
+
+		/// <summary>
+		/// The name of the log file.
+		/// </summary>
+		private string m_fileName = null;
+
+		/// <summary>
+		/// The encoding to use for the file stream.
+		/// </summary>
+#if NETSTANDARD1_3
+		private Encoding m_encoding = Encoding.Unicode;
+#else
+		private Encoding m_encoding = Encoding.Default;
+#endif
+
+		/// <summary>
+		/// The security context to use for privileged calls
+		/// </summary>
+		private SecurityContext m_securityContext;
+
+		/// <summary>
+		/// The stream to log to. Has added locking semantics
+		/// </summary>
+		private FileAppender.LockingStream m_stream = null;
+
+		/// <summary>
+		/// The locking model to use
+		/// </summary>
+		private FileAppender.LockingModelBase m_lockingModel = new FileAppender.ExclusiveLock();
+
+		#endregion Private Instance Fields
+
+		#region Private Static Fields
+
+		/// <summary>
+		/// The fully qualified type of the FileAppender class.
+		/// </summary>
+		/// <remarks>
+		/// Used by the internal logger to record the Type of the
+		/// log message.
+		/// </remarks>
+		private readonly static Type declaringType = typeof(FileAppender);
+
+		#endregion Private Static Fields
+	}
+}