【问题标题】:Logging from static members with Microsoft.Extensions.Logging使用 Microsoft.Extensions.Logging 从静态成员进行日志记录
【发布时间】:2017-09-29 06:34:34
【问题描述】:

根据https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging,建议使用Microsoft.Extensions.Logging 的方法似乎是通过ILogger 对象的依赖注入。

在依赖注入不起作用(或无法正常工作)的情况下,建议的模式是什么,例如在扩展方法、类型初始化程序、静态属性和其他静态成员中传递 ILogger 会是很麻烦?

使用 log4net(我的团队以前使用过),一个常见的模式是这样的:

public static class SomeExtensions
{
  private static readonly ILog s_log = LogManager.GetLogger(typeof(SomeExtensions));

  public static void ExtensionMethod (this SomeType someType)
  {
    s_log.Info("...");
  }
}

Microsoft.Extensions.Logging 是否有类似的既定或推荐模式?

【问题讨论】:

  • 我首先想到的是工厂。希望这篇文章对stackify.com/net-core-loggerfactory-use-correctly有帮助。
  • 要么使用服务定位器 anit-pattern,要么公开一个可以在启动期间配置的公共静态成员,以允许静态类按需要运行。
  • @AlexandrePires 感谢您的链接,我可能会选择“位于中心的静态类”选项。
  • @Nkosi 是的,我实际上想知道Microsoft.Extensions.Logging 是否存在既定模式。 (如“大多数人使用服务定位器”或“ASP.NET Core 团队建议使用在启动期间配置的单例”。)
  • @DmitryPavlov 这个问题似乎没有提到从静态位置进行日志记录。

标签: logging asp.net-core


【解决方案1】:

感谢@chris-pratt 和@shad pointing out ASP.NET Core 记录器方法不能很好地与静态和实际上 finding according documentation 配合使用。

但是,在某些情况下,避免静态是困难的或(主观上)不可取的。所以我的问题的重点是询问在这种情况下是否有任何既定的模式可以使用Microsoft.Extensions.Logging

该问题的唯一真正答案是@alexandre-pires 在a comment 中,他将我指向this Stackify article。除其他外,它还展示了如何设置可在静态上下文中使用的集中式ILoggerFactory。但是,它的结论是继续使用 NLog 或 Serilog 并将 Microsoft.Extensions.Logging 转发到该库。

【讨论】:

    【解决方案2】:

    DI 在静态方面表现不佳。从某种意义上说,它们是一种对立的设计哲学。 ASP.NET 大量使用了静态(HttpContext,有人知道吗?),这使得使用依赖注入非常在许多方面都变得困难。 ASP.NET Core 选择避开静态并采用 100% DI 模型。

    简而言之,如果你想使用依赖注入,你对静态的使用应该消失。在大多数情况下,这实际上是一件非常好的事情。虽然它们对于某些被滥用的事情可能很有用,但在大多数情况下非常有用。在单例范围内使用依赖注入类时,您无法对静态进行任何操作,而后者为您提供了更大的抽象性和可重用性。

    无法真正替代静态的一种用途是扩展。当然,有一个完整的学派认为你不应该使用扩展,无论如何。但是,如果您需要或想要拥有扩展,那么您要么无法从这些中登录,要么您必须将记录器实例作为参数传递。在许多情况下,必须传入记录器会严重限制扩展的实用性,因此您可能会完全不记录。然而,即使你是相信扩展是好的和花花公子的学校,大多数人也会同意它们也应该在范围内受到限制:即他们应该只做一些不需要大量代码的简单事情。如果是这样的话,实际记录的需求就会大大减少。

    总而言之,它归结为您必须做出的设计决策。如果你想走依赖注入路线,静态将成为你家的瘟疫,你应该避免它们。

    【讨论】:

    • 感谢您的设计讨论。我的问题实际上是关于在静态上下文中使用 Microsoft.Extensions.Logging 是否有任何建议或已建立的模式(例如,对于 log4net)。从到目前为止的 cmets 和答案中,我推断似乎没有一个。当然,避免静电通常有助于避免问题。但在大型应用程序中,至少在某些情况下,从静态上下文进行日志记录是有用或必要的,我想知道其他人是如何做到这一点的。
    • 嗯,这取决于。据推测,如果您是添加日志记录的人,那么您也是负责相关代码的人。我的观点是,如果你想走 DI 路线,你不应该编写静态代码。然后否定了这个问题。这只是一种方法,如果你想使用静态,那么你应该使用 Common.Logging 之类的东西。但是,我可以说,至少对我来说,如果你从完全避免静态的前提下开始,代码质量、可测试性等都会得到显着改善。
    【解决方案3】:

    你可以像这样使用 Serilog:

    using Serilog;
    
    private static readonly ILogger log = Log.ForContext(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
    

    【讨论】:

    • 谢谢,这是个好主意。但是,我问的是Microsoft.Extensions.Logging 的类似成语或做法。
    • 是的,对不起,我不是要直接回答你的问题。我只是认为这对寻求快速解决您的问题的其他人会有所帮助(我也遇到了同样的问题)。
    【解决方案4】:

    TLDR:不,永远不要反对任何关于的建议,而且大多数情况下它表明永远不要使用或使用最少的静态实例在 .NET Core 中。

    === 编辑 ===

    推荐的方法是不要使用静态或直接实例化,而是更喜欢正确的 DI 或生命周期指令。 DOC here

    加长版

    对于静态类,我讨论了如何在不依赖 DI 的情况下设置 Logger,以及静态类的 DI 有多糟糕。

    从讨论中可以看出,NET Core 应用程序中不需要静态,必须在生命周期中仔细管理。

    由于 Logger 扩展是在 NET Core 中使用 DI 的典型中间件,因此(据我所知)没有推荐的在静态类中构建它的方法,因为“按设计”它不是故意的。

    所以你最好自己滚动或重复使用另一个记录器。

    如果有帮助,这里是构建没有 DI 的 Logger 的方法(但仍然不是静态的):

    private readonly ILoggerFactory _logfactory;
    private readonly ILogger _logger;
    
    ==== IN CONSTRUCTOR
    _logfactory = (ILoggerFactory) new LoggerFactory();
    _logger = new Logger<YourClass>(_logfactory);
    

    显然,您可以通过不储存 ILoggerFactory 来简化它。

    希望它能回答你的问题。

    ===== 编辑 ======

    我在生命周期文档中找到了执行我之前所说的句子:link here

    这句话是:

    最佳做法是:

    • 设计服务以使用依赖注入来获取它们的依赖。
    • 避免有状态的静态类和成员。将应用设计为使用单例服务,从而避免创建全局状态。
    • 避免在服务中直接实例化依赖类。直接实例化将代码与特定实现相结合。
    • 使应用程序类更小、结构合理且易于测试。

    所以我认为,由于它是官方的 Microsoft 文档,因此它是关于该主题的最后一点。

    【讨论】:

    • 我遇到了一个关于如何在不依赖 DI 的情况下设置 Logger 的讨论,以及静态类的 DI 有多糟糕 您能否发布该讨论的链接,好吗?
    • 对不起,我已经搜索了几个小时,没有抓住它:/。它在 Microsoft 论坛上。
    • @FabianSchmied 答案已更新,我找到了上述文档 :) 我遇到的对话是在谈论这一点。
    猜你喜欢
    • 1970-01-01
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    • 2016-04-26
    • 2012-05-11
    • 2011-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多