Gin项目中添加zap日志

本文介绍了如何在Go项目中使用zap日志库与gin框架结合,包括不同日志对象的创建、gin框架中的Logger和Recovery中间件,以及如何配置和自定义日志输出。
摘要由CSDN通过智能技术生成

先将zap的包导入到项目中

"go.uber.org/zap"
了解一下zap日志存储信息的两种方式
zap.NewProduction() 创建的日志对象输出格式为 JSON

zap.NewDevelopment() 创建的日志对象输出格式为 Text

gin项目中 常用的两种注册路由方式

gin.Default(),这是一个默认的路由引擎,已经配置了一些常用的中间件,比如日志和恢复中间件

gin.New(),这是一个空的路由引擎,然后根据需要手动添加中间件和路由处理函数

Logger中间件:用于记录请求和响应的详情信息,包括请求方法,路径,状态码,处理时间等。会自动在请求处理的前后自动打印日志,默认情况下输出到了控制台。

Recovery中间件:用来捕获并处理程序汇总的panic异常。如果发生panic异常,该中间件会恢复程序运行并返回一个500内部服务器错误响应,同时打印引发panic的错误信息。

gin.New()添加两个中间件的方法

如果此时使用gin.New并且手动添加了这两个中间件,那基本和gin.Default是一样的了

下面是两个中间件的写法:

// GinLogger 接收gin框架默认的日志
func GinLogger() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		path := c.Request.URL.Path
		query := c.Request.URL.RawQuery
		c.Next()
		cost := time.Since(start)
		lg.Info(path,
			zap.Int("status", c.Writer.Status()),
			zap.String("method", c.Request.Method),
			zap.String("path", path),
			zap.String("query", query),
			zap.String("ip", c.ClientIP()),
			zap.String("user-agent", c.Request.UserAgent()),
			zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
			zap.Duration("cost", cost),
		)
	}
}
// GinRecovery recover掉项目可能出现的panic,并使用zap记录相关日志
func GinRecovery(stack bool) gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				// Check for a broken connection, as it is not really a
				// condition that warrants a panic stack trace.
				var brokenPipe bool
				if ne, ok := err.(*net.OpError); ok {
					if se, ok := ne.Err.(*os.SyscallError); ok {
						if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
							brokenPipe = true
						}
					}
				}
				httpRequest, _ := httputil.DumpRequest(c.Request, false)
				if brokenPipe {
					lg.Error(c.Request.URL.Path,
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
					// If the connection is dead, we can't write a status to it.
					c.Error(err.(error)) // nolint: errcheck
					c.Abort()
					return
				}

				if stack {
					lg.Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
						zap.String("stack", string(debug.Stack())),
					)
				} else {
					lg.Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
				}
				c.AbortWithStatus(http.StatusInternalServerError)
			}
		}()
		c.Next()
	}
}

添加了之后,然后再启动路由的地方,将两个中间件添加进去

	g := gin.New()
	g.Use(logger.GinLogger(),logger.GinRecovery(true))

zap日志如果添加到gin项目中

无论使用哪种注册路由的方法,都需要有下面这些步骤!

首先调用getLogWriter() 获取日志写入目标,该例子 使用了 lumberjack.Logger 实现日志文件的处理
接着调用 getEncoder() 获取日志编码器,该例子是用 JSON 编码器,然后对编码器相关配置进行设置
最后在 Init() 进行日志初始化

  1. 解析配置文件中的日志级别配置,创建相应的日志级别对象。
  2. 根据模式选择日志输出方式,如果是开发模式则将日志输出到控制台以便调试,否则只创建一个日志核心。
  3. 创建日志核心(core),指定编码器和输出目标。
  4. 根据需要添加其他日志核心,例如同时输出到文件和控制台。
  5. 调用 zap.New() 函数创建日志记录器,将上述步骤中创建的核心加入到记录器中。
  6. 通过 zap.ReplaceGlobals() 函数替换全局的日志记录器,以便在任何位置都可以使用该记录器。
var lg *zap.Logger

func Init(cfg *settings.LogConfig, mode string) (err error) {
	// 获取 日志 写入目标
	writeSyncer := getLogWriter()
	// 获取 日志编码器
	encoder := getEncoder()
	// 解析 日志级别配置
	var l = new(zapcore.Level)
	err = l.UnmarshalText([]byte(cfg.Level))
	if err != nil {
		return
	}
	var core zapcore.Core
	// 根据模式选择日志输出方式
	if mode == "dev" {
		// 进入开发模式,日志输出到终端
		// 创建控制台编码器
		consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
		// 创建多个 日志核心(core),分别指定不同的编码器和输出目标
		core = zapcore.NewTee(
			zapcore.NewCore(encoder, writeSyncer, l),  // JSON 编码器和指定的写入目标
			zapcore.NewCore(consoleEncoder, zapcore.Lock(os.Stdout), zapcore.DebugLevel),  // 控制台编码器和标准输出目标

		)
	} else {
		core = zapcore.NewCore(encoder, writeSyncer, l)   	// 默认模式下,只创建一个日志核心
	}
	lg = zap.New(core, zap.AddCaller())            	// 创建日志记录器
	zap.ReplaceGlobals(lg)                           // 替换全局日志记录器
	zap.L().Info("init logger success")           // 打印初始化成功的日志消息
	return
}

// 设置 zap 日志库的 日志编码器
func getEncoder() zapcore.Encoder {
	// 创建一个默认的生产环境编码器配置
	encoderConfig := zap.NewProductionEncoderConfig()
	// 将时间戳格式设置为 ISO8601 格式
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	// 设置时间键名为 "time"
	encoderConfig.TimeKey = "time"
	// 将日志级别编码为大写形式
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	// 将日志记录中的持续时间编码为以秒为单位的浮点数
	encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder
	// 将日志记录中的调用者信息编码为短格式(仅显示文件名和行号)
	encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
	// 使用以上设置创建一个 JSON 编码器
	return zapcore.NewJSONEncoder(encoderConfig)
}

// 创建一个 zapcore.WriteSyncer对象,用户将日志写入指定的文件中
func getLogWriter() zapcore.WriteSyncer {
	// 创建一个 lumberjack.Logger 对象,用于日志文件的处理
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "./app/logger/myapp.log",  // 日志文件名
		MaxSize:    10,   // 单个日志文件的大小上限  (MB为单位)
		MaxBackups: 10, // 保留旧日志文件最大个数
		MaxAge:     10,   // 日志保留的时间
	}
	// 将 lumberjack.Logger 转换为 zapcore.WriteSyncer 对象
	return zapcore.AddSync(lumberJackLogger)
}

// 结构体的信息
type LogConfig struct {
	Level      string `mapstructure:"level"`
	Filename   string `mapstructure:"filename"`
	MaxSize    int    `mapstructure:"max_size"`
	MaxAge     int    `mapstructure:"max_age"`
	MaxBackups int    `mapstructure:"max_backups"`
}

// 下面是配置yaml中的信息
mode: "dev"
port: 8080

log:
  level: "debug"
  filename: "./log/bluebell.log"
  max_size: 1000
  max_age: 3600
  max_backups: 5

最终在项目启动的时候,进行调用初始化日志的函数

	// 1.加载配置
	if err := settings.Init(); err != nil {
		fmt.Printf("配置信息加载失败: %v\n", err)
		return
	}
	// 2.初始化日志
	if err := logger.Init(settings.Conf.LogConfig, settings.Conf.Mode); err != nil {
		fmt.Printf("init logger failed, err:%v\n", err)
		return
	}

这样一个日志就成功添加到了项目中。

项目中自定义记录信息到zap日志中

在项目中我们可以根据需要是使用 zap.L().Xxx() 方法来记录自定义日志信息。

就比如:zap.L().Debug("日志初始化成功")

zap.L() 返回一个 全局的 日志记录器,通过该记录器可以进行日志的输出

Debug() 是记录器提供的一个方法,用户输出调试级别的日志信息

("日志初始化成功") 是要输出的具体日志信息内容。

除了 Debug() 还有其他一些的方法

  • Info(): 输出信息级别的日志消息。
  • Warn(): 输出警告级别的日志消息。
  • Error(): 输出错误级别的日志消息。
  • DPanic(): 输出严重错误级别的日志消息,并触发 panic。
  • Panic(): 输出严重错误级别的日志消息,并触发 panic。
  • Fatal(): 输出严重错误级别的日志消息,并调用 os.Exit(1) 终止程序。

image-20240128105123838

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值