diff --git a/src/NHibernate/Logging.cs b/src/NHibernate/Logging.cs index 9af1b93590d..a11639404a5 100644 --- a/src/NHibernate/Logging.cs +++ b/src/NHibernate/Logging.cs @@ -1,6 +1,5 @@ using System; using System.Configuration; -using System.IO; using System.Linq; namespace NHibernate @@ -117,13 +116,8 @@ private static string GetNhibernateLoggerClass() 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); - string log4NetDllPath = binPath == null ? "log4net.dll" : Path.Combine(binPath, "log4net.dll"); - - if (File.Exists(log4NetDllPath) || AppDomain.CurrentDomain.GetAssemblies().Any(a => a.GetName().Name == "log4net")) + // look for log4net + if (Log4NetLoggerFactory.Log4NetAssembly != null) { nhibernateLoggerClass = typeof(Log4NetLoggerFactory).AssemblyQualifiedName; } diff --git a/src/NHibernate/Logging.log4net.cs b/src/NHibernate/Logging.log4net.cs index 6dc14e3118c..82c72571e37 100644 --- a/src/NHibernate/Logging.log4net.cs +++ b/src/NHibernate/Logging.log4net.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Linq.Expressions; using System.Reflection; using NHibernate.Util; @@ -12,16 +13,48 @@ namespace NHibernate public class Log4NetLoggerFactory: ILoggerFactory #pragma warning restore 618 { - private static readonly System.Type LogManagerType = System.Type.GetType("log4net.LogManager, log4net"); + internal static readonly Assembly Log4NetAssembly; + private static readonly System.Type LogManagerType; private static readonly Func GetLoggerByNameDelegate; private static readonly Func GetLoggerByTypeDelegate; static Log4NetLoggerFactory() { + LogManagerType = GetLogManagerType(); + if (LogManagerType == null) + return; + + Log4NetAssembly = LogManagerType.Assembly; GetLoggerByNameDelegate = GetGetLoggerByNameMethodCall(); GetLoggerByTypeDelegate = GetGetLoggerMethodCall(); } + public Log4NetLoggerFactory() + { + if (LogManagerType == null) + throw new TypeLoadException("Cannot find log4net.LogManager type"); + } + + // Code adapted from ReflectHelper.TypeFromAssembly, which cannot be called directly due + // to depending on the logger. + private static System.Type GetLogManagerType() + { + var typeName = "log4net.LogManager, log4net"; + // Try to get the type from an already loaded assembly + var type = System.Type.GetType(typeName); + if (type != null) + return type; + + // Load type from an already loaded assembly, or yield null + return System.Type.GetType( + typeName, + // An alternate could be "a.GetName().Name == an.Name", but GetName() is not lightweight. + // "a.FullName == an.FullName" can never match because an.FullName will lack the version, culture + // and public key token. + an => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName.StartsWith("log4net,")), + null); + } + #pragma warning disable 618 [Obsolete("Use this as an INHibernateLoggerFactory instead.")] public IInternalLogger LoggerFor(string keyName) @@ -39,6 +72,8 @@ public IInternalLogger LoggerFor(System.Type type) private static Func GetGetLoggerMethodCall() { var method = LogManagerType.GetMethod("GetLogger", new[] { typeof(TParameter) }); + if (method == null) + throw new InvalidOperationException($"Unable to find LogManager.GetLogger({typeof(TParameter)})"); ParameterExpression resultValue; ParameterExpression keyParam = Expression.Parameter(typeof(TParameter), "key"); MethodCallExpression methodCall = Expression.Call(null, method, resultValue = keyParam); @@ -48,6 +83,8 @@ private static Func GetGetLoggerMethodCall() private static Func GetGetLoggerByNameMethodCall() { var method = LogManagerType.GetMethod("GetLogger", new[] {typeof(Assembly), typeof(string)}); + if (method == null) + throw new InvalidOperationException("Unable to find LogManager.GetLogger(Assembly, string)"); ParameterExpression nameParam = Expression.Parameter(typeof(string), "name"); ParameterExpression repositoryAssemblyParam = Expression.Parameter(typeof(Assembly), "repositoryAssembly"); MethodCallExpression methodCall = Expression.Call(null, method, repositoryAssemblyParam, nameParam); @@ -62,7 +99,6 @@ private static Func GetGetLoggerByNameMethodCall() public class Log4NetLogger : IInternalLogger #pragma warning restore 618 { - private static readonly System.Type ILogType = System.Type.GetType("log4net.ILog, log4net"); private static readonly Func IsErrorEnabledDelegate; private static readonly Func IsFatalEnabledDelegate; private static readonly Func IsDebugEnabledDelegate; @@ -92,29 +128,35 @@ public class Log4NetLogger : IInternalLogger static Log4NetLogger() { - IsErrorEnabledDelegate = DelegateHelper.BuildPropertyGetter(ILogType, "IsErrorEnabled"); - IsFatalEnabledDelegate = DelegateHelper.BuildPropertyGetter(ILogType, "IsFatalEnabled"); - IsDebugEnabledDelegate = DelegateHelper.BuildPropertyGetter(ILogType, "IsDebugEnabled"); - IsInfoEnabledDelegate = DelegateHelper.BuildPropertyGetter(ILogType, "IsInfoEnabled"); - IsWarnEnabledDelegate = DelegateHelper.BuildPropertyGetter(ILogType, "IsWarnEnabled"); - ErrorDelegate = DelegateHelper.BuildAction(ILogType, "Error"); - ErrorExceptionDelegate = DelegateHelper.BuildAction(ILogType, "Error"); - ErrorFormatDelegate = DelegateHelper.BuildAction(ILogType, "ErrorFormat"); - - FatalDelegate = DelegateHelper.BuildAction(ILogType, "Fatal"); - FatalExceptionDelegate = DelegateHelper.BuildAction(ILogType, "Fatal"); - - DebugDelegate = DelegateHelper.BuildAction(ILogType, "Debug"); - DebugExceptionDelegate = DelegateHelper.BuildAction(ILogType, "Debug"); - DebugFormatDelegate = DelegateHelper.BuildAction(ILogType, "DebugFormat"); - - InfoDelegate = DelegateHelper.BuildAction(ILogType, "Info"); - InfoExceptionDelegate = DelegateHelper.BuildAction(ILogType, "Info"); - InfoFormatDelegate = DelegateHelper.BuildAction(ILogType, "InfoFormat"); - - WarnDelegate = DelegateHelper.BuildAction(ILogType, "Warn"); - WarnExceptionDelegate = DelegateHelper.BuildAction(ILogType, "Warn"); - WarnFormatDelegate = DelegateHelper.BuildAction(ILogType, "WarnFormat"); + if (Log4NetLoggerFactory.Log4NetAssembly == null) + throw new TypeLoadException( + "Cannot load ILog type, log4net is not found"); + + var iLogType = Log4NetLoggerFactory.Log4NetAssembly.GetType("log4net.ILog", true); + + IsErrorEnabledDelegate = DelegateHelper.BuildPropertyGetter(iLogType, "IsErrorEnabled"); + IsFatalEnabledDelegate = DelegateHelper.BuildPropertyGetter(iLogType, "IsFatalEnabled"); + IsDebugEnabledDelegate = DelegateHelper.BuildPropertyGetter(iLogType, "IsDebugEnabled"); + IsInfoEnabledDelegate = DelegateHelper.BuildPropertyGetter(iLogType, "IsInfoEnabled"); + IsWarnEnabledDelegate = DelegateHelper.BuildPropertyGetter(iLogType, "IsWarnEnabled"); + ErrorDelegate = DelegateHelper.BuildAction(iLogType, "Error"); + ErrorExceptionDelegate = DelegateHelper.BuildAction(iLogType, "Error"); + ErrorFormatDelegate = DelegateHelper.BuildAction(iLogType, "ErrorFormat"); + + FatalDelegate = DelegateHelper.BuildAction(iLogType, "Fatal"); + FatalExceptionDelegate = DelegateHelper.BuildAction(iLogType, "Fatal"); + + DebugDelegate = DelegateHelper.BuildAction(iLogType, "Debug"); + DebugExceptionDelegate = DelegateHelper.BuildAction(iLogType, "Debug"); + DebugFormatDelegate = DelegateHelper.BuildAction(iLogType, "DebugFormat"); + + InfoDelegate = DelegateHelper.BuildAction(iLogType, "Info"); + InfoExceptionDelegate = DelegateHelper.BuildAction(iLogType, "Info"); + InfoFormatDelegate = DelegateHelper.BuildAction(iLogType, "InfoFormat"); + + WarnDelegate = DelegateHelper.BuildAction(iLogType, "Warn"); + WarnExceptionDelegate = DelegateHelper.BuildAction(iLogType, "Warn"); + WarnFormatDelegate = DelegateHelper.BuildAction(iLogType, "WarnFormat"); } ///