【发布时间】:2011-10-05 19:01:02
【问题描述】:
因此,我对此进行了大量研究,但在我说“是的,那个”的地方没有找到任何答案。我希望博学多才的 StackOverflow 人群可以帮助我。
我在几个不同的场景中遇到过这个问题。假设我有一个 C# 应用程序,并且有一些重要的事情要记录。
public class MyClass
{
...
public void ImportantMethod()
{
DoInterestingThing();
var result = SomethingElseImportant();
if (result == null)
{
logger.Log("I wasn't expecting that. No biggie.");
return;
}
MoreInterestingStuff();
}
我感兴趣的是我从哪里得到logger。
在我看来,我有几个选择。
- 在构造函数中将其注入到 MyClass 中。
- 使用全球可用的服务定位器检索它。
- 使用方法装饰器和 AOP 为我完成日志记录。
这些似乎都不是很好的选择。 #3 看起来是不可能的,因为我在我的业务逻辑中间记录,而不仅仅是对我的方法调用、输入参数和/或抛出的异常进行简单的跟踪。 #2,虽然看起来很简单,但单元测试真的很难。当然,我想对所有内容进行单元测试。 #1,虽然它可以正常工作,但我所有的业务逻辑都被记录对象弄乱了与业务对象本身无关。
关于上述选项之一的任何替代想法或想法? 非常感谢!
编辑:为了清楚起见,我已经知道如何进行 DI(我使用 Unity),并且我已经知道一个好的日志框架(我使用 log4net)。只是想知道如何以最智能的方式在整个应用程序中使用架构意义上的日志记录。
* 编辑 *
我将 Mark Seeman 的答案标记为解决方案。我浏览了我的应用程序,发现我的大部分日志调用都在做装饰器可以做的事情。即,记录方法的条目、抛出的任何异常以及退出返回值。
在某些情况下,我仍然需要直接在方法中记录。一个例子是我想在一个不返回任何东西但不返回 throw an Exception 的方法中快速失败。在这些情况下,我有一个单例,它持有一个引用 LogProvider,它反过来会检索一个命名的日志实例。代码如下所示:
private ILog logger = LogProviderFactory.Instance.GetLogger(typeof(Foo));
LogProviderFactory 有一个方法SetProvider,它允许你换出单例。所以在单元测试中我可以做到:
// LogProviderFactory.Instance now is our mock
LogProviderFactory.SetProvider(MockLogProvider);
日志装饰器使用与单例相同的 LogProvider(通过注入获得),因此日志在整个系统中是统一的。
所以实际上最终的解决方案主要是选项 #3 和混合 #2(它是服务定位器模式,但服务被“注入”到定位器中)。
AOP
就“面向方面的编程”而言,我对该语言的局限性感到有点失望。希望 AOP 在未来的版本中被视为一等公民。
- 我尝试了 PostSharp,但无法让它在我的机器上正确运行。此外,您必须在系统上安装 PostSharp 才能使用它(而不是仅调用解决方案随附的 dll 或类似的东西),这是一个很大的限制。
- 我使用了 LinFu 并且能够使其部分工作。然而,它在少数情况下爆炸了。新的 2.0 版本几乎没有文档记录,所以这是一个障碍。
- 然而,Unity 的接口拦截似乎开箱即用。我很幸运,我想记录的大部分内容都在实现接口的类中。
【问题讨论】:
-
始终密切关注您是否需要记录某些内容,或者只是通过抛出异常快速失败。快速摆脱困境往往比您预期的要好。
-
好点史蒂文!在我最近的应用程序中,我需要放入一些不一定与异常/错误相关的日志记录。诸如“收到新消息”或“添加用户”之类的内容。不是调试语句本身,而是有关应用程序执行以保存记录的信息。
标签: architecture logging dependency-injection service-locator cross-cutting-concerns