关于《NHibernate中使用NLog》中在App.config(web.config)中增加nhibernatelogger节点的疑惑

在上一篇《NHibernate中使用NLog》中最后在App.config或web.config中AppSettings节中增加nhibernate-logger节点的介绍比较含糊,引起了朋友的疑问,现在在这里关于这个节点进行详细的讲解。
首先我们先看一下NH3的源码:NHibernate-3.1.0.GA/src/NHibernate/Logging.cs
在该代码中获取AppSetttings节的配置节点的部门,如果它没有检测到用户的程序中配置了自定义的Log框架情况时则检测LOG4NET是否存在,如果存在则使用LOG4NET来记录LOG。另外NH3中也提供了LOG4NET的实现,可以看出NH3中对于LOG4NET的实现非常的灵活,我准备在下一篇文章中根据NH3中对于LOG4NET的实现方式来实现NLOG框架而不是象NHibernate中使用NLog中入门的方式来实现接口。
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Linq.Expressions;

namespace NHibernate
{
	public interface IInternalLogger
	{
		bool IsErrorEnabled { get; }
		bool IsFatalEnabled { get; }
		bool IsDebugEnabled { get; }
		bool IsInfoEnabled { get; }
		bool IsWarnEnabled { get; }
		void Error(object message);
		void Error(object message, Exception exception);
		void ErrorFormat(string format, params object[] args);

		void Fatal(object message);
		void Fatal(object message, Exception exception);

		void Debug(object message);
		void Debug(object message, Exception exception);
		void DebugFormat(string format, params object[] args);

		void Info(object message);
		void Info(object message, Exception exception);
		void InfoFormat(string format, params object[] args);

		void Warn(object message);
		void Warn(object message, Exception exception);
		void WarnFormat(string format, params object[] args);
	}

	public interface ILoggerFactory
	{
		IInternalLogger LoggerFor(string keyName);
		IInternalLogger LoggerFor(System.Type type);
	}

	public class LoggerProvider
	{
		private const string NhibernateLoggerConfKey = "nhibernate-logger";
		private readonly ILoggerFactory loggerFactory;
		private static LoggerProvider instance;

		static LoggerProvider()
		{
			string nhibernateLoggerClass = GetNhibernateLoggerClass();
			ILoggerFactory loggerFactory = string.IsNullOrEmpty(nhibernateLoggerClass) ? new NoLoggingLoggerFactory() : GetLoggerFactory(nhibernateLoggerClass);
			SetLoggersFactory(loggerFactory);
		}

		private static ILoggerFactory GetLoggerFactory(string nhibernateLoggerClass)
		{
			ILoggerFactory loggerFactory;
			var loggerFactoryType = System.Type.GetType(nhibernateLoggerClass);
			try
			{
				loggerFactory = (ILoggerFactory) Activator.CreateInstance(loggerFactoryType);
			}
			catch (MissingMethodException ex)
			{
				throw new ApplicationException("Public constructor was not found for " + loggerFactoryType, ex);
			}
			catch (InvalidCastException ex)
			{
				throw new ApplicationException(loggerFactoryType + "Type does not implement " + typeof (ILoggerFactory), ex);
			}
			catch (Exception ex)
			{
				throw new ApplicationException("Unable to instantiate: " + loggerFactoryType, ex);
			}
			return loggerFactory;
		}

		private static string GetNhibernateLoggerClass()
		{
			var nhibernateLogger = ConfigurationManager.AppSettings.Keys.Cast<string>().FirstOrDefault(k => NhibernateLoggerConfKey.Equals(k.ToLowerInvariant()));
			string nhibernateLoggerClass = null;
			if (string.IsNullOrEmpty(nhibernateLogger))
			{
				// look for log4net.dll
				string baseDir = AppDomain.CurrentDomain.BaseDirectory;
				string relativeSearchPath = AppDomain.CurrentDomain.RelativeSearchPath;
				string binPath = relativeSearchPath == null ? baseDir : Path.Combine(baseDir, relativeSearchPath);
				var log4NetDllPath = Path.Combine(binPath, "log4net.dll");

				if (File.Exists(log4NetDllPath))
				{
					nhibernateLoggerClass = typeof (Log4NetLoggerFactory).AssemblyQualifiedName;
				}
			}
			else
			{
				nhibernateLoggerClass = ConfigurationManager.AppSettings[nhibernateLogger];
			}
			return nhibernateLoggerClass;
		}

		public static void SetLoggersFactory(ILoggerFactory loggerFactory)
		{
			instance = new LoggerProvider(loggerFactory);
		}

		private LoggerProvider(ILoggerFactory loggerFactory)
		{
			this.loggerFactory = loggerFactory;
		}

		public static IInternalLogger LoggerFor(string keyName)
		{
			return instance.loggerFactory.LoggerFor(keyName);
		}

		public static IInternalLogger LoggerFor(System.Type type)
		{
			return instance.loggerFactory.LoggerFor(type);
		}
	}

	public class NoLoggingLoggerFactory: ILoggerFactory
	{
		private static readonly IInternalLogger Nologging = new NoLoggingInternalLogger();
		public IInternalLogger LoggerFor(string keyName)
		{
			return Nologging;
		}

		public IInternalLogger LoggerFor(System.Type type)
		{
			return Nologging;
		}
	}

	public class NoLoggingInternalLogger: IInternalLogger
	{
		public bool IsErrorEnabled
		{
			get { return false;}
		}

		public bool IsFatalEnabled
		{
			get { return false; }
		}

		public bool IsDebugEnabled
		{
			get { return false; }
		}

		public bool IsInfoEnabled
		{
			get { return false; }
		}

		public bool IsWarnEnabled
		{
			get { return false; }
		}

		public void Error(object message)
		{
		}

		public void Error(object message, Exception exception)
		{
		}

		public void ErrorFormat(string format, params object[] args)
		{
		}

		public void Fatal(object message)
		{
		}

		public void Fatal(object message, Exception exception)
		{
		}

		public void Debug(object message)
		{
		}

		public void Debug(object message, Exception exception)
		{
		}

		public void DebugFormat(string format, params object[] args)
		{
		}

		public void Info(object message)
		{
		}

		public void Info(object message, Exception exception)
		{
		}

		public void InfoFormat(string format, params object[] args)
		{
		}

		public void Warn(object message)
		{
		}

		public void Warn(object message, Exception exception)
		{
		}

		public void WarnFormat(string format, params object[] args)
		{
		}
	}

	public class Log4NetLoggerFactory: ILoggerFactory
	{
		private static readonly System.Type LogManagerType = System.Type.GetType("log4net.LogManager, log4net");
		private static readonly Func<string, object> GetLoggerByNameDelegate;
		private static readonly Func<System.Type, object> GetLoggerByTypeDelegate;
		static Log4NetLoggerFactory()
		{
			GetLoggerByNameDelegate = GetGetLoggerMethodCall<string>();
			GetLoggerByTypeDelegate = GetGetLoggerMethodCall<System.Type>();
		}
		public IInternalLogger LoggerFor(string keyName)
		{
			return new Log4NetLogger(GetLoggerByNameDelegate(keyName));
		}

		public IInternalLogger LoggerFor(System.Type type)
		{
			return new Log4NetLogger(GetLoggerByTypeDelegate(type));
		}

		private static Func<TParameter, object> GetGetLoggerMethodCall<TParameter>()
		{
			var method = LogManagerType.GetMethod("GetLogger", new[] { typeof(TParameter) });
			ParameterExpression resultValue;
			ParameterExpression keyParam = Expression.Parameter(typeof(TParameter), "key");
			MethodCallExpression methodCall = Expression.Call(null, method, new Expression[] { resultValue = keyParam });
			return Expression.Lambda<Func<TParameter, object>>(methodCall, new[] { resultValue }).Compile();
		}
	}

	public class Log4NetLogger: IInternalLogger
	{
		private static readonly System.Type ILogType = System.Type.GetType("log4net.ILog, log4net");
		private static readonly Func<object, bool> IsErrorEnabledDelegate;
		private static readonly Func<object, bool> IsFatalEnabledDelegate;
		private static readonly Func<object, bool> IsDebugEnabledDelegate;
		private static readonly Func<object, bool> IsInfoEnabledDelegate;
		private static readonly Func<object, bool> IsWarnEnabledDelegate;

		private static readonly Action<object, object> ErrorDelegate;
		private static readonly Action<object, object, Exception> ErrorExceptionDelegate;
		private static readonly Action<object, string, object[]> ErrorFormatDelegate;

		private static readonly Action<object, object> FatalDelegate;
		private static readonly Action<object, object, Exception> FatalExceptionDelegate;

		private static readonly Action<object, object> DebugDelegate;
		private static readonly Action<object, object, Exception> DebugExceptionDelegate;
		private static readonly Action<object, string, object[]> DebugFormatDelegate;

		private static readonly Action<object, object> InfoDelegate;
		private static readonly Action<object, object, Exception> InfoExceptionDelegate;
		private static readonly Action<object, string, object[]> InfoFormatDelegate;

		private static readonly Action<object, object> WarnDelegate;
		private static readonly Action<object, object, Exception> WarnExceptionDelegate;
		private static readonly Action<object, string, object[]> WarnFormatDelegate;

		private readonly object logger;

		static Log4NetLogger()
		{
			IsErrorEnabledDelegate = GetPropertyGetter("IsErrorEnabled");
			IsFatalEnabledDelegate = GetPropertyGetter("IsFatalEnabled");
			IsDebugEnabledDelegate = GetPropertyGetter("IsDebugEnabled");
			IsInfoEnabledDelegate = GetPropertyGetter("IsInfoEnabled");
			IsWarnEnabledDelegate = GetPropertyGetter("IsWarnEnabled");
			ErrorDelegate = GetMethodCallForMessage("Error");
			ErrorExceptionDelegate = GetMethodCallForMessageException("Error");
			ErrorFormatDelegate = GetMethodCallForMessageFormat("ErrorFormat");

			FatalDelegate = GetMethodCallForMessage("Fatal");
			FatalExceptionDelegate = GetMethodCallForMessageException("Fatal");

			DebugDelegate = GetMethodCallForMessage("Debug");
			DebugExceptionDelegate = GetMethodCallForMessageException("Debug");
			DebugFormatDelegate = GetMethodCallForMessageFormat("DebugFormat");

			InfoDelegate = GetMethodCallForMessage("Info");
			InfoExceptionDelegate = GetMethodCallForMessageException("Info");
			InfoFormatDelegate = GetMethodCallForMessageFormat("InfoFormat");

			WarnDelegate = GetMethodCallForMessage("Warn");
			WarnExceptionDelegate = GetMethodCallForMessageException("Warn");
			WarnFormatDelegate = GetMethodCallForMessageFormat("WarnFormat");
		}

		private static Func<object, bool> GetPropertyGetter(string propertyName)
		{
			ParameterExpression funcParam = Expression.Parameter(typeof(object), "l");
			Expression convertedParam = Expression.Convert(funcParam, ILogType);
			Expression property = Expression.Property(convertedParam, propertyName);
			return (Func<object, bool>)Expression.Lambda(property, funcParam).Compile();
		}

		private static Action<object, object> GetMethodCallForMessage(string methodName)
		{
			ParameterExpression loggerParam = Expression.Parameter(typeof(object), "l");
			ParameterExpression messageParam = Expression.Parameter(typeof(object), "o");
			Expression convertedParam = Expression.Convert(loggerParam, ILogType);
			MethodCallExpression methodCall = Expression.Call(convertedParam, ILogType.GetMethod(methodName, new[] { typeof(object) }), messageParam);
			return (Action<object, object>)Expression.Lambda(methodCall, new[] { loggerParam, messageParam }).Compile();
		}

		private static Action<object, object, Exception> GetMethodCallForMessageException(string methodName)
		{
			ParameterExpression loggerParam = Expression.Parameter(typeof(object), "l");
			ParameterExpression messageParam = Expression.Parameter(typeof(object), "o");
			ParameterExpression exceptionParam = Expression.Parameter(typeof(Exception), "e");
			Expression convertedParam = Expression.Convert(loggerParam, ILogType);
			MethodCallExpression methodCall = Expression.Call(convertedParam, ILogType.GetMethod(methodName, new[] { typeof(object), typeof(Exception) }), messageParam, exceptionParam);
			return (Action<object, object, Exception>)Expression.Lambda(methodCall, new[] { loggerParam, messageParam, exceptionParam }).Compile();
		}

		private static Action<object, string, object[]> GetMethodCallForMessageFormat(string methodName)
		{
			ParameterExpression loggerParam = Expression.Parameter(typeof(object), "l");
			ParameterExpression formatParam = Expression.Parameter(typeof(string), "f");
			ParameterExpression parametersParam = Expression.Parameter(typeof(object[]), "p");
			Expression convertedParam = Expression.Convert(loggerParam, ILogType);
			MethodCallExpression methodCall = Expression.Call(convertedParam, ILogType.GetMethod(methodName, new[] { typeof(string), typeof(object[]) }), formatParam, parametersParam);
			return (Action<object, string, object[]>)Expression.Lambda(methodCall, new[] { loggerParam, formatParam, parametersParam }).Compile();
		}

		public Log4NetLogger(object logger)
		{
			this.logger = logger;
		}

		public bool IsErrorEnabled
		{
			get { return IsErrorEnabledDelegate(logger); }
		}

		public bool IsFatalEnabled
		{
			get { return IsFatalEnabledDelegate(logger); }
		}

		public bool IsDebugEnabled
		{
			get { return IsDebugEnabledDelegate(logger); }
		}

		public bool IsInfoEnabled
		{
			get { return IsInfoEnabledDelegate(logger); }
		}

		public bool IsWarnEnabled
		{
			get { return IsWarnEnabledDelegate(logger); }
		}

		public void Error(object message)
		{
			ErrorDelegate(logger, message);
		}

		public void Error(object message, Exception exception)
		{
			ErrorExceptionDelegate(logger,message,exception);
		}

		public void ErrorFormat(string format, params object[] args)
		{
			ErrorFormatDelegate(logger, format, args);
		}

		public void Fatal(object message)
		{
			FatalDelegate(logger, message);
		}

		public void Fatal(object message, Exception exception)
		{
			FatalExceptionDelegate(logger,message,exception);
		}

		public void Debug(object message)
		{
			DebugDelegate(logger, message);
		}

		public void Debug(object message, Exception exception)
		{
			DebugExceptionDelegate(logger, message, exception);
		}

		public void DebugFormat(string format, params object[] args)
		{
			DebugFormatDelegate(logger, format, args);
		}

		public void Info(object message)
		{
			InfoDelegate(logger, message);
		}

		public void Info(object message, Exception exception)
		{
			InfoExceptionDelegate(logger, message, exception);
		}

		public void InfoFormat(string format, params object[] args)
		{
			InfoFormatDelegate(logger, format, args);
		}

		public void Warn(object message)
		{
			WarnDelegate(logger, message);
		}

		public void Warn(object message, Exception exception)
		{
			WarnExceptionDelegate(logger, message, exception);
		}

		public void WarnFormat(string format, params object[] args)
		{
			WarnFormatDelegate(logger, format, args);
		}
	}
}
原文地址:https://www.cnblogs.com/biyusoft/p/3432067.html