.NET Core 3.1控制台应用使用Serilog.Sinks.Async丢失日志问题
.NET Core 3.1控制台应用中Serilog Async接收器丢失日志的问题
我在.NET Core 3.1控制台应用里按顺序读取大型文本文件的记录,借助Serilog.Sinks.Console、Serilog.Sinks.File、Serilog.Sinks.Async三个接收器记录记录编号等信息,但检查日志文件时发现部分日志(如记录编号)丢失。当移除Async接收器仅使用File接收器时,日志可按顺序完整生成,无丢失情况。
使用Async接收器的Serilog配置
"Serilog": { "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.Async" ], "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "System": "Warning" } }, "WriteTo": [ { "Name": "Async", "Args": { "configure": [ { "Name": "Console", "Args": { "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u4}] {Message:lj} [{SourceContext}] {Exception}{NewLine}" } }, { "Name": "File", "Args": { "path": "C:\\FeedReader\\Logs\\AppLog-.log", "rollOnFileSizeLimit": true, "rollingInterval": "Hour", "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u4}] {Message:lj} [{SourceContext}] {Exception}{NewLine}", "fileSizeLimitBytes": 1048576, // 10 MB "retainedFileCountLimit": 999, "shared": false, // 关闭文件共享提升性能 "buffered": true, // 使用缓冲写入提升性能 "flushToDiskInterval": "00:00:05" // 每5秒刷新到磁盘 } } ] } } ] }
Program.cs初始化代码
var baseDir = AppDomain.CurrentDomain.BaseDirectory; var builder = new ConfigurationBuilder() .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); if (string.IsNullOrEmpty(environmentName) == false) { builder.AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: true); } builder.AddEnvironmentVariables(); Configuration = builder.Build(); Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(Configuration) .CreateLogger(); Log.Information("===================================Application is starting=================================");
仅使用File接收器的Serilog配置
"Serilog": { "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "System": "Warning" } }, "WriteTo": [ { "Name": "File", "Args": { "path": "C:\\FeedReader\\Logs\\AppLog.log", "fileSizeLimitBytes": 1048576, "rollingInterval": "Hour", "rollOnFileSizeLimit": true, "retainedFileCountLimit": 999, "flushToDiskInterval": "00:00:05", "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u4}] {Message:lj} [{SourceContext}] {Exception}{NewLine}" } }, { "Name": "Console", "Args": { "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u4}] {Message:lj} [{SourceContext}] {Exception}{NewLine}" } } ] }
问题原因及解决办法
Async队列溢出丢弃日志
Serilog.Sinks.Async默认使用容量为10000的有界队列,当日志生成速度超过异步处理速度时,超出队列容量的日志会被直接丢弃。可以通过以下配置调整:- 增大
queueLimit参数提升队列容量 - 设置
blockWhenFull: true,让写入线程在队列满时等待,而非丢弃日志
- 增大
应用退出未处理剩余日志
控制台应用退出时,Async队列中未处理的日志会丢失,必须在应用结束前调用Log.CloseAndFlush()确保所有日志都被写入磁盘。双重缓冲导致的冲突
Async本身已做异步缓冲,再给File接收器设置buffered: true会导致双重缓冲,增加丢失风险,建议关闭File接收器的缓冲。
修改后的Async接收器配置示例
"Serilog": { "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.Async" ], "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "System": "Warning" } }, "WriteTo": [ { "Name": "Async", "Args": { "queueLimit": 50000, // 增大队列容量 "blockWhenFull": true, // 队列满时阻塞等待 "configure": [ { "Name": "Console", "Args": { "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u4}] {Message:lj} [{SourceContext}] {Exception}{NewLine}" } }, { "Name": "File", "Args": { "path": "C:\\FeedReader\\Logs\\AppLog-.log", "rollOnFileSizeLimit": true, "rollingInterval": "Hour", "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u4}] {Message:lj} [{SourceContext}] {Exception}{NewLine}", "fileSizeLimitBytes": 1048576, "retainedFileCountLimit": 999, "shared": false, "buffered": false, // 关闭File接收器的缓冲 "flushToDiskInterval": "00:00:05" } } ] } } ] }
补充:确保应用退出时处理日志
在Program.cs的业务逻辑结束后,添加日志关闭操作:
try { // 你的业务逻辑代码(读取文本文件、记录日志等) } finally { Log.CloseAndFlush(); // 确保所有异步日志都被写入磁盘 }
内容的提问来源于stack exchange,提问作者Nitin Jain
相关产品推荐
相关产品推荐

