在 .NET Core 和 ASP.NET Core 中使用 Serilog

目录

    • 前言:
    • 一、配置基础
    • 二、 格式化输出
        • 1) 设置纯文本的格式
        • 2) 设置格式为JSON
        • 3) 格式提供程序
    • 三、过滤器
    • 四、在 ASP.NET Core 中引入 Serilog

    • 参考文档

前言:

本文使用 .NET Core SDK 3.1Serilog 3.1.2 的版本。
与.NET的其他日志记录库不同,在 Serilog 中和日志消息一起传递的参数不会破坏性地呈现为文本格式,而是作为机构化数据保留。

SerilogNuGet 包中,Serilog.AspNetCore 是所有常用包的集合。
所以你不管是控制台程序还是Web程序直接引入 Serilog.AspNetCore 即可:

	PM> Install-Package Serilog.AspNetCore -Version 3.1.2

一、配置基础

该示例在控制台运用程序中运行

#region Main Function
    var log = new LoggerConfiguration()
        .MinimumLevel.Debug()
        .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
        .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information)
        .WriteTo.File(path: "../../../logs/log_.txt", rollingInterval: RollingInterval.Day)
        .CreateLogger();
    
    log.Verbose("this is Verbose.");
    
    Log.Logger = log;
    
    Log.Verbose("this is Verbose.");
    Log.Debug("this is Debug.");
    Log.Information("this is Information.");
    
	Log.CloseAndFlush(); // 初始化 Serilog 的所有配置
#endregion

我们在创建 logger 时,需要使用 LoggerConfiguration 对象。

可以使用 WriteTo 来配置日志的接收器,这里将其配置到了控制台和文本文件中,这里文件的记录周期设置为每天。

执行代码我们发现控制台中只显示了最后一条日志记录,而文件中记录了最后两条日志记录,
Serilog 中有 最低级别 的概念,可以直接使用 MinimumLevel 以配置 Serilog 所有日志接收器的接受等级。
也可以在 接收器 中单独配置 最低级别,一律使用 restrictedToMinimumLevel 参数,这里对控制台接收器进行了单独配置。

二、 格式化输出

在== Serilog== 中有不同的输出格式设置

1) 设置纯文本的格式

在控制台或者文本文件的接收器中,通常都能够使用 outputTemplate 参数来控制日志事件数据的格式设置方式。

#region
    Log.Logger = new LoggerConfiguration()
        .WriteTo.Console(outputTemplate:
        "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
        .CreateLogger();
#endregion

输出模板中有许多内置属性:

  • Timestamp - 当前日志记录的时间
  • Level - 日志时间的级别,可以切换大小写 {Level:u3} {Level:w3}
  • Message - 日志的信息,以本文呈现,格式设置可以使嵌入的数据使用JSON或者文本格式呈现 :l :j
  • NewLine - 为System.Environment.NewLine的属性,跨平台换行符
  • Exception - 完整异常信息和堆栈跟踪,如果没有传入异常参数则为空。
  • Properties - 所有未出现在输出中其他位置的事件属性值。 以JSON格式显示 :j

事件的属性(包括使用Enrich附加的属性)也可以显示在输出模板中

实现扩充器
扩充器是添加、删除或修改附加到日志事件的属性的简单组件。

#region
    class DateTimeNowEnricher : ILogEventEnricher
    {
        public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
        {
            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(
                    "DateTimeNow", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
        }
    }
#endregion

#endregion
    Log.Logger = new LoggerConfiguration()
     .Enrich.With(new DateTimeNowEnricher())
     .WriteTo.Console(
         outputTemplate: "[{DateTimeNow} {Level}] {Message}{NewLine}{Exception}")
     .CreateLogger();
    
    Log.Information("Test");
#region

在接收器中我们将得到如下:
 ConsoleImg
可以看到自定义的 DateTimeNow 已经生效了。

还可以用 WithProperty 简化配置:

    Log.Logger = new LoggerConfiguration()
        .Enrich.WithProperty("Version", "1.0.0")
        .WriteTo.Console(
         outputTemplate: "[{Timestamp:HH:mm:ss} {Level} {Version}] {Message}{NewLine}{Exception}")
     .CreateLogger();
    
    Log.Information("Test");

在接收器中我们将得到如下:
 ConsoleImg
使用 WithProperty 配置的,将是一个静态值,例如 DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") 是行不通的。

2) 设置格式为JSON

Serilog 中可以配置接收器记录日志为JSON

    Log.Logger = new LoggerConfiguration()
        .WriteTo.Console()
        .WriteTo.File(formatter: new CompactJsonFormatter(), "../../../log.txt")
        .CreateLogger();

在以上代码中执行以后,会发现控制台中的日志并没有变成纯JSON格式,是因为需要接收器单独配置 formatter 参数。

3) 格式提供程序

#region User
    class User
    {
        public int Id { get; set; } = 1;
        public string Name { get; set; } = "雄鹿";
        public DateTime Created { get; set; } = DateTime.Now;
    }
#endregion

#region Main Function
    Log.Logger = new LoggerConfiguration()
     // outputTemplate 默认值为 [{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}
     .WriteTo.Console() 
     .CreateLogger();
    
    var exampleUser = new User { Id = 1, Name = "Adam", Created = DateTime.Now };
    Log.Information("Created {@User} on {Created}", exampleUser, DateTime.Now);
    Log.Information("Created {User} on {Created}", exampleUser, DateTime.Now);

    var unknown = new[] { 1, 2, 3 };
    Log.Information("Created {unknown}  on {Created}", unknown, DateTime.Now);
    Log.Information("Created {$unknown}  on {Created}", unknown, DateTime.Now);
#endregion

在接收器中我们将得到如下:
 ConsoleImg
可以看到 @ 能够对对象进行解构,保留对象结构。用 $ 能够强制将对象转换为字符串,相当于.ToString()

如果你使用的是基于文本的接收器,可以使用 outputTemplate 参数来控制日志格式,
这里 Timestamp 为配置时间格式, Level 后面 u3 表示大写,还可以用 w3 小写。
Message 后面的 lj 表示数据将会以 JSON 格式输出。
然后是 NewLineException,即为如果有报错,将会换行并输出错误信息。

在字符串模板中可以使用解构运算符: @ ,解构运算符将会把对象转换为JSON格式,
还可以使用 $ 获取对象的类型。

覆盖默认格式化
在特定的情况下,可能我们需要覆盖默认的格式化,可以通过实现 IFormatProvider 接口来定义。

#region CustomDateFormatter
    class CustomDateFormatter : IFormatProvider
    {
        readonly IFormatProvider basedOn;
        readonly string shortDatePattern;
        public CustomDateFormatter(string shortDatePattern, IFormatProvider basedOn)
        {
            this.shortDatePattern = shortDatePattern;
            this.basedOn = basedOn;
        }
        public object GetFormat(Type formatType)
        {
            if (formatType == typeof(DateTimeFormatInfo))
            {
                var basedOnFormatInfo = (DateTimeFormatInfo)basedOn.GetFormat(formatType);
                var dateFormatInfo = (DateTimeFormatInfo)basedOnFormatInfo.Clone();
                dateFormatInfo.ShortDatePattern = this.shortDatePattern;
                return dateFormatInfo;
            }
            return this.basedOn.GetFormat(formatType);
        }
    }
#endregion

#region Main Function
    var formatter = new CustomDateFormatter("yyyy-MM-dd", new CultureInfo("zh-CN"));
    Log.Logger = new LoggerConfiguration()
        .WriteTo.Console(formatProvider: formatter)
        .WriteTo.Console()
        .CreateLogger();
    
    Log.Information("Created Date {Created}", DateTime.Now);
#endregion

在接收器中我们将得到如下:
 ConsoleImg
因为配置了两个控制台接收器,所以我们看到了不同的两个输出。

三、过滤器

可以通过筛选有选择地记录日志

    Log.Logger = new LoggerConfiguration()
        .Enrich.WithProperty("Version", new Version("1.0.0.0"))
        .WriteTo.Console(
         outputTemplate: "[{Timestamp:HH:mm:ss} {Level} {Version}] {Message}{NewLine}{Exception}")
        .Filter.ByExcluding(Matching.WithProperty<string>("Version", v =>
        {
            if (new Version(v) > new Version("1.0.0.1"))
                return true; // 不记录日志
            else
                return false; // 记录日志
        }))
        .CreateLogger();
    
    Log.Information("Test");

四、在 ASP.NET Core 中引入 Serilog

此处直接提供示例,因为内容在上方已经讲解地差不多了

Serilog 在配置文件中需要单独配置,配置如下:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Error",
        "System": "Information"
      }
    }
  },
  "AllowedHosts": "*"
}

代码:

#region Program
    // 获取配置文件和环境变量的配置
    public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
        .AddEnvironmentVariables()
        .Build();
    
    public static int Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            // 将配置传给 Serilog 的提供程序 
            .ReadFrom.Configuration(Configuration)
            .MinimumLevel.Debug()
            .Enrich.FromLogContext()
            .WriteTo.Console(new RenderedCompactJsonFormatter())
            .WriteTo.File(formatter: new CompactJsonFormatter(), "logs/log_.txt", rollingInterval: RollingInterval.Day)
            .CreateLogger();
        try
        {
            Log.Information("Starting web host");
            CreateHostBuilder(args).Build().Run();
            return 0;
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host terminated unexpectedly");
            return 1;
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }
    
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })
            // dispose 参数设置为 true 会在程序退出时释放日志对象
            .UseSerilog(dispose: true);
#endregion

在记录日志时,依然是使用注入 ILogger 来记录日志。


参考文档

Serilog Wiki

你可能感兴趣的:(C#,.NET,Core,ASP.NET,Core)