serilog多sink配置本质是广播式日志事件分发,各sink独立处理同一logevent,共享事件流但互不阻塞;错误配置易致丢失、重复、格式错乱或性能骤降。

直接上结论:Serilog 的多 Sink 配置不是“叠加多个 WriteTo 就完事”,关键在于**每个 Sink 的行为独立、互不干扰,但共享同一日志事件流**;错误配置会导致日志丢失、重复、格式错乱或性能骤降。
为什么 WriteTo.Console() 和 WriteTo.File() 能同时生效?
Serilog 的日志管道是“广播式”的:一次 Log.Information() 调用会把同一个 LogEvent 对象分发给所有已注册的 Sink。所以只要在 LoggerConfiguration 中连续调用多个 WriteTo.Xxx(),它们就会并行接收日志。
- 每个 Sink 自行决定是否处理该事件(例如通过
restrictedToMinimumLevel过滤) - 每个 Sink 独立控制输出格式(
outputTemplate)、线程安全策略和缓冲行为 - 没有隐式顺序依赖——
Console写得慢不会卡住File,反之亦然
常见 Sink 参数差异与踩坑点
不同 Sink 的关键参数含义和默认行为差异很大,不注意会出问题:
-
WriteTo.Console()默认不带时间戳和级别前缀,建议显式传outputTemplate,否则日志难以定位上下文 -
WriteTo.File()的rollingInterval: RollingInterval.Day是按**文件创建时间**滚动,不是按日志时间戳;若程序凌晨启动,首日日志可能跨两天 -
WriteTo.File()默认使用shared: true,多个进程写同一路径会冲突;生产环境必须设shared: false或改用RollingFileSink的新版替代方案 -
WriteTo.MSSqlServer()若未配restrictedToMinimumLevel: LogEventLevel.Error,高频 Info 日志会直接拖垮数据库连接池
如何避免多 Sink 导致的日志爆炸或性能抖动?
多个 Sink 并行写入本身不慢,但不当组合会放大开销:
- 别在高并发循环里直接调用
Log.Information("msg {Prop}", value)—— 每次都触发全部 Sink;改用Log.ForContext("Prop", value).Information("msg")提前过滤 - 禁用冗余 Sink:开发环境保留
Console+File;生产环境关掉Console(它会阻塞主线程且无缓冲) - 对低优先级 Sink(如 UI 控件、HTTP 上报)加
.WriteTo.Async(...)包裹,避免阻塞主日志流 - 用
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)降低框架日志量,尤其 ASP.NET Core 的中间件日志非常密集
最易被忽略的是 Sink 初始化时机和生命周期管理:所有 WriteTo.Xxx() 必须在 CreateLogger() 前完成注册;一旦 Log.Logger 被赋值,后续再改配置无效——哪怕你重新 new 一个 LoggerConfiguration,也得手动替换 Log.Logger 并确保旧 logger 已 CloseAndFlush(),否则内存泄漏+日志静默丢弃。










