Serilog多进程共享失效:.NET 8 Core API无法写入同一错误日志文件
问题排查:多.NET 8 API共享Serilog文件日志失败
问题现象
- 两个.NET 8 Core API(API-1、API-2)配置Serilog将错误日志写入同一
Errors-.txt文件,但始终只有第一个触发错误的API能成功写入,另一个完全无法生成日志。 - 测试1:重启IIS后先触发API-1错误,日志写入成功;API-2触发错误无日志输出;API-1再次触发错误仍能正常写入。
- 测试2:重启IIS后先触发API-2错误,日志写入成功;API-1触发错误无日志输出;API-2再次触发错误仍能正常写入。
当前配置
API-1的Serilog配置(appsettings.json)
"Serilog": { "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information", "System": "Warning" } }, "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], "WriteTo": [ { "Name": "Console" }, { "Name": "File", "Args": { "path": "E:/Logs/SerilogAPITester1-.txt", "rollingInterval": "Day", "fileSizeLimitBytes": 50000000, "rollOnFileSizeLimit": true, "shared": true } }, { "Name": "File", "Args": { "path": "E:/Logs/Errors-.txt", "rollingInterval": "Day", "fileSizeLimitBytes": 50000000, "rollOnFileSizeLimit": true, "shared": true, "restrictedToMinimumLevel": "Error" } } ] }
API-2的配置差异
仅修改两处:
"AppName": "Tester1" --> "Tester2" "path": "E:/Logs/SerilogAPITester1-.txt" --> "E:/Logs/SerilogAPITester2-.txt"
Program.cs初始化代码
Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(builder.Configuration).CreateLogger();
排查与解决方案
1. 升级Serilog.Sinks.File版本
旧版本的Serilog.Sinks.File在多进程共享文件场景下存在锁竞争缺陷,.NET 8环境建议直接升级到v5.0.0及以上稳定版,该版本修复了多进程文件写入的锁机制问题,是解决此类问题的核心步骤。
2. 验证日志目录权限
- 确认
E:/Logs目录对两个API的IIS应用程序池身份(通常为IIS AppPool\对应的应用池名称)同时拥有读写权限,权限不足会导致后启动的API无法打开日志文件。 - 滚动日志生成的带日期后缀文件(如
Errors-20240520.txt)也需要确保权限继承正常。
3. 补充滚动日志清理配置(可选但推荐)
在共享文件的sink配置中添加retainedFileCountLimit,避免日志滚动清理时因锁冲突导致写入失败:
{ "Name": "File", "Args": { "path": "E:/Logs/Errors-.txt", "rollingInterval": "Day", "fileSizeLimitBytes": 50000000, "rollOnFileSizeLimit": true, "shared": true, "restrictedToMinimumLevel": "Error", "retainedFileCountLimit": 30 } }
4. 启用Serilog内部日志排查
在Program.cs中添加内部日志输出,直接查看文件写入时的错误细节(如锁失败、权限报错):
Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(builder.Configuration) .WriteTo.Sink(new Serilog.Sinks.File.FileSink( "E:/Logs/SerilogInternal-.txt", new Serilog.Formatting.Display.MessageTemplateTextFormatter("{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}", null), fileSizeLimitBytes: 50000000, rollOnFileSizeLimit: true, shared: true, retainedFileCountLimit: 10 ), restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Verbose) .CreateLogger();
触发错误后检查SerilogInternal-.txt,即可定位具体失败原因。
5. 验证shared配置是否加载成功
确认shared: true被正确读取,可在Program.cs中添加调试代码:
var errorSinkArgs = builder.Configuration .GetSection("Serilog:WriteTo") .Where(w => w.GetValue<string>("Name") == "File") .Select(w => w.GetSection("Args")) .First(a => a.GetValue<string>("path") == "E:/Logs/Errors-.txt"); Console.WriteLine($"Error sink shared setting: {errorSinkArgs.GetValue<bool>("shared")}");
如果输出为false,说明配置未被正确解析,需检查JSON格式或配置加载逻辑。
总结
最核心的问题大概率是Serilog.Sinks.File版本过低导致的多进程锁冲突,优先升级包版本,再结合权限检查和内部日志排查,即可解决日志写入异常问题。
内容的提问来源于stack exchange,提问作者MCS
相关产品推荐
相关产品推荐

