.NET 6后台服务启动崩溃时Serilog无法向Seq Sink发送日志
问题根源与修复方案
你的代码存在三个关键问题,导致catch块的日志无法输出到Seq:
- 全局
Log.Logger未初始化:catch块里调用Log.Logger.Error,但此时全局的Log.Logger还未被赋值为你创建的Serilog实例,默认是一个空日志实现,这条日志根本不会被发送。 - try/catch覆盖范围不足:当前try仅包裹了
Host.CreateDefaultBuilder的构建过程,但崩溃实际发生在Main方法的Build()或Run()阶段(即HostBuilder创建后的实例化、启动环节),这部分代码不在CreateHostBuilder的try块内,异常根本没被捕获。 - logger被提前释放:你在using块中创建logger,同时在
ConfigureLogging里设置了dispose: true,导致Host接管logger生命周期,但using块在CreateHostBuilder返回后就会释放logger,后续启动过程中即使出现异常,也没有可用的日志器记录。
修复后的代码示例
public sealed class Program { public static void Main(string[] args) { // 提前初始化全局日志器,覆盖全启动流程的异常记录 var environmentName = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT"); var configuration = new ConfigurationBuilder() .AddEnvironmentVariables() // 加载环境变量,确保能读取到Seq等配置 .Build(); var logger = new LoggerConfiguration() .Enrich.WithProperty("Application", configuration.GetValue<string>("ApplicationName")) .Enrich.WithProperty("ApplicationHost", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name) .Enrich.WithProperty("Environment", environmentName) .Enrich.WithExceptionDetails(new DestructuringOptionsBuilder() .WithDefaultDestructurers() .WithDestructurers(new[] { new DbUpdateExceptionDestructurer() })) .ReadFrom.Configuration(configuration) .CreateLogger(); // 设置全局日志器 Log.Logger = logger; try { logger.Information("************ STARTING MY WORKER ************"); CreateHostBuilder(args, logger).Build().Run(); } catch (Exception ex) { logger.Fatal(ex, "Worker启动失败"); throw; } finally { // 确保所有日志都被刷新到Seq Log.CloseAndFlush(); } } private static IHostBuilder CreateHostBuilder(string[] args, ILogger logger) { return Host.CreateDefaultBuilder(args) .ConfigureServices((ctx, services) => { services.AddSingleton(logger); services.AddHostedService<MyWorker>(); services.AddSingleton<CustomClass>(); // 启用该修复解决崩溃问题 }) .ConfigureLogging((ctx, loggingBuilder) => { loggingBuilder.ClearProviders(); loggingBuilder.AddSerilog(logger, dispose: false); // 不让Host释放日志器,交由finally块处理 }); } }
关键修改说明
- 全局日志器提前初始化:在Main方法开头就创建并设置
Log.Logger,确保启动全流程的异常都能被捕获记录。 - 扩大try/catch范围:将
Build()和Run()全部包裹在try块内,覆盖整个启动环节。 - 避免日志器提前释放:移除using块,改用finally块调用
Log.CloseAndFlush()保证日志发送;同时在AddSerilog时设置dispose: false,避免Host提前释放日志器。 - 补充配置源:原
ConfigurationBuilder未添加任何配置来源,导致可能无法读取Seq的连接配置,这里添加.AddEnvironmentVariables()适配Azure容器实例的环境变量配置方式。
内容的提问来源于stack exchange,提问作者user1451111
相关产品推荐
相关产品推荐

