我应该如何在我的应用程序中构建日志?

Oni*_*mus 5 architecture logging dependency-injection cross-cutting-concerns service-locator

所以我对此做了很多研究,并没有找到任何答案,我说,"是的,那就是".我希望那些博学多才的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(); 
}
Run Code Online (Sandbox Code Playgroud)

我感兴趣的事情是我在哪里得到logger.

我看到它有几个选择.

  1. 将它注入到构造函数中的MyClass中.
  2. 使用全局可用的服务定位器检索它.
  3. 使用方法装饰器和AOP为我完成日志记录.

这些似乎都不是很好的选择.#3看起来是不可能的,因为我正在我的业务逻辑中间进行记录而不只是简单地跟踪我的方法调用,输入参数和/或引发的异常.#2,虽然简单似乎很难进行单元测试.当然,我想要对所有内容进行单元测试.#1,虽然它可以正常工作,但是使用与业务对象本身无关的日志记录对象会使我的所有业务逻辑变得混乱.

关于上述选项之一的任何其他想法或想法?非常感谢!

编辑:只是要清楚,我已经知道如何做DI(我使用Unity),我已经知道一个很好的日志框架(我使用log4net).只是想知道如何以最智能的方式在应用程序中使用体系结构意义上的日志记录.


*编辑*

我将Mark Seeman的答案标记为解决方案.我浏览了我的应用程序,发现我的大多数日志记录调用都是装饰者可以做的事情.即,记录方法的条目,抛出任何异常,并退出返回值.

在某些情况下,我仍然需要直接在方法内部进行记录.一个例子是我希望在一个方法中快速失败的方法,该方法不返回任何东西但不抛出异常.在这些情况下,我有一个包含引用的单例,LogProvider它将依次检索一个命名的日志实例.代码看起来类似于:

private ILog logger = LogProviderFactory.Instance.GetLogger(typeof(Foo));
Run Code Online (Sandbox Code Playgroud)

LogProviderFactory有一个SetProvider允许你换出单例的方法.所以在单元测试中,我可以这样做:

// LogProviderFactory.Instance now is our mock
LogProviderFactory.SetProvider(MockLogProvider);
Run Code Online (Sandbox Code Playgroud)

日志记录装饰器使用与单例(它通过注入获得)相同的LogProvider,因此日志记录在整个系统中统一.

所以最终的解决方案主要是选项#3和混合#2(其中它是服务定位器模式,但服务被'注入'到定位器中).

AOP

就"面向方面的编程"而言,我对语言的局限性感到有些失望.希望AOP在未来版本中被视为一等公民.

  • 我试过PostSharp但是无法正确地在我的机器上运行它.此外,您必须在系统上安装PostSharp才能使用它(而不是仅仅调用解决方案附带的dll或类似的东西),这是一个很大的限制.
  • 我使用LinFu并且能够使其部分工作.然而,它在少数情况下爆炸了.新的2.0版本几乎没有记录,因此这是一个障碍.
  • 然而,与Unity的接口拦截似乎开箱即用.我很幸运,我想记录的大部分内容都是在实现接口的类中.

Mar*_*ann 5

使用日志 装饰器

  • @Onisemus:这就是拦截的用武之地。 (2认同)
  • +1 @Onisemus:我不相信你已经正确阅读了链接的文章并建议重新阅读以获取拦截点 (2认同)
  • 如果有的话,注入的日志依赖项是唯一的方法,但我认为在很多情况下您应该从方法内部进行日志记录。但永远不要说永远:) (2认同)