在上一篇中,我依据项目需求引入了Serilog日志框架,成功实现了自定义日志的输出功能。然而,完成日志记录仅仅是完成了日志管理流程中的输入环节。接下来,我们需要着重考虑日志的输出环节,即如何以一种高效且清晰的方式将日志信息呈现出来,以便更好地满足项目需求和便于后续的日志分析与管理。
在输出方面,我采用了自定义 Sink 并结合 Property 的方式来实现。通过这种方式,能够根据实际需求灵活地对日志进行处理和展示,从而确保日志输出的高效性和针对性,进一步提升日志系统的实用性和价值。
一、Sink核心与ILogEventSink
-
Sink的定义
Sink是Serilog日志系统的输出插槽,负责将日志事件(LogEvent)分发到具体的目标(如文件、数据库、控制台等)。每个Sink对应一种输出通道。 -
ILogEventSink
接口
该接口定义了日志分发的核心方法Emit
,所有Sink必须实现此接口:public interface ILogEventSink { void Emit(LogEvent logEvent); }
Emit
方法:接收LogEvent
对象(包含日志级别、消息模板、属性等),决定如何输出或存储日志。
-
自定义Sink的意义
通过实现ILogEventSink
,开发者可以自由控制日志的分发逻辑(如按业务模块过滤、输出到自定义UI组件等)。
二、Property的概念与使用
-
Property的作用
Property是附加到日志事件的键值对,用于记录上下文信息(如用户ID、模块名称、业务标识)。通过Property可以实现:- 日志分类(如区分业务日志与系统日志)
- 动态过滤(按属性筛选输出目标)
- 数据扩展(添加业务相关元数据)
-
添加Property的方式
- 全局附加:通过
Enrich.WithProperty
为所有日志添加固定属性。
.Enrich.WithProperty("AppVersion", "1.0.0")
- 动态附加:在记录日志时通过
ForContext
添加临时属性。
var log = Log.ForContext("Module", "Payment"); log.Information("Payment processed");
- 全局附加:通过
-
代码示例:模块化属性绑定
// 动态创建Logger并绑定模块属性 var extentionLevel = $"{ moduleName}.{ shortName}"; var logger = new