⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fileappender.cs

📁 精通SQL Server2005项目开发
💻 CS
📖 第 1 页 / 共 3 页
字号:
#region Copyright & License
//
// Copyright 2001-2006 The Apache Software Foundation
//
// Licensed 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 log4net.Util;
using log4net.Layout;
using log4net.Core;

namespace log4net.Appender
{
	/// <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, <see cref="FileAppender.MinimalLock"/>, only holds a
	/// write lock while the appender is writing a logging event.
	/// </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>
	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() 
			{
				this.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>
			/// 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>
		/// 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.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -