.net 如果使用了日志外观,是否应在使用IoC/DI时注入日志基础架构?

hgb9j2n6  于 2022-12-01  发布在  .NET
关注(0)|答案(6)|浏览(129)

我正在使用Autofac作为我的IoC,从我所读到的DI主题中,我教过使用“构造函数注入”来显式地暴露类依赖关系......然而,我也在Log 4 Net中使用日志外观(Common.Logging),并且已经创建了Autofac模块来注入它。现在,在我想做一些日志的每个类中,我都有额外的构造函数参数(参见示例#1)......
我想知道在使用日志外观时是否需要记录DI?我知道通过构造函数签名显式地公开依赖项是一个很好的架构。* 但是 * 在日志外观的情况下,我相信以下是正确的:

  • 我仍然可以随时“换出”日志框架
  • 类IMHO并不真正依赖于Logger。如果没有配置日志,则使用NullLogger。这几乎是“如果你需要它,它就可以使用”与“除非你提供它,否则它不会工作”的交易...(参见示例#2)

那么,其他人是怎么想的呢?注入日志外观是不是有点矫枉过正?在这个主题上有一些similar questions,但在更一般的术语(infrastructure)-我主要对日志感兴趣......

// IoC "way"
public class MyController : BaseController
{
    private readonly ILog _logger;

    public MyController(ILog logger)
    {
        _logger = logger;
    }

    public IList<Customers> Get()
    {
        _logger.Debug("I am injected via constructor using some IoC!");
    }
}

// just use the logger "way"
public class MyController : BaseController
{
    private static readonly ILog Logger = LogManager.GetCurrentClassLogger();

    public IList<Customers> Get()
    {
        Logger.Debug("Done! I can use it!");
    }
}
9njqaruj

9njqaruj1#

日志只是基础设施。注入它是多余的。我个人甚至不使用抽象层。我直接使用库提供的静态类。我的动机是我不太可能在当前项目中切换日志库(但可能会在下一个项目中切换)。
但是,您在示例中使用的是控制器,为什么需要登录控制器?控制器只是视图和模型(业务逻辑)之间的适配器,应该没有登录的必要。
您通常只登录包含业务逻辑的类,并在顶层记录未处理的异常。这些是调试困难的情况,因此需要记录的地方。
必须在其他位置登录表明您需要重构以正确封装业务逻辑。

cxfofazt

cxfofazt2#

这可能是一个较老的职位,但我想插话。
认为测井系统的控制成本过高的想法是短视的。
日志记录是一种机制,应用程序开发人员可以通过它与其他系统(事件日志、平面文件、数据库等)进行通信,而这些系统现在都是应用程序所依赖的外部资源。
如果我的单元测试代码现在被锁定到一个特定的记录器,我该如何对我的组件的日志进行单元测试?分布式系统通常使用记录器来集中记录源,而不是文件系统上的平面文件。
对我来说,注入一个日志记录器和注入一个数据库连接API或一个外部Web服务没有什么不同。它是应用程序需要的资源,因此应该被注入,这样你就可以测试组件对所述资源的使用模拟所述依赖性的能力,测试独立于日志接收者的组件输出的能力,对强大的单元测试来说是至关重要的。
考虑到IoC容器使这种注入变得很简单,在我看来,* 不 * 使用IoC来注入记录器并不比这样做更有效。

qv7cva1a

qv7cva1a3#

现在,在每个类中,我想做一些日志记录,我有额外的构造函数参数
如果你需要在你的系统中记录很多类,那么你的设计就有问题。要么你记录了太多,要么你违反了单一责任原则,因为记录是一个横切的问题,你不应该用像记录这样的横切问题来扰乱你的类。
半年前我回答了一个(完全不同的)问题,我的回答也适用于你的问题。请阅读这篇文章。

daupos2t

daupos2t4#

我个人认为这是矫枉过正
理想情况下,日志记录的开销应该非常低,因此每个类使用一个静态日志记录器示例似乎是一个更好的解决方案。保持低开销有助于使用调试级别的日志记录进行检测。

u3r8eeie

u3r8eeie5#

在许多应用程序中,由于整个应用程序的体系结构都需要日志记录,因此在任何地方注入日志记录都会使代码变得混乱和复杂。对Logger对象的静态引用是可以的,只要您的Logger具有某种Attach(ILoggerService)机制,您可以在其中为运行环境附加日志服务。然后,静态Logger将这些内容存储在一个集合中,以便在执行日志记录命令时使用。
在运行时引导应用程序时,请附加应用程序所需的日志记录目标(文件、数据库、Web服务等)。
当执行自动测试时,您可以选择不使用日志记录,不附加任何东西(默认情况下)。如果您想分析被测系统的日志记录,您可以在设置测试时附加您自己的ILoggerService instance/subsitute/mock。
像这样的静态Logger应该具有最小的性能问题,并且没有意外的后果,同时通过绕过依赖注入的需要来避免代码混乱。
必须声明的是,您不应该对架构中的每个对象都采用这种静态对象方法;日志记录是一种特殊情况。2通常在代码库中使用静态对象会使维护和测试变得困难,应该避免。

fkaflof6

fkaflof66#

这不是一个可以在任何情况下应用的通用答案,但在C#中还有第三个选项:如果日志记录是可选的,则可以将其转换为事件。

public class MyController : BaseController
{
    public event Action<string> DebugMessage;

    public IList<Customers> Get()
    {
        DebugMessage?.Invoke("Done! I can use it!");
    }
}

这将编写日志的负担转移到了composer(Setter注入导致了Temporal耦合),但是,如果您正在开发小型库,并且希望避免依赖甚至System.Diagnostics.Debug,这可能值得考虑。
您可能希望引入一些接口以使注册更容易:

// Collect this interface with your favorite auto-registering DI container
public interface IDebugMessageEmitter
{
    event Action<string> DebugMessage;
}

public class MyController : BaseController, IDebugMessageEmitter
{
    // ...
}

同样,您可能希望使用IObservable

public interface IDebugEvent
{
    string Message { get; }
}

public class MyController : BaseController, IObservable<IDebugEvent>
{
    // ...
}

相关问题