20 | 結構化日志組件Serilog:記錄對查詢分析友好的日志
之前講解的日志框架,記錄的日志都是文本,而且是非結構化的,這樣一串串文本實際上不利於我們去做分析
結構化的日志它的好處就顯而易見,它可以讓我們更易於去檢索,更易於與現有的分析系統進行結合
結構化日志的主要場景:
1、實現日志告警
2、實現上下文的關聯:可以在日志系統里面對一段業務邏輯輸出的日志進行分析
3、實現與追蹤系統集成:在調用鏈的系統里面看到有問題的情況下,可以追蹤到調用鏈過程中間的所有的日志信息
這里創建的依然是一個默認的 ASP.NET Core 的工程
引用包:Serilog.AspNetCore
這個包實際上依賴了 Serilog 很多的內置的包
比如核心的 Serilog (2.8.0)
配置 Serilog.Settings.Configuration (3.1.0)
Console 的輸出 Serilog.Sinks.Console (3.1.1)
Debug 的輸出 Serilog.Sinks.Debug (1.0.1)
File 的輸出 Serilog.Sinks.File (4.0.0)
我們在 Program 這里提前讀取一下配置,然后傳遞給 Serilog 的初始化過程,這里我們把 Main 函數進行了稍微的改造,以讓 Serilog 可以接替整個默認的日志記錄框架
namespace LoggingSerilogDemo
{
public class 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)
{
// 將配置傳遞給 Serilog 的初始化過程
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(Configuration)
.MinimumLevel.Debug()
.Enrich.FromLogContext()
.WriteTo.Console(new RenderedCompactJsonFormatter())
.WriteTo.File(formatter: new CompactJsonFormatter(), "logs\\myapp.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>();
})
.UseSerilog(dispose: true);// dispose 設置為 true,它就會在退出時幫我們釋放我們的日志對象
}
}
啟動程序,輸出如下:
{"@t":"2020-03-08T15:47:40.2569100Z","@m":"Starting web host","@i":"4872fd06"}
{"@t":"2020-03-08T15:47:44.1978171Z","@m":"Get 隨機創建數據","@i":"6936e72c","SourceContext":"LoggingSerilogDemo.Controllers.WeatherForecastController","ActionId":"8d8ebb60-2211-4acb-bc91-a079be45a689","ActionName":"LoggingSerilogDemo.Controllers.WeatherForecastController.Get (LoggingSerilogDemo)","RequestId":"0HLU3F052RUUN:00000001","RequestPath":"/weatherforecast","SpanId":"|99917a4d-4ccf47636d09b066.","TraceId":"99917a4d-4ccf47636d09b066","ParentId":""}
可以看到每一行都是一個 json,也就是將日志輸出為 json 格式,這就意味着可以在整個日志系統里面以 json 的格式去檢索數據,比如 SourceContext 就是 Logger 的 name
它還記錄了請求上下文,並且輸出了 RequestId,SpanId,TraceId,ParentId
RequestId 與 SpanId 的作用就是與追蹤系統可以結合
我們記錄的日志的方式實際上是與之前是一樣的,Controller 里面還是注入了 ILogger,依然使用 ILogger 來記錄日志
namespace LoggingSerilogDemo.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
_logger.LogInformation("Get 隨機創建數據");
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
也就是說可以通過簡單的配置和幾行代碼的設置就可以替換官方提供的日志框架,讓我們具備記錄結構化日志的能力
我們剛才看到日志輸出到 Console,同時輸出到文件,可以看到 logs 目錄已經產生了一個 myapp20200308.txt 文件
{"@t":"2020-03-08T15:47:40.2569100Z","@mt":"Starting web host"}
{"@t":"2020-03-08T15:47:44.1978171Z","@mt":"Get 隨機創建數據","SourceContext":"LoggingSerilogDemo.Controllers.WeatherForecastController","ActionId":"8d8ebb60-2211-4acb-bc91-a079be45a689","ActionName":"LoggingSerilogDemo.Controllers.WeatherForecastController.Get (LoggingSerilogDemo)","RequestId":"0HLU3F052RUUN:00000001","RequestPath":"/weatherforecast","SpanId":"|99917a4d-4ccf47636d09b066.","TraceId":"99917a4d-4ccf47636d09b066","ParentId":""}
這個文件可以看到每一行是一條日志,每一條日志都是一個 json 對象,包括剛才我們記錄的 Get 隨機創建數據,已經輸出出來了
我們可以調整日志級別,打開配置文件
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Error",
"System": "Information"
}
}
},
"AllowedHosts": "*"
}
Serilog 需要單獨配置,它與之前的配置方式略有不同,它需要配置最小的日志輸出級別,默認是 Information
Override 是重載上面 Logging 定義的日志級別
設置 Microsoft 為 Error 之后會把 Microsoft 默認的日志輸出級別過濾掉
也意味着整個的配置和輸出的方式與之前是級別類似的,我們可以把日志輸出到 Console,也可以把日志輸出到文件,當然實際上 Serilog 還提供了很多的這種輸出的提供程序,還可以與 EFK,ELK 這種日志的套件進行集成,把日志輸出到分析系統里面
GitHub源碼鏈接:
本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。
歡迎轉載、使用、重新發布,但務必保留文章署名 鄭子銘 (包含鏈接: http://www.cnblogs.com/MingsonZheng/ ),不得用於商業目的,基於本文修改后的作品務必以相同的許可發布。
如有任何疑問,請與我聯系 (MingsonZheng@outlook.com) 。