NLog能否通过c#扩展方法保留调用站点信息?

NLog能否通过c#扩展方法保留调用站点信息?,c#,nlog,C#,Nlog,编辑:虽然类似,但这与关于使用NLog包装器的问题不同。扩展方法添加了另一个间接级别,这使得即使是正确的包装器也会报告错误的调用站点 目前,我在NLog周围使用了日志包装器,我使用了他们在源代码示例中展示的技巧来获取准确的callsite信息。对于我开始的一个新项目,我想创建一个更简单的类,所以我只实现了如下接口: 公共接口ILogger { 作废日志(日志条目); } 然后我创建了一个扩展方法类,如: 公共静态类LoggerExtensions { 公共静态void调试(此ILogger记录

编辑:虽然类似,但这与关于使用NLog包装器的问题不同。扩展方法添加了另一个间接级别,这使得即使是正确的包装器也会报告错误的调用站点

目前,我在NLog周围使用了日志包装器,我使用了他们在源代码示例中展示的技巧来获取准确的callsite信息。对于我开始的一个新项目,我想创建一个更简单的类,所以我只实现了如下接口:

公共接口ILogger
{
作废日志(日志条目);
}
然后我创建了一个扩展方法类,如:

公共静态类LoggerExtensions
{
公共静态void调试(此ILogger记录器,字符串格式,参数对象[]args)
{
logger.Log(新的日志条目(LogLevel.Debug、format、args));
}
...
}
问题是NLog然后将callsite显示为扩展方法,而不是扩展方法的调用者。我四处搜索了一下,但找不到任何关于NLog和扩展方法的信息


在这种情况下,是否可以修复callsite信息?还是在界面本身中包含调试、信息等功能的唯一方法?

编辑:不幸的是,这个答案不再有效。NLog在3.2.0中破坏了这一功能,看起来他们不打算修复它:。

我找到了一个解决办法。虽然与仅针对NLog包装的解决方案不完全相同,但结果是类似的

我没有让ILogger实现者(NLog包装器)简单地将自己的类型传递给NLog,而是创建了一个重载,允许从调用方传递类型:

public void Log( LogEntry entry )
{
    this.Log( this.GetType(), entry );
}

public void Log( Type type, LogEntry entry)
{
    NLogLogger.Log( type, new NLog.LogEventInfo( ... ) );
}
这需要将重载添加到接口中,这使得接口有点难看(并且是特定于NLog的):

然后可以修改扩展方法:

public static class LoggerExtensions
{
    public static void Debug( this ILogger logger, string format params object[] args )
    {
        logger.Log( typeof(LoggerExtensions), LogLevel.Debug, format, args ) );
    }

    ...
}

虽然不像简单地使用包装器那样干净,但这确实允许在保留调用站点信息的同时使用扩展方法。如果有人有更干净的方法,我想看看

日志条目是您自己的类/结构吗?也许您可以向其中添加一个字段/属性来保存记录器类型。在扩展方法中,当创建要发送到ILogger的LogEntry时,使用tyepof(LoggerExtensions)填充LogEntry.LoggerType

因此,您的LoggerExtensions类可能看起来像这样(未编译且未测试):


由于log4net使用类似的方案(查看记录器类型以判断哪个堆栈帧对应于实际调用站点),因此可以编写log4net包装器和相应的log4net包装器扩展方法,如果你这么想的话。

晚会迟到了,但我对这个解决方案有异议,因为我的包装器使用了扩展方法。通过将程序集传递给LogManager,我可以让NLog忽略我的扩展类

    /// <summary>
    /// Bootstrap the wrapper class
    /// </summary>
    static Logger()
    {
        LogManager.AddHiddenAssembly(typeof(LoggingExtensions).Assembly);
    }
不要忘了使用获取LogEventInfo()的重载


正如我在问题中提到的,它与使用包装器不同,我已经在使用包装器了。这不是一个坏主意,它将消除接口中的过载,同时基本上提供相同的解决方案。我想不利的一面是,您将信息放在日志条目中,而这些信息并不是严格意义上的日志条目的一部分,因此激怒了OO诸神。@bj0我的答案被删除了b/c我将其发布到了其他相关问题上。但这又是给你的;它适合我,所以应该适合你。我甚至测试了从LoggerExtensions(我的AddHiddenSassembly)的同一个程序集调用Logger()。看起来您的调用站点信息来自
ActionTests.LoggingTest+LogTest.RunLogTest
,而不是
SettingsHelper
。我的经验也是一样,如果调用站点在程序集中,它会跳过调用站点,并显示Assembly.Derp的第一个调用方。我错过了。你是对的!也许我们需要打开源代码并进行pull-req来解决这个问题。。或者,在一个diff程序集中完全分离Logger()=/更好的是,我正在考虑将loggerType转换为一个参数,然后我可以在NLog方法
私有静态bool IsNonUserStackFrame([NotNull]MethodBase方法,[NotNull]类型loggerType)中传递
这可能比全局设置更干净。它更显式,让您可以更好地控制何时忽略类。但不确定这会对性能产生怎样的影响
public static class LoggerExtensions
{
    public static void Debug( this ILogger logger, string format, params object[] args)
    {
        logger.Log( new LogEntry( typeof(LoggerExtensions), LogLevel.Debug, format, args ) );
    }

    ...
}
    /// <summary>
    /// Bootstrap the wrapper class
    /// </summary>
    static Logger()
    {
        LogManager.AddHiddenAssembly(typeof(LoggingExtensions).Assembly);
    }
ILogger logger = new Logger(typeof(SettingsHelper));
logger.Debug("A test from the same assembly as Logger()");
_logger.Log(typeof(Logger), logEvent);