本文使用 .NET Core SDK 3.1 和 Serilog 3.1.2 的版本。
与.NET的其他日志记录库不同,在 Serilog 中和日志消息一起传递的参数不会破坏性地呈现为文本格式,而是作为机构化数据保留。
在 Serilog 的 NuGet 包中,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== 中有不同的输出格式设置
在控制台或者文本文件的接收器中,通常都能够使用 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
在接收器中我们将得到如下:
可以看到自定义的 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");
在接收器中我们将得到如下:
使用 WithProperty
配置的,将是一个静态值,例如 DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
是行不通的。
在 Serilog 中可以配置接收器记录日志为JSON
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File(formatter: new CompactJsonFormatter(), "../../../log.txt")
.CreateLogger();
在以上代码中执行以后,会发现控制台中的日志并没有变成纯JSON格式,是因为需要接收器单独配置 formatter
参数。
#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
在接收器中我们将得到如下:
可以看到 @
能够对对象进行解构,保留对象结构。用 $
能够强制将对象转换为字符串,相当于.ToString()
。
如果你使用的是基于文本的接收器,可以使用 outputTemplate
参数来控制日志格式,
这里 Timestamp
为配置时间格式, Level
后面 u3
表示大写,还可以用 w3
小写。
Message
后面的 lj
表示数据将会以 JSON 格式输出。
然后是 NewLine
和 Exception
,即为如果有报错,将会换行并输出错误信息。
在字符串模板中可以使用解构运算符: @
,解构运算符将会把对象转换为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
在接收器中我们将得到如下:
因为配置了两个控制台接收器,所以我们看到了不同的两个输出。
可以通过筛选有选择地记录日志
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");
此处直接提供示例,因为内容在上方已经讲解地差不多了
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