2013-05-03 78 views
0

编辑:虽然相似,这与关于使用NLog包装的问题不一样。扩展方法增加一个间接的另一个层面,这使得即使是适当的包装报告错误调用点NLog可以通过c#扩展方法保存callsite信息吗?

我目前使用的是日志来包裹NLOG,我用他们的例子显示的把戏在他们的来源得到准确调用点信息。对于一个新项目,我开始,我想创建一个简单的类,所以我只是实现类似如下界面:

public interface ILogger 
{ 
    void Log(LogEntry entry); 
} 

然后,我创建了一个扩展方法类,如:

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

    ... 
} 

的问题在于NLog然后将该调用站点显示为扩展方法而不是扩展方法的调用者。我做了一些搜索,但找不到有关NLog和扩展方法的任何信息。

在这种情况下是否可以修复现场信息?或者是在接口本身中包含Debug,Info等功能的唯一方法?

+0

可能重复[如何保留wr时的callsite信息(http://stackoverflow.com/questions/7412156/how-to-retain-callsite-information-when-wrapping-nlog) – 2013-05-03 20:04:11

+0

正如我在问题中提到的,它不同于使用包装器,我是已经在做 – bj0 2013-05-03 20:15:00

回答

1

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

我找到了解决方法。虽然不完全相同到只是一个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 interface ILogger 
{ 
    void Log(LogEntry entry); 
    void Log(Type type, LogEntry entry); 
} 

然后扩展方法可以被修改:

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

    ... 
} 

尽管不如简单地使用包装器那样干净,但它确实允许在保留调用点信息的同时使用扩展方法。如果有人有更清晰的方式,我想看看它。

0

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

所以,你LoggerExtensions类可能是这个样子(未编译和未经测试):

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)); 
    } 

    ... 
} 

由于log4net的使用相似的方案(看着记录器类型来告诉它堆栈帧对应的实际调用你可以编写一个log4net包装器和相应的log4net包装器扩展方法,如果你这么倾向的话。

+0

这不是一个坏主意,它可以消除接口过载,同时提供相同的解决方案。我认为不利的一面是,你将信息放在LogEntry中,这不是日志条目的一部分,因此会激怒OO神。 – bj0 2013-05-07 17:38:10

8

晚会晚会,但我有这个解决方案的问题,因为我使用扩展方法为我的包装。通过将程序集传递给LogManager,我能够让NLog忽略我的扩展类。

/// <summary> 
    /// Bootstrap the wrapper class 
    /// </summary> 
    static Logger() 
    { 
     LogManager.AddHiddenAssembly(typeof(LoggingExtensions).Assembly); 
    } 

没有从非

增加给定程序将在NLOG试图找到堆栈跟踪调用方法跳过其他的文档的细节。

NLog Documentation

在此设置下,我甚至设法扩展方法+ DI与SimpleInjector工作。

为了显示你仍然可以使用连同SettingsHelper() 我的设置与SettingsHelper输出测试这种方法

我的记录器()住在公用事业项目具有相同的组件内的调用点:

2015-08-18 20:44:07.5352 | vstest.executionengine.x86 |调试| Utilities.Settings.SettingsHelper |来自与Logger()|相同组件的测试ActionTests.LoggingTest + LogTest.RunLogTest

大胆位是$ {}调用点

我SettingsHelper()测试:

ILogger logger = new Logger(typeof(SettingsHelper)); 
logger.Debug("A test from the same assembly as Logger()"); 

也不要忘了使用过载需要LogEventInfo()

_logger.Log(typeof(Logger), logEvent); 
+0

@ bj0我的答案已删除b/c我将其发布到其他相关问题。但是,这又是为了你;它适用于我,所以它应该适合你。我甚至从与LoggerExtensions(我的** AddHiddenAssembly **)相同的程序集中调用Logger() – diZzyCoDeR 2015-08-19 12:21:11

+0

看起来您的调用站点信息来自ActionTests.LoggingTest + LogTest.RunLogTest,而不是来自SettingsHelper '''。我的经验是相同的,如果它位于装配体内部并显示装配体的第一个呼叫者,则跳过该呼叫点。 – bj0 2015-08-19 17:39:47

+0

Derp。我错过了。你是对的!也许我们需要破解源代码,并提出一个拉请求来解决这个问题..或者,将Logger()完全分散在一个diff程序集里=/ – diZzyCoDeR 2015-08-19 17:42:09