zapcore SPI:Core / Encoder / WriteSyncer
zapcore 是 zap 的内核层,也是整个日志库的 SPI(Service Provider Interface)。它定义了一组关键接口,让上层 zap 包只依赖抽象,而不关心具体实现。
💡 API 是你调用框架,SPI 是框架调用你。 zap 顶层通过
zapcore定义的接口工作,任何满足这些接口的实现都能插入其中。
什么是 SPI
SPI 是一种软件设计模式:框架定义接口,第三方提供实现,框架在运行时调用。它与 API 的方向恰好相反。
gozapcore/core.go
type Core interface {
Enabled(Level) bool
With([]Field) Core
Check(Entry, *CheckedEntry) *CheckedEntry
Write(Entry, []Field) error
Sync() error
}
Core:调度中心
Core 是日志过滤、编码、写入的调度中心。zap 内置了 ioCore、multiCore、nopCore 三种实现,并通过装饰器模式提供了 sampler、hooked、levelFilter 等扩展。
ioCore
最基础的实现:持有一个 Encoder 和一个 WriteSyncer,负责编码并写入。
multiCore(tee)
将多个 Core 组合成一个,日志会同时写入所有子 Core。常用于同时输出到文件和 Kafka。
⚠️ 注意:
multiCore会按顺序调用每个子 Core 的Write,任一失败不会中断其他 Core,但错误会被聚合返回。
Encoder:编码抽象
Encoder 负责将 Entry 和 Field 编码为字节。zap 内置 jsonEncoder 和 consoleEncoder,前者面向机器解析,后者面向人类阅读。
gozapcore/encoder.go
type Encoder interface {
ObjectEncoder
Clone() Encoder
EncodeEntry(Entry, []Field) (*Buffer, error)
}
WriteSyncer:输出抽象
WriteSyncer 组合了 io.Writer 和 Sync 方法,是 zap 对输出目的地的抽象。
Lock:为 Writer 加锁,保证并发安全Multi:将多个 Writer 组合成一个Buffered:带缓冲的 Writer,减少系统调用
装饰器 Core
zap 通过装饰器模式实现了多种 Core 扩展,每一个都遵循 SPI,可以自由组合:
- sampler:按级别和消息采样,降低高频日志开销
- tee / multiCore:多路复用,写入多个目的地
- hooked:在写入前后触发 Hook
- levelFilter:按级别过滤
- lazyWith:延迟添加上下文字段
- nopCore:空实现,用于禁用日志
小结
zapcore 作为 SPI 层,用一组精简的接口定义了日志系统的骨架。理解它,就理解了 zap 为什么能在保持高性能的同时,拥有极强的可扩展性。