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


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
9天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
29 2
|
7天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
19 2
|
7天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
20 2
|
10天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
7天前
|
Go
go语言中的 跳转语句
【11月更文挑战第4天】
16 4
|
7天前
|
JSON 安全 Go
Go语言中使用JWT鉴权、Token刷新完整示例,拿去直接用!
本文介绍了如何在 Go 语言中使用 Gin 框架实现 JWT 用户认证和安全保护。JWT(JSON Web Token)是一种轻量、高效的认证与授权解决方案,特别适合微服务架构。文章详细讲解了 JWT 的基本概念、结构以及如何在 Gin 中生成、解析和刷新 JWT。通过示例代码,展示了如何在实际项目中应用 JWT,确保用户身份验证和数据安全。完整代码可在 GitHub 仓库中查看。
39 1
|
9天前
|
Go 调度 开发者
探索Go语言中的并发模式:goroutine与channel
在本文中,我们将深入探讨Go语言中的核心并发特性——goroutine和channel。不同于传统的并发模型,Go语言的并发机制以其简洁性和高效性著称。本文将通过实际代码示例,展示如何利用goroutine实现轻量级的并发执行,以及如何通过channel安全地在goroutine之间传递数据。摘要部分将概述这些概念,并提示读者本文将提供哪些具体的技术洞见。
|
15天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
128 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
1月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
231 3
|
1月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1637 14