• 在Gin框架中加入Zap日志中间件


    基于Zap的中间件

    在使用gin.Default()的同时是用到了gin框架内的两个默认中间件Logger()和Recovery()。所以我们可以模仿Logger()和Recovery()的实现,使用我们的日志库来接收gin框架默认输出的日志。这里以zap为例,我们实现两个中间件如下:

    package middleware
    
    import (
    	"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.Path
    		query := c.Request.URL.RawQuery
    		c.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 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 {
    					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()
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    这样就能在gin框架中使用我们上面定义好的两个中间件来代替gin框架默认的Logger()和Recovery()了。

    r.Use(middleware.GinLogger(global.LOGGER), middleware.GinRecovery(global.LOGGER, true))
    
    • 1

    在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.CapitalLevelEncoder
    	return 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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    这样只需要在main.go文件中导入Logger()函数,那么就实现了Gin框架中使用Zap日志了。

  • 相关阅读:
    Apache安装教程
    第二十章·中介者模式
    配置CLion进行嵌入式STM32的HAL库开发
    threejs 加载各种格式的3d模型 封装
    证件照处理
    高考选择:专业优先还是学校优先?
    【C++】-- STL之unordered_map/unordered_set详解
    重学Java8新特性(二) : Stream API、Optional类
    班级新闻管理系统asp.net+sqlserver
    返回文件名问题
  • 原文地址:https://blog.csdn.net/qq_54015483/article/details/133798417