前言:
本文使用 .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== 中有不同的輸出格式設置
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
在接收器中我們將得到如下:
可以看到自定義的 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")
是行不通的。
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
在接收器中我們將得到如下:
可以看到 @
能夠對對象進行解構,保留對象結構。用 $
能夠強制將對象轉換爲字符串,相當於.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");
四、在 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 來記錄日誌。