ILogger.Log 方法声明类型参数
ILogger.Log method declaringType parameter
当我想使用 log4net 可用的不同日志记录级别时,我发现我需要使用方法 ILogger.Log,它看起来像这样:
void Log(Type callerStackBoundaryDeclaringType, Level level, object message, Exception exception);
我们可以从我们通常的 ILog 引用中获取一个 ILogger 引用来调用这个方法,通常建议将这个调用包装在一个扩展方法中。我们得到的是:
//typical log4net ILog reference
private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
//suggested extension method
public static void Trace(this ILog logger, object message, Exception e)
{
logger.Logger.Log(MethodBase.GetCurrentMethod().DeclaringType, log4net.Core.Level.Trace, message, e);
}
我注意到获取声明类型的反射调用看起来是多余的。当我们检索 ILog 引用时,我们已经将声明类型传递给 GetLogger。为什么我们需要将另一个类型引用传递给方法 Log,我们在从 ILog 引用中检索到的 ILogger 引用上调用该方法。更重要的是,扩展方法中的声明类型将是包含扩展方法的 class。使用像 Log4NetExtensions 这样的 class 名称记录所有 Trace 日志是没有意义的。最后,反射应该是昂贵的,即使反射当前方法可能更便宜,但每次我们记录时调用反射代码听起来并不正确。所以我决定做一个测试:
//I just created a logger
var logger = logManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
//and then I called Log with different type parameters
logger.Logger.Log(MethodBase.GetCurrentMethod().DeclaringType, log4net.Core.Level.Info, "hello!", null);
logger.Logger.Log(logger.GetType(), log4net.Core.Level.Info, "hello!", null);
logger.Logger.Log(null, log4net.Core.Level.Info, "hello!", null);
logger.Logger.Log(typeof(System.Console), log4net.Core.Level.Info, "hello!", null);
生成的日志如下所示:
INFO 2015-05-29 11:06:57,200 [9] Foo.Program - hello!
INFO 2015-05-29 11:06:57,207 [9] Foo.Program - hello!
INFO 2015-05-29 11:06:57,207 [9] Foo.Program - hello!
INFO 2015-05-29 11:06:57,207 [9] Foo.Program - hello!
因此,似乎忽略了此方法的类型参数。这很令人费解。谁能证实或否认这些结果?有谁知道为什么会这样工作?我打算为此参数创建带有 null 的扩展方法。你会建议相同吗?我错过了什么吗?
以下问题的答案建议在扩展方法中使用声明类型:
Log4net creating custom levels
Why isn't there a trace level in log4Net?
Log4net, how to log a verbose message?
您不应该像您建议的那样创建扩展方法。
因为 ILog Logger 是静态的,所以将它用作参数值没有多大意义。只需按以下方式使用 Log4Net:
private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // that part was ok
public static void Trace(object message, Exception e)
{
Logger.DebugFormat(message, e); // Use InfoFormat or something else if needed
}
如果您只使用标准功能,只需直接调用 DebugFormat()(或其他方式):
try {
int i=7/0;
} catch (Exception e){
Logger.ErrorFormat("Looks like you are not Jon Skeet",e);
}
创建自己的 "Trace" 方法没有任何意义,如果您不向其中添加任何内容。
此外,当您记录某些内容时设置类型(通常)没有意义,但仅在初始化记录器
时在class之上
您传递给 LogManager.GetLogger
的类型用于命名返回的记录器,这就是为什么您的所有记录调用都标记为 'Foo.Program'。
尽管传递给 Logger.Log
的类型是“方法的声明类型,它是此调用的日志系统中的堆栈边界”并且用于确定在何处停止记录堆栈跟踪 - 这在内部是必需的,否则堆栈跟踪将包含 log4net 内部方法。
您当然可以创建一个将 null 作为 callerStackBoundaryDeclaringType
传递的扩展方法,因为它将在内部默认为 typeof(Logger)
。
当我想使用 log4net 可用的不同日志记录级别时,我发现我需要使用方法 ILogger.Log,它看起来像这样:
void Log(Type callerStackBoundaryDeclaringType, Level level, object message, Exception exception);
我们可以从我们通常的 ILog 引用中获取一个 ILogger 引用来调用这个方法,通常建议将这个调用包装在一个扩展方法中。我们得到的是:
//typical log4net ILog reference
private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
//suggested extension method
public static void Trace(this ILog logger, object message, Exception e)
{
logger.Logger.Log(MethodBase.GetCurrentMethod().DeclaringType, log4net.Core.Level.Trace, message, e);
}
我注意到获取声明类型的反射调用看起来是多余的。当我们检索 ILog 引用时,我们已经将声明类型传递给 GetLogger。为什么我们需要将另一个类型引用传递给方法 Log,我们在从 ILog 引用中检索到的 ILogger 引用上调用该方法。更重要的是,扩展方法中的声明类型将是包含扩展方法的 class。使用像 Log4NetExtensions 这样的 class 名称记录所有 Trace 日志是没有意义的。最后,反射应该是昂贵的,即使反射当前方法可能更便宜,但每次我们记录时调用反射代码听起来并不正确。所以我决定做一个测试:
//I just created a logger
var logger = logManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
//and then I called Log with different type parameters
logger.Logger.Log(MethodBase.GetCurrentMethod().DeclaringType, log4net.Core.Level.Info, "hello!", null);
logger.Logger.Log(logger.GetType(), log4net.Core.Level.Info, "hello!", null);
logger.Logger.Log(null, log4net.Core.Level.Info, "hello!", null);
logger.Logger.Log(typeof(System.Console), log4net.Core.Level.Info, "hello!", null);
生成的日志如下所示:
INFO 2015-05-29 11:06:57,200 [9] Foo.Program - hello!
INFO 2015-05-29 11:06:57,207 [9] Foo.Program - hello!
INFO 2015-05-29 11:06:57,207 [9] Foo.Program - hello!
INFO 2015-05-29 11:06:57,207 [9] Foo.Program - hello!
因此,似乎忽略了此方法的类型参数。这很令人费解。谁能证实或否认这些结果?有谁知道为什么会这样工作?我打算为此参数创建带有 null 的扩展方法。你会建议相同吗?我错过了什么吗?
以下问题的答案建议在扩展方法中使用声明类型:
Log4net creating custom levels
Why isn't there a trace level in log4Net?
Log4net, how to log a verbose message?
您不应该像您建议的那样创建扩展方法。
因为 ILog Logger 是静态的,所以将它用作参数值没有多大意义。只需按以下方式使用 Log4Net:
private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // that part was ok
public static void Trace(object message, Exception e)
{
Logger.DebugFormat(message, e); // Use InfoFormat or something else if needed
}
如果您只使用标准功能,只需直接调用 DebugFormat()(或其他方式):
try {
int i=7/0;
} catch (Exception e){
Logger.ErrorFormat("Looks like you are not Jon Skeet",e);
}
创建自己的 "Trace" 方法没有任何意义,如果您不向其中添加任何内容。
此外,当您记录某些内容时设置类型(通常)没有意义,但仅在初始化记录器
时在class之上您传递给 LogManager.GetLogger
的类型用于命名返回的记录器,这就是为什么您的所有记录调用都标记为 'Foo.Program'。
尽管传递给 Logger.Log
的类型是“方法的声明类型,它是此调用的日志系统中的堆栈边界”并且用于确定在何处停止记录堆栈跟踪 - 这在内部是必需的,否则堆栈跟踪将包含 log4net 内部方法。
您当然可以创建一个将 null 作为 callerStackBoundaryDeclaringType
传递的扩展方法,因为它将在内部默认为 typeof(Logger)
。