【问题标题】:ILogger.Log method declaringType parameterILogger.Log 方法声明类型参数
【发布时间】:2015-05-30 00:53:54
【问题描述】:

当我想使用 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 引用上调用该方法。更重要的是,扩展方法中的声明类型将是包含扩展方法的类。使用 Log4NetExtensions 之类的类名记录所有 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?

【问题讨论】:

    标签: c# log4net


    【解决方案1】:

    您传递给LogManager.GetLogger 的类型用于命名返回的记录器,这就是为什么您的所有记录调用都标记为“Foo.Program”。

    虽然传递给Logger.Log 的类型是“在此调用的日志系统中作为堆栈边界的方法的声明类型”,并用于确定停止记录堆栈的位置trace - 内部需要,否则堆栈跟踪将包含 log4net 内部方法。

    您当然可以创建一个将 null 作为callerStackBoundaryDeclaringType 传递的扩展方法,因为它在内部默认为typeof(Logger)

    【讨论】:

    • this: “因为它将在内部默认为记录器的类型。”这就是我一直在寻找的。有参考吗?或者关于如何测试的任何建议? log4net 什么时候产生堆栈跟踪?当我传入异常时?但是异常不是有自己的堆栈跟踪吗?
    • 你是对的,异常有自己的堆栈跟踪:log4net 也是allows the stack trace to be included in the pattern,但回想起来这不是一个常见的用例——关于参考,我查看了源代码,lines 428 and 725跨度>
    【解决方案2】:

    您不应该像您建议的那样创建扩展方法。

    因为 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”-Method 是没有意义的。

    此外,当您记录某些内容时(通常)设置类型没有意义,但仅在初始化 Logger 时设置在类的顶部

    【讨论】:

    • 扩展方法将被多个类使用,每个类都有自己的 ILog 引用,以您也建议的通常方式声明。另外,我希望使用 Level.Trace 记录消息,它没有 ILog 提供的标准方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-22
    相关资源
    最近更新 更多