From 27da04a6bfe22fdbe88376789dc07c0a34a8a1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Tue, 4 Sep 2018 15:43:14 +0200 Subject: [PATCH 1/6] Have more robust log4net loading --- src/NHibernate/Logging.cs | 9 ++--- src/NHibernate/Logging.log4net.cs | 56 +++++++++++++++++-------------- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/src/NHibernate/Logging.cs b/src/NHibernate/Logging.cs index 9af1b93590d..1252478323e 100644 --- a/src/NHibernate/Logging.cs +++ b/src/NHibernate/Logging.cs @@ -117,13 +117,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 (System.Type.GetType("log4net.LogManager, log4net") != null) { nhibernateLoggerClass = typeof(Log4NetLoggerFactory).AssemblyQualifiedName; } diff --git a/src/NHibernate/Logging.log4net.cs b/src/NHibernate/Logging.log4net.cs index 6dc14e3118c..b0d07c8bdcf 100644 --- a/src/NHibernate/Logging.log4net.cs +++ b/src/NHibernate/Logging.log4net.cs @@ -12,12 +12,13 @@ namespace NHibernate public class Log4NetLoggerFactory: ILoggerFactory #pragma warning restore 618 { - private static readonly System.Type LogManagerType = System.Type.GetType("log4net.LogManager, log4net"); + private static readonly System.Type LogManagerType; private static readonly Func GetLoggerByNameDelegate; private static readonly Func GetLoggerByTypeDelegate; static Log4NetLoggerFactory() { + LogManagerType = System.Type.GetType("log4net.LogManager, log4net", true); GetLoggerByNameDelegate = GetGetLoggerByNameMethodCall(); GetLoggerByTypeDelegate = GetGetLoggerMethodCall(); } @@ -39,6 +40,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 +51,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 +67,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 +96,31 @@ 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"); + var iLogType = System.Type.GetType("log4net.ILog, log4net", 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"); } /// From acac0ccf62c35b0f469ee0f3edcc312288853d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Thu, 6 Sep 2018 11:41:20 +0200 Subject: [PATCH 2/6] fixup! Have more robust log4net loading Reuse the logic from ReflectHelper, and mutualise it for all log4net type loadings --- src/NHibernate/Logging.cs | 3 +- src/NHibernate/Logging.log4net.cs | 50 ++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/NHibernate/Logging.cs b/src/NHibernate/Logging.cs index 1252478323e..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 @@ -118,7 +117,7 @@ private static string GetNhibernateLoggerClass() if (string.IsNullOrEmpty(nhibernateLogger)) { // look for log4net - if (System.Type.GetType("log4net.LogManager, log4net") != null) + if (Log4NetLoggerFactory.Log4NetAssembly != null) { nhibernateLoggerClass = typeof(Log4NetLoggerFactory).AssemblyQualifiedName; } diff --git a/src/NHibernate/Logging.log4net.cs b/src/NHibernate/Logging.log4net.cs index b0d07c8bdcf..db6fa5886d6 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,15 +13,56 @@ namespace NHibernate public class Log4NetLoggerFactory: ILoggerFactory #pragma warning restore 618 { + internal static readonly Assembly Log4NetAssembly; + private static readonly Exception LogManagerTypeLoadException; private static readonly System.Type LogManagerType; private static readonly Func GetLoggerByNameDelegate; private static readonly Func GetLoggerByTypeDelegate; static Log4NetLoggerFactory() { - LogManagerType = System.Type.GetType("log4net.LogManager, log4net", true); - GetLoggerByNameDelegate = GetGetLoggerByNameMethodCall(); - GetLoggerByTypeDelegate = GetGetLoggerMethodCall(); + try + { + LogManagerType = GetLogManagerType(); + Log4NetAssembly = LogManagerType.Assembly; + GetLoggerByNameDelegate = GetGetLoggerByNameMethodCall(); + GetLoggerByTypeDelegate = GetGetLoggerMethodCall(); + } + catch (Exception ex) + { + LogManagerTypeLoadException = ex; + } + } + + public Log4NetLoggerFactory() + { + if (LogManagerType == null) + throw new TypeLoadException("Could not load LogManager type", LogManagerTypeLoadException); + } + + // Code mostly adapted from ReflectHelper.TypeFromAssembly, which cannot be called directly due + // to depending on the logger. + private static System.Type GetLogManagerType() + { + var typeName = new AssemblyQualifiedTypeName("log4net.LogManager", "log4net"); + // Try to get the type from an already loaded assembly + var type = System.Type.GetType(typeName.ToString()); + if (type != null) + return type; + + // Load type from an already loaded assembly + type = System.Type.GetType( + typeName.ToString(), + an => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == an.FullName), + null); + if (type != null) + return type; + + var assembly = Assembly.Load(typeName.Assembly); + if (assembly == null) + throw new TypeLoadException($"Could not load type '{typeName}', assembly not found"); + + return assembly.GetType(typeName.Type, true); } #pragma warning disable 618 @@ -96,7 +138,7 @@ public class Log4NetLogger : IInternalLogger static Log4NetLogger() { - var iLogType = System.Type.GetType("log4net.ILog, log4net", true); + var iLogType = Log4NetLoggerFactory.Log4NetAssembly.GetType("log4net.ILog"); IsErrorEnabledDelegate = DelegateHelper.BuildPropertyGetter(iLogType, "IsErrorEnabled"); IsFatalEnabledDelegate = DelegateHelper.BuildPropertyGetter(iLogType, "IsFatalEnabled"); From 8c5c8760de0c10596b14074beda58f4445503d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Thu, 6 Sep 2018 11:58:15 +0200 Subject: [PATCH 3/6] fixup! Have more robust log4net loading --- src/NHibernate/Logging.log4net.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/NHibernate/Logging.log4net.cs b/src/NHibernate/Logging.log4net.cs index db6fa5886d6..eb706a586b6 100644 --- a/src/NHibernate/Logging.log4net.cs +++ b/src/NHibernate/Logging.log4net.cs @@ -14,7 +14,7 @@ public class Log4NetLoggerFactory: ILoggerFactory #pragma warning restore 618 { internal static readonly Assembly Log4NetAssembly; - private static readonly Exception LogManagerTypeLoadException; + internal static readonly Exception LogManagerTypeLoadException; private static readonly System.Type LogManagerType; private static readonly Func GetLoggerByNameDelegate; private static readonly Func GetLoggerByTypeDelegate; @@ -138,7 +138,12 @@ public class Log4NetLogger : IInternalLogger static Log4NetLogger() { - var iLogType = Log4NetLoggerFactory.Log4NetAssembly.GetType("log4net.ILog"); + if (Log4NetLoggerFactory.Log4NetAssembly == null) + throw new TypeLoadException( + "Could not load ILog type, LogManager own loading has previously failed", + Log4NetLoggerFactory.LogManagerTypeLoadException); + + var iLogType = Log4NetLoggerFactory.Log4NetAssembly.GetType("log4net.ILog", true); IsErrorEnabledDelegate = DelegateHelper.BuildPropertyGetter(iLogType, "IsErrorEnabled"); IsFatalEnabledDelegate = DelegateHelper.BuildPropertyGetter(iLogType, "IsFatalEnabled"); From 8f4aee83509da06469de7f8a835a3236feab98d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Mon, 19 Nov 2018 13:52:34 +0100 Subject: [PATCH 4/6] fixup! Have more robust log4net loading Remove non-sense --- src/NHibernate/Logging.log4net.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/NHibernate/Logging.log4net.cs b/src/NHibernate/Logging.log4net.cs index eb706a586b6..3aa373858a8 100644 --- a/src/NHibernate/Logging.log4net.cs +++ b/src/NHibernate/Logging.log4net.cs @@ -40,7 +40,7 @@ public Log4NetLoggerFactory() throw new TypeLoadException("Could not load LogManager type", LogManagerTypeLoadException); } - // Code mostly adapted from ReflectHelper.TypeFromAssembly, which cannot be called directly due + // Code adapted from ReflectHelper.TypeFromAssembly, which cannot be called directly due // to depending on the logger. private static System.Type GetLogManagerType() { @@ -53,15 +53,16 @@ private static System.Type GetLogManagerType() // Load type from an already loaded assembly type = System.Type.GetType( typeName.ToString(), - an => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == an.FullName), + // 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); if (type != null) return type; + // Assembly.Load fails if it does not find the assembly. It does not yield null. var assembly = Assembly.Load(typeName.Assembly); - if (assembly == null) - throw new TypeLoadException($"Could not load type '{typeName}', assembly not found"); - return assembly.GetType(typeName.Type, true); } From 67bbdd65de4853213a0479fed4438197e677f14d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Mon, 19 Nov 2018 14:01:57 +0100 Subject: [PATCH 5/6] Remove exception handling --- src/NHibernate/Logging.log4net.cs | 34 ++++++++++--------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/src/NHibernate/Logging.log4net.cs b/src/NHibernate/Logging.log4net.cs index 3aa373858a8..f72c169aef3 100644 --- a/src/NHibernate/Logging.log4net.cs +++ b/src/NHibernate/Logging.log4net.cs @@ -14,30 +14,25 @@ public class Log4NetLoggerFactory: ILoggerFactory #pragma warning restore 618 { internal static readonly Assembly Log4NetAssembly; - internal static readonly Exception LogManagerTypeLoadException; private static readonly System.Type LogManagerType; private static readonly Func GetLoggerByNameDelegate; private static readonly Func GetLoggerByTypeDelegate; static Log4NetLoggerFactory() { - try - { - LogManagerType = GetLogManagerType(); - Log4NetAssembly = LogManagerType.Assembly; - GetLoggerByNameDelegate = GetGetLoggerByNameMethodCall(); - GetLoggerByTypeDelegate = GetGetLoggerMethodCall(); - } - catch (Exception ex) - { - LogManagerTypeLoadException = ex; - } + LogManagerType = GetLogManagerType(); + if (LogManagerType == null) + return; + + Log4NetAssembly = LogManagerType.Assembly; + GetLoggerByNameDelegate = GetGetLoggerByNameMethodCall(); + GetLoggerByTypeDelegate = GetGetLoggerMethodCall(); } public Log4NetLoggerFactory() { if (LogManagerType == null) - throw new TypeLoadException("Could not load LogManager type", LogManagerTypeLoadException); + throw new TypeLoadException("Cannot find log4net.LogManager type"); } // Code adapted from ReflectHelper.TypeFromAssembly, which cannot be called directly due @@ -50,20 +45,14 @@ private static System.Type GetLogManagerType() if (type != null) return type; - // Load type from an already loaded assembly - type = System.Type.GetType( + // Load type from an already loaded assembly, or yield null + return System.Type.GetType( typeName.ToString(), // 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); - if (type != null) - return type; - - // Assembly.Load fails if it does not find the assembly. It does not yield null. - var assembly = Assembly.Load(typeName.Assembly); - return assembly.GetType(typeName.Type, true); } #pragma warning disable 618 @@ -141,8 +130,7 @@ static Log4NetLogger() { if (Log4NetLoggerFactory.Log4NetAssembly == null) throw new TypeLoadException( - "Could not load ILog type, LogManager own loading has previously failed", - Log4NetLoggerFactory.LogManagerTypeLoadException); + "Cannot load ILog type, log4net is not found"); var iLogType = Log4NetLoggerFactory.Log4NetAssembly.GetType("log4net.ILog", true); From bf9c312fac13463a021131fee5477edad7b85a7a Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Mon, 19 Nov 2018 22:02:06 +0100 Subject: [PATCH 6/6] Simplify further the change Co-Authored-By: fredericDelaporte <12201973+fredericDelaporte@users.noreply.github.com> --- src/NHibernate/Logging.log4net.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NHibernate/Logging.log4net.cs b/src/NHibernate/Logging.log4net.cs index f72c169aef3..82c72571e37 100644 --- a/src/NHibernate/Logging.log4net.cs +++ b/src/NHibernate/Logging.log4net.cs @@ -39,15 +39,15 @@ public Log4NetLoggerFactory() // to depending on the logger. private static System.Type GetLogManagerType() { - var typeName = new AssemblyQualifiedTypeName("log4net.LogManager", "log4net"); + var typeName = "log4net.LogManager, log4net"; // Try to get the type from an already loaded assembly - var type = System.Type.GetType(typeName.ToString()); + 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.ToString(), + 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.