104 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			104 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | 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() | |||
|  | 	} | |||
|  | }  |