Files
tyapi-server/internal/shared/middleware/panic_recovery.go

104 lines
2.7 KiB
Go
Raw Normal View History

2025-07-28 15:21:37 +08:00
package middleware
import (
"net/http"
"runtime/debug"
"time"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// PanicRecoveryMiddleware Panic恢复中间件
type PanicRecoveryMiddleware struct {
logger *zap.Logger
}
// NewPanicRecoveryMiddleware 创建Panic恢复中间件
func NewPanicRecoveryMiddleware(logger *zap.Logger) *PanicRecoveryMiddleware {
return &PanicRecoveryMiddleware{
logger: logger,
}
}
// GetName 返回中间件名称
func (m *PanicRecoveryMiddleware) GetName() string {
return "panic_recovery"
}
// GetPriority 返回中间件优先级
func (m *PanicRecoveryMiddleware) GetPriority() int {
return 100 // 最高优先级,第一个执行
}
// Handle 返回中间件处理函数
func (m *PanicRecoveryMiddleware) Handle() gin.HandlerFunc {
return gin.RecoveryWithWriter(&panicLogger{logger: m.logger})
}
// IsGlobal 是否为全局中间件
func (m *PanicRecoveryMiddleware) IsGlobal() bool {
return true
}
// panicLogger 实现io.Writer接口用于记录panic信息
type panicLogger struct {
logger *zap.Logger
}
// Write 实现io.Writer接口
func (pl *panicLogger) Write(p []byte) (n int, err error) {
pl.logger.Error("系统发生严重错误",
zap.String("error_type", "panic"),
zap.String("stack_trace", string(p)),
zap.String("timestamp", time.Now().Format("2006-01-02 15:04:05")),
)
return len(p), nil
}
// CustomPanicRecovery 自定义panic恢复中间件
func (m *PanicRecoveryMiddleware) CustomPanicRecovery() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
// 获取请求信息
requestID := c.GetString("request_id")
traceID := c.GetString("trace_id")
userID := c.GetString("user_id")
clientIP := c.ClientIP()
method := c.Request.Method
path := c.Request.URL.Path
userAgent := c.Request.UserAgent()
// 记录详细的panic信息
m.logger.Error("系统发生严重错误",
zap.Any("panic_error", err),
zap.String("error_type", "panic"),
zap.String("request_id", requestID),
zap.String("trace_id", traceID),
zap.String("user_id", userID),
zap.String("client_ip", clientIP),
zap.String("method", method),
zap.String("path", path),
zap.String("user_agent", userAgent),
zap.String("stack_trace", string(debug.Stack())),
zap.String("timestamp", time.Now().Format("2006-01-02 15:04:05")),
)
// 返回500错误响应
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "服务器内部错误",
"error_code": "INTERNAL_SERVER_ERROR",
"request_id": requestID,
"timestamp": time.Now().Unix(),
})
// 中止请求处理
c.Abort()
}
}()
c.Next()
}
}