| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- package middlewares
- import (
- "net"
- "net/http"
- "net/http/httputil"
- "os"
- "strings"
- "time"
- "github.com/gin-gonic/gin"
- "github.com/runningwater/gohub/pkg/logger"
- "go.uber.org/zap"
- )
- // Recovery 使用 zap.Error() 来记录 panic 和 call stack
- func Recovery() gin.HandlerFunc {
- return func(c *gin.Context) {
- defer func() {
- if err := recover(); err != nil {
-
- // 获取用户的请求信息
- httpRquest, _ := httputil.DumpRequest(c.Request, true)
- // 链接中断,客户端中断连接为正常行为,不需要记录堆栈信息
- var brokenPipe bool
- if ne, ok := err.(*net.OpError); ok {
- if se, ok := ne.Err.(*os.SyscallError); ok {
- errStr := strings.ToLower(se.Error())
- if strings.Contains(errStr, "broken pipe") || strings.Contains(errStr, "connection reset by peer") {
- brokenPipe = true
- }
- }
- }
- // 链接中断的情况
- if brokenPipe {
- logger.Error(c.Request.URL.Path,
- zap.Time("time", time.Now()),
- zap.Any("error", err),
- zap.String("request", string(httpRquest)),
- )
- c.Error(err.(error))
- c.Abort()
- // 链接已断开,无法写状态
- return
- }
- // 如果不是链接中断的情况,记录堆栈信息
- logger.Error("[Recovery from panic]",
- zap.Time("time", time.Now()), // 记录当前时间
- zap.Any("error", err), // 记录错误信息
- zap.String("request", string(httpRquest)), // 记录请求信息
- zap.Stack("stack"), // 记录堆栈信息
- )
- c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
- "message": "服务器内部错误,请稍后再试",
- })
- }
- }()
- // 继续处理请求
- c.Next()
- }
- }
|