【问题标题】:How to properly implement ILogger.IsEnabled() in custom logger in ASP.NET Core MVC如何在 ASP.NET Core MVC 的自定义记录器中正确实现 ILogger.IsEnabled()
【发布时间】:2021-08-16 21:22:24
【问题描述】:

我(作为一个新手)正在实现我自己的自定义记录器,以便在 ASP.NET Core MVC 应用程序中使用。我有这个记录器在各个方面都功能工作。但是到目前为止我作弊了一点,即我实现了ILogger.IsEnabled方法如下:

public bool IsEnabled(LogLevel logLevel)
{
    return true;
}

从功能上讲,这很好用,因为框架确保只有在日志级别等于或高于指定级别时才调用Log() 方法。因此,正确的“事物”被记录下来,而较低级别的“事物”没有按预期记录。

但是,我还想在我的代码中支持以下类型的情况,其中_logger 输入为ILogger 并正确注入到我的控制器中:

if (_logger.IsEnabled(LogLevel.Debug))
{
    _logger.LogDebug("This is an expensive message to generate: " +
        JsonConvert.SerializeObject(request));
}

为了使其有效,我的IsEnabled() 方法应该能够知道使用我的LoggerProvider 创建的记录器实例的日志级别是什么,但我不知道如何直接获取该信息,或者如何正确地将其传递给我正在使用的记录器的注入实例。

我能够找到的复杂示例和教程似乎在每种情况下都是针对控制台应用程序类型而不是网络应用程序类型构建的,到目前为止,我未能通过模板化的Startup 弄清楚如何做到这一点ASP.NET MVC 中的类。

如果注入的实例中没有注册记录器正在处理Debug 日志,为了避免不必要的序列化(在我的示例中),停止在我的自定义 IsEnabled() 方法中作弊的最简单和最有效的方法是什么等级?或者您有没有最喜欢的 ASP.NET 核心设置示例或教程可以指点我?

【问题讨论】:

  • 如果您使用 appsettings.{Environment}.json 文件配置日志记录,您可以从 appsettings.{Environment}.json 文件获取当前日志记录级别,并将其添加到您的条件中。参考:Configure logging.
  • 谢谢@ZhiLv - 这是一个好主意,我也考虑过 - 虽然要制作一个非作弊版本,但如果我愿意,我必须循环浏览各种条目的所有排列制定一个通用的解决方案。而且由于大概 .NET 日志记录扩展已经在这样做了,复制整个过程似乎很可惜......

标签: c# asp.net-core logging


【解决方案1】:

您可以查看内置记录器 source code 并了解它们是如何实现的。

简而言之,他们只检查logLevel != LogLevel.None,但根据记录器逻辑,您可能还想检查一些其他配置。例如,DebugLogger logger 还检查 Debugger.IsAttached 属性,EventLogLogger 检查 EventLogSettings.Filter(通过构造函数提供)。

更新

为了使其有效,我的IsEnabled() 方法应该能够知道使用我的LoggerProvider 创建的记录器实例的日志级别是什么,但我不知道如何直接获取该信息,或者如何正确地将其传递给我正在使用的记录器的注入实例。

你可以创建一个ILoggerProvider 的实现,它反过来可以利用依赖注入来获得你想要的配置。如果你想使用选项模式来配置它,你必须按照以下方式做一些事情:

public class MyLoggerProvider : ILoggerProvider
{
    private readonly IOptions<MyLoggerOptions> _options;

    public MyLoggerProvider(IOptions<MyLoggerOptions> options)
    {
        _options = options;
    }

    public ILogger CreateLogger(string name)
    {
        return new MyLogger(name, _options.Value);
    }
}

并且可选地添加一个扩展方法以使注册更容易:

public static class MyLoggerExtensions
{
    public static ILoggingBuilder AddMyLogger(this ILoggingBuilder builder, Action<MyLoggerOptions> configure)
    {
        builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, MyLoggerProvider>());
        LoggerProviderOptions.RegisterProviderOptions<MyLoggerOptions, MyLoggerProvider>(builder.Services);
        builder.Services.Configure(configure);
    }
}

【讨论】:

  • 谢谢,根据您的建议,我查看了此源代码和其他代码。他们在做什么似乎很简单。但也很不完整。我见过一些其他的例子,例如codeproject.com/Articles/1556475/…,它提出了一个更完整的解决方案,但我还没有想出如何将这些普通的.net核心示例应用到asp.net核心场景中。
  • 请记住,框架在将调用转发到您的记录器实现之前已经检查了日志级别配置,因此您无需担心这一点。您只需要实现特定于记录器的逻辑。
  • 感谢@Axel,但请参阅(根据最初的问题)我知道这一点。我只想检查是否有重要或昂贵的操作来生成将被记录的实际消息。根据我的示例,无需序列化如果不发生日志记录将被记录的复杂对象。我的理解是,这正是这种方法成为ILogger 接口一部分的目的......
  • 我明白了...我忽略了那部分。请看一下我的最新编辑。
  • 谢谢@Axel - 最新的编辑很有用而且很有启发性。但我认为这归结为另一位评论者在原始帖子中提出的相同建议 - 即您可以获取此信息并直接从配置中注入它。但是,当然,为了正确地做到这一点,您必须浏览所有排列和覆盖以及如何根据docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/… 在配置中设置日志级别的特殊条件 - MS 必须已经这样做了......这似乎重复的。
猜你喜欢
  • 2020-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
  • 2013-11-25
  • 1970-01-01
相关资源
最近更新 更多