2. Zapcore
Zapcore 是 Zap 日志库的核心组件,提供构建和自定义日志系统的底层接口和类型。
1 编码器
类别
函数名称
用途
描述
时间编码器
EpochMillisTimeEncoder
机器处理、日志聚合系统
时间戳以毫秒为单位(如 1700000000000
)
EpochNanosTimeEncoder
高精度性能分析、分布式追踪
时间戳以纳秒为单位(如 1700000000000000000
)
EpochTimeEncoder
兼容旧系统、简单时间戳需求
时间戳以秒为单位(如 1700000000
)
ISO8601TimeEncoder
人类可读、跨时区日志分析
ISO8601 格式(如 2023-11-15T09:30:00Z
)
RFC3339TimeEncoder
严格时间格式兼容性需求
RFC3339 格式(等同于 ISO8601 严格模式)
RFC3339NanoTimeEncoder
高精度时间戳、微服务链路追踪
RFC3339 格式含纳秒(如 2023-11-15T09:30:00.123456Z
)
日志级别编码器
CapitalLevelEncoder
结构化日志(如 JSON)、机器处理
大写级别(如 INFO
)
CapitalColorLevelEncoder
终端输出、开发环境调试
大写级别带 ANSI 颜色(如 \033[32mINFO\033[0m
)
LowercaseLevelEncoder
兼容小写日志系统(如 ELK)
小写级别(如 info
)
LowercaseColorLevelEncoder
终端输出颜色统一(小写风格)
小写级别带 ANSI 颜色
调用者信息编码器
FullCallerEncoder
调试阶段详细追踪代码路径
完整调用路径(如 /src/project/main.go:42
)
ShortCallerEncoder
生产环境简洁日志、减少存储开销
短调用路径(如 main.go:42
)
持续时间编码器
MillisDurationEncoder
监控系统(Prometheus)、性能统计
持续时间以毫秒为单位(如 1500
)
NanosDurationEncoder
低延迟系统、纳秒级性能分析
持续时间以纳秒为单位(如 1500000000
)
SecondsDurationEncoder
粗略时间统计、简单日志记录
持续时间以秒为单位(如 1.5
)
StringDurationEncoder
人类可读日志、开发调试
可读字符串(如 1.5s
)
日志器名称编码器
FullNameEncoder
微服务/模块化日志追踪、区分日志源
完整日志器名称(如 app.module.submodule
)
2 类型
2.1 Core接口
Core
是 Zap 日志库的核心接口,定义了日志处理的基本逻辑。
type Core interface {
LevelEnabler
// With adds structured context to the Core.
With([]Field) Core
// Check determines whether the supplied Entry should be logged (using the
// embedded LevelEnabler and possibly some extra logic). If the entry
// should be logged, the Core adds itself to the CheckedEntry and returns
// the result.
//
// Callers must use Check before calling Write.
Check(Entry, *CheckedEntry) *CheckedEntry
// Write serializes the Entry and any Fields supplied at the log site and
// writes them to their destination.
//
// If called, Write should always log the Entry and Fields; it should not
// replicate the logic of Check.
Write(Entry, []Field) error
// Sync flushes buffered logs (if any).
Sync() error
}
方法
作用
With([]Field) Core
添加结构化字段到 Core,返回新的 Core(链式调用)。
Check(Entry, *CheckedEntry) *CheckedEntry
判断是否记录日志,若需记录,将自身添加到 CheckedEntry
。
Write(Entry, []Field) error
序列化并写入日志条目及字段。
Sync() error
同步缓冲区数据到存储(如刷新文件到磁盘)。
2.1.1 NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler) Core
作用:创建基础 Core
,将日志写入指定目标。
参数:
enc Encoder
:日志编码器(如 JSON、Console)。ws WriteSyncer
:日志输出目标(文件、标准输出等)。enab LevelEnabler
:日志级别过滤器(如zap.InfoLevel
)。
示例:
// 创建 JSON 编码器
encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
// 输出到文件和控制台
file, _ := os.Create("app.log")
writer := zapcore.NewMultiWriteSyncer(file, os.Stdout)
// 创建 Core(只记录 Info 及以上级别)
core := zapcore.NewCore(encoder, writer, zap.InfoLevel)
2.1.2 NewIncreaseLevelCore(core Core, level LevelEnabler) (Core, error)
作用:提升现有 Core
的日志级别(只能提升,不能降低)。
注意:若 level
低于原 Core 的级别,返回错误。
示例:
baseCore := zapcore.NewCore(...)
// 原级别为 Debug
newCore, _ := zapcore.NewIncreaseLevelCore(baseCore, zap.WarnLevel) // 提升到 Warn
logger := zap.New(newCore)
logger.Debug("此日志被过滤") // 不输出
logger.Warn("警告日志") // 输出
2.1.3 NewLazyWith(core Core, fields []Field) Core
作用:延迟字段的编码,仅在日志实际写入时处理字段。 适用场景:字段值计算开销大时优化性能。
示例:
// 生成字段值可能耗时
lazyCore := zapcore.NewLazyWith(core, []zap.Field{
zap.Lazy(func() zap.Field {
return zap.String("lazy_data", computeExpensiveValue())
}),
})
logger := zap.New(lazyCore)
2.1.4 NewNopCore() Core
作用:创建无操作的 Core
,禁用所有日志记录。
适用场景:测试或需要完全关闭日志时使用。
示例:
logger := zap.New(zapcore.NewNopCore())
logger.Info("此日志不会被记录") // 无输出
2.1.5 NewSamplerWithOptions(core Core, tick time.Duration, first, thereafter int, opts ...SamplerOption) Core
作用:创建带采样策略的 Core
,控制日志量。
参数:
tick
:采样时间窗口(如time.Second
)。first
:每个窗口内首次记录的日志条数。thereafter
:后续每记录thereafter
条日志保留 1 条。
示例:
// 每秒最多记录 10 条相同日志,后续每 5 条保留 1 条
sampledCore := zapcore.NewSamplerWithOptions(
core,
time.Second,
10,
5,
)
logger := zap.New(sampledCore)
2.1.6 NewTee(cores ...Core) Core
作用:组合多个 Core
,日志同时写入多个目标。
示例:
fileCore := zapcore.NewCore(encoder, fileWriter, zap.InfoLevel)
httpCore := zapcore.NewCore(encoder, httpWriter, zap.ErrorLevel)
teeCore := zapcore.NewTee(fileCore, httpCore)
logger := zap.New(teeCore)
2.1.7 RegisterHooks(core Core, hooks ...func(Entry) error) Core
作用:注册钩子函数,在日志写入前后执行自定义逻辑(如统计、告警)。
示例:
// 统计日志数量
hook := func(e zapcore.Entry) error {
metrics.LogCount.WithLabelValues(e.Level.String()).Inc()
return nil
}
core := zapcore.RegisterHooks(baseCore, hook)
logger := zap.New(core)
2.1.8 示例
将日志同时输出到文件(Info+)和远程服务(Error+),并采样高频日志。
package main
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
"time"
)
func main() {
// 1. 配置编码器
encoderCfg := zapcore.EncoderConfig{
TimeKey: "time",
EncodeTime: zapcore.ISO8601TimeEncoder,
MessageKey: "msg",
LevelKey: "level",
EncodeLevel: zapcore.CapitalLevelEncoder,
}
encoder := zapcore.NewJSONEncoder(encoderCfg)
// 2. 输出到文件
file, _ := os.Create("app.log")
fileWriter := zapcore.AddSync(file)
fileCore := zapcore.NewCore(encoder, fileWriter, zap.InfoLevel)
// 3. 输出到 HTTP 服务(仅 Error+)
httpCore := zapcore.NewCore(encoder, NewHTTPSink("http://logs.example.com"), zap.ErrorLevel)
// 4. 组合 Core
teeCore := zapcore.NewTee(fileCore, httpCore)
// 5. 添加采样策略(每秒最多 100 条,后续每 10 条保留 1 条)
sampledCore := zapcore.NewSamplerWithOptions(teeCore, time.Second, 100, 10)
// 6. 注册钩子(统计日志)
hookCore := zapcore.RegisterHooks(sampledCore, func(e zapcore.Entry) error {
logCount.WithLabelValues(e.Level.String()).Inc()
return nil
})
// 7. 构建 Logger
logger := zap.New(hookCore, zap.AddCaller())
defer logger.Sync()
// 8. 记录日志
logger.Info("服务启动")
logger.Error("数据库连接失败")
}
2.2 Entry类型
Entry
表示一个完整的日志条目,包含日志的基本信息和上下文。
type Entry struct {
Level Level // 日志级别(Debug, Info, Error 等)
Time time.Time // 日志时间戳
LoggerName string // 记录器名称(用于区分不同 Logger)
Message string // 日志消息内容
Caller EntryCaller // 调用者信息(文件、行号、函数名)
Stack string // 堆栈跟踪(可选)
}
池化(Pooled)机制:
Entry
实例通过对象池管理,以提升性能。处理完日志后必须释放引用,否则可能导致内存泄漏或数据竞争。字段特性:
LoggerName
,Caller
,Stack
为可选字段,留空时在编码时会被忽略。Caller
和Stack
需通过 Logger 配置启用(如AddCaller()
,AddStacktrace()
)。
2.3 Encoder接口
Encoder
是 Zap 的日志编码器接口,负责将日志条目和字段序列化为特定格式(如 JSON、控制台)。
type Encoder interface {
ObjectEncoder
// Clone copies the encoder, ensuring that adding fields to the copy doesn't
// affect the original.
Clone() Encoder
// EncodeEntry encodes an entry and fields, along with any accumulated
// context, into a byte buffer and returns it. Any fields that are empty,
// including fields on the `Entry` type, should be omitted.
EncodeEntry(Entry, []Field) (*buffer.Buffer, error)
}
方法
作用
Clone() Encoder
创建编码器的副本,避免修改原实例。
EncodeEntry(Entry, []Field) (*buffer.Buffer, error)
序列化日志条目和字段到字节缓冲区,返回结果。
2.3.1 NewConsoleEncoder(cfg EncoderConfig) Encoder
作用:创建面向人类阅读的控制台编码器,核心数据以纯文本格式输出,结构化字段以 JSON 显示。 参数:
cfg EncoderConfig
:编码器配置(时间格式、字段键名等)。
示例配置:
encoderCfg := zapcore.EncoderConfig{
TimeKey: "time",
EncodeTime: zapcore.ISO8601TimeEncoder, // 时间格式:ISO8601
LevelKey: "level",
EncodeLevel: zapcore.CapitalLevelEncoder, // 级别格式:"INFO"
MessageKey: "msg",
CallerKey: "caller",
EncodeCaller: zapcore.ShortCallerEncoder, // 调用者格式:文件:行号
}
// 2023-10-01T12:00:00Z INFO user_controller.go:42 用户登录成功 {"user_id": 42}
2.3.2 NewJSONEncoder(cfg EncoderConfig) Encoder
作用:创建高效 JSON 编码器,所有字段以 JSON 格式输出。 参数:
cfg EncoderConfig
:同上,但需注意键名配置。
示例配置:
encoderCfg := zapcore.EncoderConfig{
TimeKey: "timestamp",
EncodeTime: zapcore.EpochMillisEncoder, // 时间戳:毫秒数
LevelKey: "severity",
EncodeLevel: zapcore.LowercaseLevelEncoder, // 级别格式:"info"
MessageKey: "message",
}
/*{
"timestamp": 1696147200000,
"severity": "info",
"message": "用户登录成功",
"user_id": 42
}*/
2.3.3 示例
分别使用 JSON 和控制台编码器记录日志。
package main
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
)
func main() {
// 公共配置
encoderCfg := zapcore.EncoderConfig{
TimeKey: "time",
EncodeTime: zapcore.ISO8601TimeEncoder,
LevelKey: "level",
EncodeLevel: zapcore.CapitalLevelEncoder,
MessageKey: "msg",
CallerKey: "caller",
EncodeCaller: zapcore.ShortCallerEncoder,
}
// 1. JSON 编码器
jsonEncoder := zapcore.NewJSONEncoder(encoderCfg)
jsonWriter := zapcore.AddSync(os.Stdout)
jsonCore := zapcore.NewCore(jsonEncoder, jsonWriter, zap.InfoLevel)
jsonLogger := zap.New(jsonCore, zap.AddCaller())
jsonLogger.Info("JSON 日志示例", zap.Int("user_id", 42))
// 2. 控制台编码器
consoleEncoder := zapcore.NewConsoleEncoder(encoderCfg)
consoleWriter := zapcore.AddSync(os.Stdout)
consoleCore := zapcore.NewCore(consoleEncoder, consoleWriter, zap.InfoLevel)
consoleLogger := zap.New(consoleCore, zap.AddCaller())
consoleLogger.Info("控制台日志示例", zap.Int("user_id", 42))
}
/*
// JSON 输出
{"time":"2023-10-01T12:00:00Z","level":"INFO","msg":"JSON 日志示例","caller":"main.go:15","user_id":42}
// 控制台输出
2023-10-01T12:00:00Z INFO main.go:20 控制台日志示例 {"user_id": 42}
*/
EncoderConfig类型
type EncoderConfig struct {
// 日志消息的键名(如不设置则隐藏消息字段)
MessageKey string `json:"messageKey" yaml:"messageKey"`
// 日志级别的键名(如不设置则隐藏级别字段)
LevelKey string `json:"levelKey" yaml:"levelKey"`
// 时间戳的键名(如不设置则隐藏时间字段)
TimeKey string `json:"timeKey" yaml:"timeKey"`
// 记录器名称的键名(如不设置则隐藏名称字段)
NameKey string `json:"nameKey" yaml:"nameKey"`
// 调用者信息的键名(如不设置则隐藏调用者字段)
CallerKey string `json:"callerKey" yaml:"callerKey"`
// 函数名的键名(如不设置则隐藏函数名字段)
FunctionKey string `json:"functionKey" yaml:"functionKey"`
// 堆栈跟踪的键名(如不设置则隐藏堆栈字段)
StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"`
// 是否跳过自动换行符(默认 false,自动添加换行)
SkipLineEnding bool `json:"skipLineEnding" yaml:"skipLineEnding"`
// 自定义换行符(默认 "\n",Windows 可设为 "\r\n")
LineEnding string `json:"lineEnding" yaml:"lineEnding"`
// 日志级别的编码方式(如大写、小写、带颜色)
EncodeLevel LevelEncoder `json:"levelEncoder" yaml:"levelEncoder"`
// 时间戳的编码格式(如 ISO8601、时间戳)
EncodeTime TimeEncoder `json:"timeEncoder" yaml:"timeEncoder"`
// 持续时间的编码方式(如秒、毫秒、可读字符串)
EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"`
// 调用者信息的编码方式(如完整路径、短路径)
EncodeCaller CallerEncoder `json:"callerEncoder" yaml:"callerEncoder"`
// 记录器名称的编码方式(默认 FullNameEncoder 显示完整名称)
EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"`
// 自定义反射类型(interface{})的编码器(默认使用标准库的 json.Encoder)
NewReflectedEncoder func(io.Writer) ReflectedEncoder `json:"-" yaml:"-"`
// 控制台编码器的字段分隔符(默认 "\t",可改为空格等)
ConsoleSeparator string `json:"consoleSeparator" yaml:"consoleSeparator"`
}
2.4 WriteSyncer接口
WriteSyncer
是 Zap 中定义的一个接口,结合了 io.Writer
和 Sync()
方法,用于写入日志数据并同步缓冲区。
type WriteSyncer interface {
io.Writer // 写入字节数据
Sync() error // 同步缓冲区到持久存储
}
2.4.1 AddSync(w io.Writer) WriteSyncer
作用:将任意 io.Writer
转换为 WriteSyncer
。若 w
已实现 Sync()
,则直接使用;否则添加空操作 Sync()
。
适用场景:适配非 WriteSyncer
的写入目标(如网络流、缓冲区)。
示例:
// 将 bytes.Buffer 转换为
WriteSyncer buf := new(bytes.Buffer)
ws := zapcore.AddSync(buf)
logger := zap.New(zapcore.NewCore(encoder, ws, zap.InfoLevel))
2.4.2 Lock(ws WriteSyncer) WriteSyncer
作用:用互斥锁包装 WriteSyncer
,实现并发安全写入。
适用场景:多 Goroutine 共享同一写入目标(如文件、标准输出)。
示例:
file, _ := os.Create("app.log")
lockedWs := zapcore.Lock(zapcore.AddSync(file)) // 确保并发安全
core := zapcore.NewCore(encoder, lockedWs, zap.InfoLevel)
logger := zap.New(core)
2.4.3 NewMultiWriteSyncer(ws ...WriteSyncer) WriteSyncer
作用:将日志同时写入多个目标(类似 io.MultiWriter
)。
适用场景:日志多路输出(如文件 + 控制台 + 远程服务)。
示例:
// 输出到文件和控制台
file, _ := os.Create("app.log")
stdoutWs := zapcore.AddSync(os.Stdout)
multiWs := zapcore.NewMultiWriteSyncer(fileWs, stdoutWs)
core := zapcore.NewCore(encoder, multiWs, zap.InfoLevel)
logger := zap.New(core)
2.4.4 示例
并发安全地写入文件,并同时输出到控制台和远程服务。
package main
import (
"bytes"
"net/http"
"os"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// 模拟远程日志服务
type RemoteSink struct {
url string
client *http.Client
}
func (r *RemoteSink) Write(p []byte) (int, error) {
resp, err := r.client.Post(r.url, "application/json", bytes.NewReader(p))
if err != nil {
return 0, err
}
defer resp.Body.Close()
return len(p), nil
}
func (r *RemoteSink) Sync() error {
return nil // 无操作
}
func main() {
// 1. 创建多个写入目标
file, _ := os.Create("app.log")
remote := &RemoteSink{url: "http://logs.example.com", client: http.DefaultClient}
// 2. 转换为 WriteSyncer 并组合
fileWs := zapcore.Lock(zapcore.AddSync(file)) // 文件(并发安全)
remoteWs := zapcore.AddSync(remote) // 远程服务
stdoutWs := zapcore.AddSync(os.Stdout) // 控制台
multiWs := zapcore.NewMultiWriteSyncer(fileWs, remoteWs, stdoutWs)
// 3. 创建 Core
encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
core := zapcore.NewCore(encoder, multiWs, zap.InfoLevel)
// 4. 构建 Logger
logger := zap.New(core)
defer logger.Sync()
// 5. 并发写入测试
for i := 0; i < 10; i++ {
go func(id int) {
logger.Info("并发日志", zap.Int("goroutine_id", id))
}(i)
}
}
2.5 Level类型
Level
表示日志的优先级级别,值越高表示越重要。
type Level int8
级别
值
说明
DebugLevel
-1
调试信息,通常在生产环境中关闭。
InfoLevel
0
常规信息,默认日志级别。
WarnLevel
1
警告信息,需关注但无需立即处理。
ErrorLevel
2
错误信息,应用程序仍可运行但需排查。
DPanicLevel
3
严重错误,开发环境下会触发 panic。
PanicLevel
4
记录日志后触发 panic。
FatalLevel
5
记录日志后调用 os.Exit(1)
终止程序。
InvalidLevel
6
无效级别,用于错误处理。
2.5.1 LevelOf(enab LevelEnabler) Level
作用:获取 LevelEnabler
(如 Core
)的最低启用级别。
参数:enab LevelEnabler
(需实现 Level() Level
方法)。
返回:启用的最低级别或 InvalidLevel
。
示例:
core := zapcore.NewCore(..., zap.InfoLevel)
currentLevel := zapcore.LevelOf(core) // 返回 InfoLevel
2.5.2 ParseLevel(text string) (Level, error)
作用:将字符串解析为 Level
(不区分大小写)。
示例:
level, err := zapcore.ParseLevel("warn") // 返回 WarnLevel, nil
level, err := zapcore.ParseLevel("FATAL") // 返回 FatalLevel, nil
2.5.3 (l Level) CapitalString() string
作用:返回级别的大写字符串(如 "INFO", "ERROR")。 示例:
zapcore.InfoLevel.CapitalString() // "INFO"
zapcore.ErrorLevel.CapitalString() // "ERROR"
2.5.4 (l Level) Enabled(lvl Level) bool
作用:检查给定级别是否高于或等于当前级别。 示例:
zapcore.InfoLevel.Enabled(zapcore.WarnLevel) // false
zapcore.InfoLevel.Enabled(zapcore.DebugLevel) // true
2.5.5 (l *Level) Get() interface{}
作用:实现 flag.Getter
接口,用于命令行参数解析。
示例:
var level zapcore.Level
flag.Var(&level, "log-level", "日志级别")
flag.Parse()
fmt.Println(level.Get()) // 输出当前级别
2.5.6 (l *Level) Set(s string) error
作用:实现 flag.Value
接口,从字符串设置级别。
示例:
var level zapcore.Level
_ = level.Set("error") // 设置为 ErrorLevel
2.5.7 (l Level) String() string
作用:返回级别的小写字符串(如 "info", "error")。 示例:
zapcore.WarnLevel.String() // "warn"
2.5.8 (l *Level) UnmarshalText(text []byte) error
作用:从文本反序列化级别(用于配置文件解析)。 示例:
var level zapcore.Level
_ = level.UnmarshalText([]byte("debug")) // 设置为 DebugLevel
最后更新于