文章目录
- 基于Zap的中间件
- 在gin项目中使用zap
基于Zap的中间件
在使用gin.Default()的同时是用到了gin框架内的两个默认中间件Logger()和Recovery()。所以我们可以模仿Logger()和Recovery()的实现,使用我们的日志库来接收gin框架默认输出的日志。这里以zap为例,我们实现两个中间件如下:
package middlewareimport ("github.com/gin-gonic/gin""go.uber.org/zap""net""net/http""net/http/httputil""os""runtime/debug""strings""time"
)// GinLogger 接收gin框架默认的日志
func GinLogger(logger *zap.Logger) gin.HandlerFunc {return func(c *gin.Context) {start := time.Now()path := c.Request.URL.Pathquery := c.Request.URL.RawQueryc.Next()cost := time.Since(start)logger.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
func GinRecovery(logger *zap.Logger, 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 boolif 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 {logger.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))c.Abort()return}if stack {logger.Error("[Recovery from panic]",zap.Any("error", err),zap.String("request", string(httpRequest)),zap.String("stack", string(debug.Stack())),)} else {logger.Error("[Recovery from panic]",zap.Any("error", err),zap.String("request", string(httpRequest)),)}c.AbortWithStatus(http.StatusInternalServerError)}}()c.Next()}
}
这样就能在gin框架中使用我们上面定义好的两个中间件来代替gin框架默认的Logger()和Recovery()了。
r.Use(middleware.GinLogger(global.LOGGER), middleware.GinRecovery(global.LOGGER, true))
在gin项目中使用zap
在Gin框架中使用定制日志记录日志的实现如下:
import ("docker_compose_blog/global""go.uber.org/zap""go.uber.org/zap/zapcore""gopkg.in/natefinch/lumberjack.v2"
)func Logger() {encoder := getEncoder()writeSyncer := getLogWriter()core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)global.LOGGER = zap.New(core, zap.AddCaller())
}func getEncoder() zapcore.Encoder {// 得到编码配置encoderConfig := zap.NewProductionEncoderConfig()// 通过配置修改时间编码规则encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder// 通过配置添加调用者信息encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoderreturn zapcore.NewConsoleEncoder(encoderConfig)
}func getLogWriter() zapcore.WriteSyncer {lumberJackLogger := &lumberjack.Logger{Filename: "./zap/gin.log",MaxSize: 1,MaxBackups: 5,MaxAge: 30,Compress: false,}return zapcore.AddSync(lumberJackLogger)
}
这样只需要在main.go文件中导入Logger()函数,那么就实现了Gin框架中使用Zap日志了。