使用Microsoft.Extensions.Hosting时UseSerilog启动执行两次问题排查
我使用Microsoft.Extensions.Hosting,并通过UseSerilog将Serilog设为唯一日志记录器,代码如下:
var hostBuilder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args); hostBuilder.UseSerilog((hostingContext, services, loggerConfiguration) => { loggerConfiguration .ReadFrom.Configuration(hostingContext.Configuration) });
但传入的委托会执行两次,导致日志文件被覆盖。原本预期该委托仅执行一次,此前因误调用BuildServiceProvider导致执行三次,现已移除该调用且无其他BuildServiceProvider调用,请问还有哪些操作会触发服务构建?两次执行均发生在await hostBuilder.RunConsoleAsync()调用之后。
可能触发服务构建的操作及解决方案
1. 启用了主机启动等待超时配置
当配置中设置了HostOptions.WaitForStartTimeout时,主机启动过程中会等待服务就绪,这个逻辑可能触发服务提供者的多次构建。检查appsettings.json或其他配置源是否存在类似配置:
{ "Host": { "WaitForStartTimeout": "00:00:10" } }
处理方式:
- 若无需等待逻辑,直接移除该配置;
- 若必须保留,修改Serilog的文件写入配置为追加模式,避免覆盖:
"Serilog": { "WriteTo": [ { "Name": "File", "Args": { "path": "logs/log-.txt", "rollingInterval": "Day", "append": true, "shared": true } } ] }
2. 自定义服务/中间件触发重复启动
即使只调用了RunConsoleAsync,自定义的IHostedService或中间件可能在内部重复触发主机启动流程,间接导致服务提供者多次构建。
处理方式:检查所有自定义启动逻辑,确保StartAsync等启动方法仅被执行一次,避免手动调用服务提供者相关初始化操作。
3. 默认日志系统未完全清除
Host.CreateDefaultBuilder会自动添加控制台、调试等默认日志提供程序,即便调用了UseSerilog,某些场景下仍可能触发默认日志系统的初始化,进而导致Serilog配置委托重复执行。
处理方式:在构建主机时显式清除默认日志提供程序,确保Serilog是唯一日志实现:
var hostBuilder = Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => logging.ClearProviders()) .UseSerilog((hostingContext, services, loggerConfiguration) => { loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration); });
4. 配置自动重新加载触发
如果配置加载时启用了自动重新加载(比如AddJsonFile(reloadOnChange: true)),当配置文件发生变化时,会触发配置重新加载,进而导致服务重新构建,Serilog配置委托也会再次执行。
处理方式:
- 若无需自动重新加载,移除
reloadOnChange: true设置; - 若必须保留,确保Serilog配置支持动态更新,避免文件覆盖问题。
内容的提问来源于stack exchange,提问作者MrHinsh - Martin Hinshelwood

