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