.NET Core 3.1控制台应用Serilog WriteTo.File不生效无报错问题
问题根因
- 未释放日志资源:Serilog的File Sink默认采用缓冲写入机制,日志不会实时落盘,程序退出前如果不主动执行刷新操作,缓冲区中未写入磁盘的日志会全部丢失,且不会抛出任何异常。
- 配置项拼写错误:
appsettings.json中Serilog的最低日志级别配置项误写为MinimalLevel,正确键名为MinimumLevel,拼写错误会导致配置读取逻辑异常,干扰Sink初始化流程。 - 静态Logger实例被覆盖:调用
Host.CreateDefaultBuilder().UseSerilog()时,默认会重新构建Logger实例替换你之前手动初始化的全局Log.Logger,而你的配置文件中没有配置File Sink写入规则,替换后的Logger仅保留控制台输出能力。 - 日志路径认知偏差:代码中传入的是相对路径
log.txt,日志文件不会生成在项目源码目录,默认会生成在程序运行时的工作目录(调试状态下为bin/Debug/netcoreapp3.1/目录),找错路径会误以为文件未生成。 - 运行时错误被吞:Serilog默认会捕获Sink运行时的非致命错误(比如目录无写入权限、文件被占用),不会向外抛出异常打断主程序运行,没有开启SelfLog时很难直接感知到错误。
修复方案
- 修正
appsettings.json中的配置拼写错误,修正后的配置如下:
{ "Serilog": { "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Error", "System": "Error" } } }, "ConnectionStrings": { "DefaultConnection": "DataSource=app.db;Cache=Shared" } }
- 调整Host构建逻辑,避免手动初始化的Logger被覆盖,同时显式指定日志文件的绝对路径,避免找错文件位置:
static IHost AppStartup() { var builder = new ConfigurationBuilder(); BuildConfig(builder); var config = builder.Build(); // 提前创建日志存放目录,避免目录不存在导致写入失败 var logPath = Path.Combine(AppContext.BaseDirectory, "logs"); Directory.CreateDirectory(logPath); Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(config) .MinimumLevel.Information() .MinimumLevel.Override("Microsoft", LogEventLevel.Error) .MinimumLevel.Override("System", LogEventLevel.Error) .Enrich.FromLogContext() .WriteTo.Console() .WriteTo.File( path: Path.Combine(logPath, "log.txt"), rollingInterval: RollingInterval.Day, fileSizeLimitBytes: 10 * 1024 * 1024, rollOnFileSizeLimit: true, retainedFileCountLimit: 30 ) .CreateLogger(); Log.Logger.Information("Application Starting"); var host = Host.CreateDefaultBuilder() .ConfigureServices((context, services) => { }) // 传入preserveStaticLogger: true,保留手动初始化的全局Logger,不被Host构建流程覆盖 .UseSerilog(Log.Logger, preserveStaticLogger: true) .Build(); return host; }
- 修正Main方法逻辑,在程序退出前强制刷新日志缓冲区,确保所有日志落盘:
static void Main(string[] args) { try { var host = AppStartup(); Log.Warning("test log"); Console.ReadKey(); } catch (Exception ex) { Log.Fatal(ex, "Application start-up failed"); } finally { // 释放日志资源,强制将缓冲区日志写入磁盘 Log.CloseAndFlush(); } }
- (可选排查项)如果修复后仍无法写入,可开启Serilog的SelfLog查看内部报错,在初始化Logger前加如下代码:
Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine($"Serilog内部错误: {msg}"));
启动后控制台会输出Serilog运行时的内部错误,可直接定位是权限、文件占用还是其他问题。
修复完成后启动程序,到程序输出目录(bin/Debug/netcoreapp3.1/)下的logs文件夹即可看到按日期滚动生成的日志文件。
内容的提问来源于stack exchange,提问作者Davood Ramezani
相关产品推荐
相关产品推荐

