【.NET Core框架】日志(Logging)

简介

在ASP.NET 4.X中,我们通常使用 log4net, NLog 等来记录日志,但是当我们引用的一些第三方类库使用不同的日志框架时,就比较混乱了。而在 ASP.Net Core 中内置了日志系统,并提供了一个统一的日志接口,ASP.Net Core 系统以及其它第三方类库等都使用这个日志接口来记录日志,而不关注日志的具体实现,这样便可以在我们的应用程序中进行统一的配置,并能很好的与第三方日志框架集成。

涉及的nuget包:

Microsoft.Extensions.Logging.Abstractions:抽象定义;
Microsoft.Extensions.Logging:具体实现;

日志提供程序

日志提供程序就是最终为我们输出日志的组件,如:

  • Console
    日志将输出到控制台中。
  • Debug
    日志将通过System.Diagnostics.Debug类进行输出,可以通过VS输出窗口查看。
    在 Linux 上,可以在/var/log/message或/var/log/syslog下找到
  • EventSource
    跨平台日志记录,在Windows上则使用 ETW
  • Windows EventLog
    仅在Windows系统下生效,可通过“事件查看器”进行日志查看。
  • 其他常见的三方日志提供程序:
    • log4net:流行第三方日志记录提供程序,需引用 Microsoft.Extensions.Logging.Log4Net.AspNetCore
    • Serilog:流行第三方日志记录提供程序,需引用 Serilog.AspNetCore
    • NLog: 流行第三方日志记录提供程序,需引用 NLog.Web.AspNetCore

在 Host.CreateDefaultBuilder方法中,默认通过调用ConfigureLogging方法添加了Console、Debug、EventSource和EventLog(仅Windows)共四种日志记录提供程序(Logger Provider)

public static IHostBuilder CreateDefaultBuilder(string[] args)
{
  //省略....
  builder.ConfigureLogging((hostingContext, logging) =>
              {
                  bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
                  if (isWindows)
                  {
                      logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
                  }

                  logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                  logging.AddConsole();
                  logging.AddDebug();
                  logging.AddEventSourceLogger();

                  if (isWindows)
                  {
                      logging.AddEventLog();
                  }

              });
  //省略....
}

如果不想使用默认添加的日志提供程序,我们可以通过ClearProviders清除所有已添加的日志记录提供程序,然后添加自己想要的

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureLogging(logging =>
        {
            logging.ClearProviders()
                .AddConsole();
        });

记录日志

可以使用以下两种方式记录日志:

  • 注入ILogger接口,调用相应方法
  • 注入ILoggerFactory,调用ILoggerFactory.CreateLogger(string categoryName)方法创建ILogger,调用相应方法

一般情况下使用第一种方式就可以,如果想显式的指定categoryName,可以使用ILoggerFactory
在父类中的方法,如果想记录日志,并且类别名称想指定子类名称,可以使用如下方法:

    public class BaseClass
    {
        private ILogger _logger;
        public BaseClass(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger(this.GetType().FullName);
        }
        protected void RecordLog(string log)
        {
            _logger.LogInformation(log);
        }
    }

日志类别:我们创建的每一个日志器都指定了一个类别。它可以是任意的字符串,但是约定使用写入类的完整限定名,如:“WebApp.Controllers.ValueController”。

日志级别(LogLevel)

在我们记录日志时,需要指定日志的级别,用于我们输出日志时进行过滤。比如在测试环境中,我们希望提供非常的详细的日志信息,包括一些敏感信息等,但是在生产环境中,我们希望只记录严重的错误,这时候只需要简单的通过配置文件或AddFilter()方法对日志的过滤级别配置一下就行了。
日志级别按严重程度排序如下:
Trace 、Debug 、Information 、Warning 、Error 、Critical

配置日志

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "Console": {
      "LogLevel": {
        "Default": "Error"
      }
    },
    "Debug": {
      "LogLevel": {
        "Microsoft": "None"
      }
    },
    "EventSource": {
      "LogLevel": {
        "Default": "Trace",
        "Microsoft": "Trace",
        "Microsoft.Hosting.Lifetime": "Trace"
      }
    }
  }
}

Logging结点用于配置日志
Logging.LogLevel:全局配置,对所有日志提供者都有效。Logging.LogLevel结点下的字段是对日志类别设置日志级别

  • Default
    默认情况下,如果分类没有进行特别配置(即没有在LogLevel中配置),则应用Default的配置。
  • Microsoft
    所有分类以Microsoft开头的日志均应用Microsoft的配置。例如,Microsoft.AspNetCore.Routing.EndpointMiddleware类别的日志就会应用该配置。
  • Microsoft.Hosting.Lifetime
    所有分类以Microsoft.Hosting.Lifetime开头的日志均应用Microsoft.Hosting.Lifetime的配置。例如,分类Microsoft.Hosting.Lifetime就会应用该配置,而不会应用Microsoft,因为Microsoft.Hosting.Lifetime比Microsoft更具体。

也可以针对日志提供者进行配置,如上面的Console、Debug、EventSource结点
就像appsettings.{Environment}.jsonappsettings.json之间的关系一样,Logging.{Provider}.LogLevel中的配置将会覆盖Logging.LogLevel中的配置。
例如Logging.Console.LogLevel.Default将会覆盖Logging.LogLevel.Default,Console日志记录器将默认记录Error及其以上级别的日志。
刚才提到了,Windows EventLog比较特殊,它不会继承Logging.LogLevel的配置。EventLog默认日志级别为LogLevel.Warning,如果想要修改,则必须显式进行指定,如:

{
  "Logging": {
    "EventLog": {
      "LogLevel": {
        "Default": "Information"
      }
    }
  }
}

配置的筛选原理

当创建ILogger的对象实例时,ILoggerFactory根据不同的日志记录提供程序,将会:

  1. 查找匹配该日志记录提供程序的配置。如果找不到,则使用通用配置。
  2. 然后匹配拥有最长前缀的配置类别。如果找不到,则使用Default配置。
  3. 如果匹配到了多条配置,则采用最后一条。
  4. 如果没有匹配到任何配置,则使用MinimumLevel,这是个配置项,默认是LogLevel.Information。

通过程序配置

除了通过配置文件对日志配置,也可以通过程序配置,允许你书写复杂的逻辑

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureLogging(logging =>
        {
            logging
                // 针对所有 LoggerProvider 设置 Microsoft 最小日志级别,建议通过配置文件进行配置
                .AddFilter("Microsoft", LogLevel.Trace)
                // 针对 ConsoleLoggerProvider 设置 Microsoft 最小日志级别,建议通过配置文件进行配置
                .AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Debug)
                // 针对所有 LoggerProvider 进行过滤配置
                .AddFilter((provider, category, logLevel) =>
                {
                    // 由于下面单独针对 ConsoleLoggerProvider 添加了过滤配置,所以 ConsoleLoggerProvider 不会进入该方法
                    if (provider == typeof(ConsoleLoggerProvider).FullName
                        && category == typeof(ValuesController).FullName
                        && logLevel <= LogLevel.Warning)
                    {
                        // false:不记录日志
                        return false;
                    }

                    // true:记录日志
                    return true;
                })
                // 针对 ConsoleLoggerProvider 进行过滤配置
                .AddFilter<ConsoleLoggerProvider>((category, logLevel) =>
                {
                    if (category == typeof(ValuesController).FullName
                        && logLevel <= LogLevel.Warning)
                    {
                        // false:不记录日志
                        return false;
                    }

                    // true:记录日志
                    return true;
                });
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

控制台日志格式配置

在.NET 5中,对控制台日志记录提供程序进行了扩展,预置了三种日志输出格式:Json、Simple、Systemd。
通过扩展方法AddSimpleConsole()可以添加支持Simple格式的控制台日志记录提供程序,默认行为与AddConsole()一致。

.ConfigureLogging(logging =>
{
    logging.ClearProviders()
        .AddSimpleConsole();
}

你可以通过SimpleConsoleFormatterOptions进行一些自定义配置:

.ConfigureLogging(logging =>
{
    logging.ClearProviders()
        .AddSimpleConsole(options => 
        {
            // 一条日志消息展示在同一行
            options.SingleLine = true;
            options.IncludeScopes = true;
            options.TimestampFormat = "yyyy-MM-dd HH:mm:ss ";
            options.UseUtcTimestamp = false;
        });
}

通过扩展方法AddSystemdConsole()可以添加支持Systemd格式的控制台日志记录提供程序。如果你熟悉Linux,那你对它也一定不陌生。

.ConfigureLogging(logging =>
{
    logging.ClearProviders()
        .AddSystemdConsole();
}

通过扩展方法AddJsonConsole()可以添加支持Json格式的控制台日志记录提供程序。

.ConfigureLogging(logging =>
{
    logging.ClearProviders()
        .AddJsonConsole(options =>
        {
            options.JsonWriterOptions = new JsonWriterOptions
            {
                // 启用缩进,看起来更舒服
                Indented = true
            };
        });
}

参考:
https://www.cnblogs.com/xiaoxiaotank/p/15525052.html
https://www.cnblogs.com/RainingNight/tag/Logging/

posted @ 2020-09-12 16:58  .Neterr  阅读(707)  评论(0编辑  收藏  举报