Serilog.Sinks.MSSqlServer的WriteTo无法写入数据库但AuditTo运行正常
1 优先修复SelfLog捕获逻辑
你当前测试代码的SelfLog开启时机晚于日志写入操作,因此写入过程抛出的异常无法被捕获。必须将SelfLog初始化放到所有Serilog配置和日志写入操作之前,比如放在Global.asax的Application_Start方法最开头:
// 程序启动第一时间开启SelfLog Serilog.Debugging.SelfLog.Enable(msg => { Debug.WriteLine(msg); Console.Error.WriteLine(msg); }); // 再执行Logger配置和后续日志写入
开启后重新复现问题,就能拿到具体的写入错误原因。
2 常见核心问题排查
批量写入延迟/日志未刷入问题
Serilog.Sinks.MSSqlServer的WriteTo默认使用异步批量写入,即使你设置了BatchPostingLimit = 1,默认还有2秒的批处理等待周期。如果请求结束/程序退出前没有手动刷入日志,就会出现写入丢失的情况。
可以通过两个配置解决:- 调整批处理等待时间:
sinkOpts.BatchPeriod = TimeSpan.FromMilliseconds(100); - 测试时手动强制刷入:写完日志后调用
Log.CloseAndFlush();或者手动释放Logger实例。
也可以直接配置sinkOpts.EagerlyEmitFirstEvent = true;强制第一条日志立即写入,跳过等待周期。
- 调整批处理等待时间:
事务回滚导致日志丢失
这是WriteTo和AuditTo最核心的差异之一:WriteTo默认会登记到当前的环境事务(比如你代码中用了TransactionScope),如果外层事务回滚,日志写入操作也会被回滚;而AuditTo默认不参与环境事务,因此不受外层事务影响。
可以在配置Sink时显式禁用事务登记验证:.WriteTo.MSSqlServer( connectionString: connstring, columnOptions: GetSqlColumnOptions(), sinkOptions: sinkOpts, restrictedToMinimumLevel: LogEventLevel.Verbose, enlistInTransaction: false // 新增这一行,禁用事务登记 )自定义列配置错误
检查GetSqlColumnOptions()中配置的自定义列:如果存在非空的自定义列,但是你写入的日志事件中没有对应的属性赋值,WriteTo会静默写入失败,而AuditTo会直接抛出异常,因此你之前用AuditTo的时候可能没触发这个场景。可以逐个核对自定义列的允许空值配置和日志属性的赋值逻辑。日志级别过滤冲突
检查是否存在全局Filter规则过滤了目标级别的日志,比如是否配置了Filter.ByExcluding规则误拦截了需要写入的日志事件,或者是否有其他Sink的级别配置覆盖了当前的最小级别设置。
调整后的参考配置
// 第一步:先开SelfLog Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg)); var connstring = ConfigurationManager.AppSettings["serilog:write-to:MSSqlServer.connectionString"]; var sinkOpts = new MSSqlServerSinkOptions(); sinkOpts.TableName = ConfigurationManager.AppSettings["serilog:write-to:MSSqlServer.tableName"]; sinkOpts.AutoCreateSqlTable = false; sinkOpts.BatchPostingLimit = 1; sinkOpts.BatchPeriod = TimeSpan.FromMilliseconds(100); // 缩短批处理等待时间 sinkOpts.EagerlyEmitFirstEvent = true; // 第一条日志立即写入 var log = new LoggerConfiguration() .MinimumLevel.Verbose() .WriteTo.MSSqlServer( connectionString: connstring, columnOptions: GetSqlColumnOptions(), sinkOptions: sinkOpts, restrictedToMinimumLevel: LogEventLevel.Verbose, enlistInTransaction: false) // 禁用事务登记 .CreateLogger();
内容的提问来源于stack exchange,提问作者nitse

