Go Zap 使用

Zap日志库使用文档

Zap是由Uber开源的一个Go语言高性能日志库。它以极高的性能和极少的内存分配著称,非常适合用于对性能要求严苛的场景。

快速入门

首先,你需要安装Zap库:

1
go get -u go.uber.org/zap

下面是一个最简单的使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"go.uber.org/zap"
)

func main() {
// 创建一个开发环境下的Logger,提供了更多调试信息,如文件名和行号
logger, _ := zap.NewDevelopment()
defer logger.Sync() // 确保所有缓冲的日志都写入文件

logger.Info("这是一条普通信息",
zap.String("name", "Go"),
zap.Int("age", 15),
)

logger.Warn("这是一条警告信息")

logger.Error("这是一条错误信息", zap.Error(nil))
}

运行以上代码,你将会在控制台看到如下输出:

1
2
3
{"level":"info","ts":1678886400.123456,"caller":"main/main.go:12","msg":"这是一条普通信息","name":"Go","age":15}
{"level":"warn","ts":1678886400.123456,"caller":"main/main.go:15","msg":"这是一条警告信息"}
{"level":"error","ts":1678886400.123456,"caller":"main/main.go:17","msg":"这是一条错误信息"}

Zap Logger 的类型

Zap 提供了两种主要的 Logger 类型:

  • zap.NewProduction(): 适用于生产环境。它会以 JSON 格式输出日志,并禁用调用者(caller)信息,以获得最佳性能。
  • zap.NewDevelopment(): 适用于开发环境。它会以更易读的格式输出日志,并包含文件和行号信息,方便调试。

如果你需要更细粒度的控制,可以使用 zap.New()zap.Config

核心概念

Logger

*zap.Logger 是 Zap 的核心。它是线程安全的,可以被全局共享。你可以通过它来记录不同级别的日志。

SugaredLogger

为了方便,Zap 还提供了一个更人性化的 SugaredLogger。它使用 Printf 风格的 API,但性能略低于 Logger

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"go.uber.org/zap"
)

func main() {
logger, _ := zap.NewProduction()
defer logger.Sync()

// 转换为 SugaredLogger
sugar := logger.Sugar()

sugar.Infow("记录一个结构化的事件",
"url", "http://example.com",
"attempt", 3,
"backoff", "5s",
)

sugar.Infof("请求失败,重试中... %s", "http://example.com")
}

SugaredLogger 适用于以下场景:

  • 日志格式变化频繁。
  • 应用程序对性能要求不高。
  • 想要快速迁移旧项目中的日志代码。

Field

zap.Field 用于将结构化数据附加到日志中。Zap 提供了多种预定义的 Field 类型,以减少内存分配:

  • 基本类型: zap.String(), zap.Int(), zap.Float64(), zap.Bool()
  • 错误: zap.Error()
  • 时间: zap.Time(), zap.Duration()
  • 通用: zap.Any()(使用反射,性能较低,尽量避免)

高级用法

自定义配置

你可以使用 zap.Config 来完全自定义 Logger 的行为,包括日志级别、输出目标、编码器等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
"os"

"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

func main() {
// 创建一个EncoderConfig,用于配置日志的输出格式
encoderConfig := zap.NewProductionEncoderConfig()
// 设置时间格式为ISO8601
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder

// 创建一个Core,用于定义日志的输出方式
core := zapcore.NewCore(
// 使用JSON编码器,并传入自定义的EncoderConfig
zapcore.NewJSONEncoder(encoderConfig),
// 指定日志写入标准输出
zapcore.AddSync(os.Stdout),
// 设置日志级别为Debug
zapcore.DebugLevel,
)

// 使用New()方法创建Logger,并传入Core
logger := zap.New(core)
defer logger.Sync()

logger.Debug("这条日志是Debug级别的")
logger.Info("这条日志是Info级别的")
}

日志级别

Zap 支持以下日志级别:

  • DebugLevel
  • InfoLevel
  • WarnLevel
  • ErrorLevel
  • DPanicLevel(仅在开发环境panic)
  • PanicLevel
  • FatalLevel(记录日志后调用os.Exit(1))

你可以通过 zap.Configzap.AtomicLevel 来动态更改日志级别。

输出到文件

你可以通过 zapcore.AddSync() 将日志写入文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
"os"
"path/filepath"

"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)

func main() {
// 使用lumberjack进行日志切割
lumberjackLogger := &lumberjack.Logger{
Filename: filepath.Join(os.TempDir(), "app.log"),
MaxSize: 10, // 日志文件最大10MB
MaxBackups: 3, // 保留3个旧文件
MaxAge: 7, // 保留7天
Compress: true, // 压缩旧文件
}

writeSyncer := zapcore.AddSync(lumberjackLogger)

core := zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
writeSyncer,
zap.InfoLevel,
)

logger := zap.New(core)
defer logger.Sync()

logger.Info("日志已成功写入文件")
}

总结

特性 Loggerzap.Logger SugaredLoggerzap.SugaredLogger
性能 更高,零内存分配(zero allocation) 较低,有反射和接口调用开销
API风格 结构化,使用 zap.Field 类似 fmt.Printf
适用场景 对性能要求高,日志格式相对固定,如微服务、高并发应用 快速开发,日志格式不固定,对性能要求不高