Gin框架整合Zap日志库

1,216 阅读3分钟

Gin是一款轻量级的web框架,同时也支持高性能的路由和中间件功能。Zap是Uber开发的一个高性能的日志库,比标准库的log包性能更好,而且支持多个日志级别和可配置的日志输出。

本文将介绍如何在Gin框架中整合Zap日志库,以便记录应用程序的日志并增加其稳定性。

第一步:安装Zap日志库

Zap日志库可以通过go get命令进行安装:

go get go.uber.org/zap

第二步:创建Zap日志库记录器

在Gin应用程序中使用Zap记录日志需要先创建一个记录器,并定义其配置选项。例如,以下代码段创建了一个配置了输出到控制台的记录器:

import "go.uber.org/zap"

func NewLogger() (*zap.Logger,error){
    config := zap.Config{
      Encoding: "console",
      Level:    zap.NewAtomicLevelAt(zap.DebugLevel),
      OutputPaths: []string{"stdout"},
      ErrorOutputPaths: []string{"stderr"},
      EncoderConfig: zap.NewDevelopmentEncoderConfig(),
    }
    return config.Build()
}

上面的代码中,我们创建了一个Zap配置对象,其中包括以下选项:

  • Encoding:设置输出编码格式,这里使用的是console,也可以配置为json等。
  • Level:设置日志输出的级别,这里设置为debug级别。
  • OutputPaths:设置日志输出的路径,这里设置为控制台(stdout)。
  • ErrorOutputPaths:设置错误日志输出的路径,这里设置为标准错误(stderr)
  • EncoderConfig:设置输出格式的细节,比如时间戳、输出颜色等。

在我们的示例应用程序中,我们将配置用于输出调试信息,最后返回一个Zap日志记录器。

第三步:在Gin应用程序中使用Zap记录日志

为了在Gin应用程序中使用Zap日志记录器,我们需要在中间件或处理程序函数中调用它。

import "github.com/gin-gonic/gin"

func main() {
  r := gin.Default()
  logger,err := NewLogger()
  if err != nil{
      panic(err)
  }
  defer logger.Sync()
  
  r.Use(func(c *gin.Context){
      logger.Info("Before request", zap.Any("request", c.Request))
      c.Next()
      logger.Info("After request",zap.Any("response",c.Writer.Status()))
  })
  
  r.GET("/hello", func(c *gin.Context) {
    c.JSON(200, gin.H{
      "message": "Hello World",
    })
  })
  
  r.Run() // listen and serve on 0.0.0.0:8080
}

上面的代码中,我们创建了一个Gin记录请求的中间件,我们在该中间件函数的开始和结束位置记录请求和响应数据。使用zap.Any方法记录内容的类型可能不同,包括字符串、数字、时间等等。这里我们使用了两个不同的Logger.Info函数来记录请求的开始和结束。使用defer logger.Sync()最终确保将任何未写入磁盘的日志条目刷新到磁盘。

启动应用程序,并在浏览器中访问http://localhost:8080/hello,Gin框架将记录请求信息和响应信息,记录的内容可以在控制台中查看。

结论

本文介绍了如何在Gin应用程序中使用Zap日志库来记录日志和增加应用程序的稳定性。我们首先安装了Zap包,并创建了一个Zap配置和记录器。然后,我们在Gin应用程序中使用这个记录器来记录请求和响应的信息。这将帮助开发人员更好地了解其应用程序的性能和稳定性。

完整代码

package main

import (
   "github.com/gin-gonic/gin"
   "go.uber.org/zap"
   "time"
)

func NewLogger() (*zap.Logger, error) {
   config := zap.Config{
      Encoding:         "console",
      Level:            zap.NewAtomicLevelAt(zap.DebugLevel),
      OutputPaths:      []string{"stdout"},
      ErrorOutputPaths: []string{"stderr"},
      EncoderConfig:    zap.NewDevelopmentEncoderConfig(),
   }
   return config.Build()
}

func Logger() gin.HandlerFunc {
   logger, err := NewLogger()
   if err != nil {
      panic(err)
   }
   return func(c *gin.Context) {
      // 执行时间
      nowTime := time.Now()
      logger.Info("Before request", zap.Any("request", c.Request.URL))
      c.Next()
      logger.Info("After request", zap.Any("response", c.Writer.Status()))
      // ip
      logger.Info("IP", zap.String("ip", c.ClientIP()))
      // method
      logger.Info("Method", zap.String("method", c.Request.Method))
      // path
      logger.Info("Path", zap.String("path", c.Request.URL.Path))
      // status
      logger.Info("Status", zap.Int("status", c.Writer.Status()))
      // latency
      logger.Info("Latency", zap.Duration("latency", time.Since(nowTime)))
   }
}

func main() {
   r := gin.Default()
   logger, err := NewLogger()
   if err != nil {
      panic(err)
   }
   defer logger.Sync()

   r.Use(Logger())

   r.GET("/hello", func(c *gin.Context) {
      logger.Info("logger info")   // 会输出到控制台
      logger.Warn("logger warn")   // 会输出到控制台
      logger.Error("logger error") // 会输出到控制台, 打印堆栈信息
      logger.Debug("logger debug") // 会输出到控制台
      //logger.Fatal("logger fatal") // 会导致程序退出
      logger.Panic("logger panic") // 会导致程序退出,打印堆栈信息
      c.JSON(200, gin.H{
         "message": "Hello World",
      })
   })

   r.Run() // listen and serve on 0.0.0.0:8080
}