Go 语言怎么使用 zap 日志库?

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Go 语言怎么使用 zap 日志库?

01

介绍

我们在之前的文章中介绍过标准库 log 包的使用方式,它虽然使用方便,但是它支持的功能比较简单。

本文我们介绍 uber 开源的日志库 zap,首先使用 Gin 框架构建一个 Web 应用,然后通过在该 Web 应用中记录日志,来介绍 zap 的使用方式。

最后,我们再使用开源的日志切割库 lumberjack,进行日志切割。

使用 Gin 构建一个 Web 应用

本文重点不是介绍 gin 框架的使用方式,所以我们仅使用 gin 框架构建一个简单的 Web 应用,代码如下:

func main() {
 r := gin.Default()
 r.GET("/ping", ping)
 r.Run()
}
func ping(c *gin.Context) {
 c.JSON(http.StatusOK, gin.H{
  "message": "pong",
 })
}

阅读上面这段代码,访问 http://127.0.0.1:8080/ping,返回结果是 {"message":"pong"}

然后,我们使用 zap 记录 ping 函数的请求日志。

03

Gin 框架使用 zap 日志库

Zap 支持两种模式,分别是 SugaredLoggerLogger,其中 SugaredLogger 模式比 Logger 模式执行速度更慢。

SugaredLogger 模式

使用 Zap 日志库,首先需要使用 New 函数创建一个 Logger,代码如下:

func New(core zapcore.Core, options ...Option) *Logger

使用 New 函数,接收一个 zapcore.Core 类型的参数和一个 Option 类型的可选参数,返回一个 *Logger

其中 zap.Core 类型的参数,可以使用 NewCore 函数创建,接收三个参数,分别是 zapcore.Encoder 类型,zapcore.WriteSyncer 类型和 zapcore.LevelEnabler 类型,分别用于指定日志格式、日志路径和日志级别。

func NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler) Core

其中 zapcore.Encoder 类型的参数,可以使用 NewProductionEncoderConfig 函数创建,返回一个用于生产环境的固定日志编码配置。

// NewProductionEncoderConfig returns an opinionated EncoderConfig for
// production environments.
func NewProductionEncoderConfig() zapcore.EncoderConfig {
 return zapcore.EncoderConfig{
  TimeKey:        "ts",
  LevelKey:       "level",
  NameKey:        "logger",
  CallerKey:      "caller",
  FunctionKey:    zapcore.OmitKey,
  MessageKey:     "msg",
  StacktraceKey:  "stacktrace",
  LineEnding:     zapcore.DefaultLineEnding,
  EncodeLevel:    zapcore.LowercaseLevelEncoder,
  EncodeTime:     zapcore.EpochTimeEncoder,
  EncodeDuration: zapcore.SecondsDurationEncoder,
  EncodeCaller:   zapcore.ShortCallerEncoder,
 }
}

我们可以修改任意配置选项的值。

其中 zapcore.WriteSyncer 类型的参数,可以使用 AddSync 函数创建,该函数接收一个 io.Writer 类型的参数。

func AddSync(w io.Writer) WriteSyncer

其中 zapcore.LevelEnabler 类型的参数,可以使用 zapcore 包定义的常量 zapcore.DebugLevel,该常量是 zapcore.Level 类型,并且 zapcore.Level 类型实现了 zapcore.LevelEnabler 接口。

完整代码:

var sugaredLogger *zap.SugaredLogger
func main() {
 InitLogger()
 defer sugaredLogger.Sync()
 r := gin.Default()
 r.GET("/ping", ping)
 r.Run()
}
func ping(c *gin.Context) {
 sugaredLogger.Debug("call func ping")
 c.JSON(http.StatusOK, gin.H{
  "message": "pong",
 })
}
func InitLogger() {
 core := zapcore.NewCore(enc(), ws(), enab())
 logger := zap.New(core)
 sugaredLogger = logger.Sugar()
}
func enc() zapcore.Encoder {
 cfg := zap.NewProductionEncoderConfig()
 cfg.TimeKey = "time"
 cfg.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05")
 return zapcore.NewJSONEncoder(cfg)
}
func ws() zapcore.WriteSyncer {
 logFileName := fmt.Sprintf("./%v.log", time.Now().Format("2006-01-02"))
 logFile, err := os.Create(logFileName)
 if err != nil {
  log.Fatal(err)
 }
 return zapcore.AddSync(logFile)
}
func enab() zapcore.LevelEnabler {
 return zapcore.DebugLevel
}

运行程序,执行 curl http://127.0.0.1:8080/ping

可以看到,生成的日志文件 xxx.log,文件中是 json 格式的日志内容,我们可以根据实际需求修改为其他格式。

开发中,可能我们希望日志可以同时输出到日志文件和终端中,可以使用函数 NewMultiWriteSyncer,代码如下:

func wsV2() zapcore.WriteSyncer {
 return zapcore.NewMultiWriteSyncer(ws(), zapcore.AddSync(os.Stdout))
}

除了使用 zap.New() 创建 Logger 之外,Zap 还提供了开箱即用的三种创建 Logger 的方式,分别是函数 NewProductionNewDevelopmentExample(),感兴趣的读者朋友们,可以试用一下。

Logger 模式

接下来,我们简单介绍一下 Logger 模式,它主要用于性能和类型安全比较重要的场景中,但是,它没有 SugaredLogger 模式简单易用,我们可以根据实际场景选择使用哪种模式。

我们修改一下现有代码,新创建 InitLoggerV2 函数,其中 encwsenab 函数的代码与 SugaredLogger 模式保持一致。

var loggerV2 *zap.Logger
func main() {
 InitLoggerV2()
 defer loggerV2.Sync()
 r := gin.Default()
 r.GET("/ping", ping)
 r.Run()
}
func ping(c *gin.Context) {
 loggerV2.Debug("call func ping", zap.Int("code", 200))
 c.JSON(http.StatusOK, gin.H{
  "message": "pong",
 })
}
func InitLoggerV2() {
 core := zapcore.NewCore(enc(), ws(), enab())
 loggerV2 = zap.New(core)
}

阅读上面这段代码,我们可以发现,在使用 zap 记录日志时,我们需要显示指定数据类型,一般用于性能和类型安全比较重要的场景中。

04

zap 日志库使用 lumberjack 库进行日志切割

Zap 日志库也不支持日志切割的功能,我们可以使用 lumberjack 日志切割库进行日志切割,关于 lumberjack 库的使用方式,我们在之前的文章介绍过,此处不再重复介绍,直接上代码:

func wsV3() zapcore.WriteSyncer {
 logFileName := fmt.Sprintf("./%v.log", time.Now().Format("2006-01-02"))
 lumberjackLogger := &lumberjack.Logger{
  Filename:   logFileName,
  MaxSize:    1,
  MaxBackups: 3,
  MaxAge:     28,
  Compress:   false,
 }
 return zapcore.AddSync(lumberjackLogger)
}

lumberjack.Logger 的字段含义:

  • Filename 日志保存文件路径
  • MaxSize 日志文件大小,单位是 MB
  • MaxBackups 保留的日志文件数量
  • MaxAge 日志文件的最长保留时间,单位是天
  • Compress 日志文件是否需要压缩

05

总结

本文我们通过在 Gin 构建的应用中,使用 Zap 记录请求日志,介绍了 Zap 的使用方式,最后还通过 lumberjack 日志切割库进行切割日志。

更多关于 Zap 的内容,感兴趣的读者朋友们可以阅读官方文档或源码。

推荐阅读:

参考资料:

  1. https://github.com/uber-go/zap
  2. https://pkg.go.dev/go.uber.org/zap


相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
9天前
|
存储 监控 算法
防止员工泄密软件中文件访问日志管理的 Go 语言 B + 树算法
B+树凭借高效范围查询与稳定插入删除性能,为防止员工泄密软件提供高响应、可追溯的日志管理方案,显著提升海量文件操作日志的存储与检索效率。
41 2
|
6月前
|
JavaScript 前端开发 Java
通义灵码 Rules 库合集来了,覆盖Java、TypeScript、Python、Go、JavaScript 等
通义灵码新上的外挂 Project Rules 获得了开发者的一致好评:最小成本适配我的开发风格、相当把团队经验沉淀下来,是个很好功能……
1249 103
|
3月前
高性能网络库设计之日志组件
高性能网络库设计之日志组件
139 2
|
11月前
|
安全 Go
用 Zap 轻松搞定 Go 语言中的结构化日志
在现代应用程序开发中,日志记录至关重要。Go 语言中有许多日志库,而 Zap 因其高性能和灵活性脱颖而出。本文详细介绍如何在 Go 项目中使用 Zap 进行结构化日志记录,并展示如何定制日志输出,满足生产环境需求。通过基础示例、SugaredLogger 的便捷使用以及自定义日志配置,帮助你在实际开发中高效管理日志。
351 1
|
7月前
|
Go 开发者
go-carbon v2.6.0 重大版本更新,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持
137 3
|
7月前
|
JSON API Go
基于责任链与策略模式的轻量级PHP日志库设计
项目日志乱成一团,bug 时好时坏,服务器问题难以复现?我写了个 PHP 日志系统,第一时间发现问题,避免跑路。实现了责任链模式+策略模式,让日志存储更灵活,支持多种输出方式。
|
8月前
|
网络协议 Linux Go
用 Go 基于 epoll 实现一个最小化的IO库
Go 语言社区中存在多个异步网络框架,如 evio、nbio、gnet 和 netpoll 等。这些框架旨在解决标准库 netpoll 的低效问题,如一个连接占用一个 goroutine 导致的资源浪费。easyio 是一个最小化的 IO 框架,核心代码不超过 500 行,仅实现 Linux 下的 epoll 和 TCP 协议。它通过 Worker Pool、Buffer 等优化提高了性能,并提供了简单的事件处理机制。
114 0
|
11月前
|
JSON Go 开发者
go-carbon v2.5.0 发布,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持。
230 4
|
11月前
|
存储 Go PHP
Go语言中的加解密利器:go-crypto库全解析
在软件开发中,数据安全和隐私保护至关重要。`go-crypto` 是一个专为 Golang 设计的加密解密工具库,支持 AES 和 RSA 等加密算法,帮助开发者轻松实现数据的加密和解密,保障数据传输和存储的安全性。本文将详细介绍 `go-crypto` 的安装、特性及应用实例。
552 0
|
20天前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
73 1