在.NET Standard 2.0类库中使用Serilog:运行时为每条日志选sink
Serilog 按单条日志灵活路由sink实现方案
核心依托Serilog原生的属性过滤能力,无需拆分多实例全局Logger、不依赖日志级别规则,即可精准实现单条日志的输出sink范围控制。
前置准备
在.NET Standard 2.0类库中需要引入Serilog.Filters.Expressions包,用于给sink配置灵活的属性匹配规则。
初始化配置改造
不再直接无过滤挂载sink,给每个目标sink配置专属的属性匹配规则:
Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() // Console sink:匹配带Console输出标识的日志 .WriteTo.Console( filter: "OutputSink @contains 'Console'" ) // File sink:匹配带File输出标识的日志 .WriteTo.File( path: @"c:\temp\SerilogTest.txt", filter: "OutputSink @contains 'File'" ) .CreateLogger();
三类场景的写入实现
所有日志写入时通过ForContext附加自定义路由属性OutputSink,根据需要选择对应的sink标识组合:
- 同时输出到Console与File
Log.ForContext("OutputSink", new[] { "Console", "File" }) .Information("Hello, world! 双sink输出"); - 仅输出到Console
Log.ForContext("OutputSink", new[] { "Console" }) .Information("Hello, world! 仅Console输出"); - 仅输出到File
Log.ForContext("OutputSink", new[] { "File" }) .Information("Hello, world! 仅File输出");
注意细节
- 直接调用
Log.Information()不带路由属性的日志,因为不匹配任何sink的过滤规则,会被直接丢弃。如果需要全局默认兜底逻辑(比如未指定路由属性时默认同时输出到所有sink),可以把过滤规则调整为:Console sink过滤:
not OutputSink is defined or OutputSink @contains 'Console'
File sink过滤:not OutputSink is defined or OutputSink @contains 'File' - 该路由逻辑完全独立于日志级别控制,不管日志等级是Verbose还是Fatal,只要属性匹配就能精准路由,不会和级别过滤规则冲突。
- 后续新增sink时(比如Seq、Elasticsearch),只需要在初始化阶段给新sink加上对应标识的过滤规则,写入时把对应标识加到属性数组即可,无需修改现有日志写入代码。
内容的提问来源于stack exchange,提问作者Kurt Colemonts
相关产品推荐
相关产品推荐

