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 为可选字段,留空时在编码时会被忽略。

    • CallerStack 需通过 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.WriterSync() 方法,用于写入日志数据并同步缓冲区。

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

最后更新于