package middleware import ( "net/http" "runtime/debug" "github.com/gin-gonic/gin" "go.uber.org/zap" ) // Recovery middleware personnalisé avec logging structuré // Capture les panics et les log avec stack trace et contexte // MOD-P1-005: Stack traces seulement si includeStackTrace=true (dev/DEBUG mode) func Recovery(logger *zap.Logger, includeStackTrace bool) gin.HandlerFunc { return func(c *gin.Context) { defer func() { if err := recover(); err != nil { requestID, _ := c.Get("request_id") // MOD-P1-005: Stack traces seulement en development/debug, pas en prod var stack []byte if includeStackTrace { stack = debug.Stack() } // Construire les champs de log logFields := []zap.Field{ zap.Any("error", err), zap.String("path", c.Request.URL.Path), zap.String("method", c.Request.Method), } if len(stack) > 0 { logFields = append(logFields, zap.ByteString("stack", stack)) } // Ajouter request_id si disponible if requestID != nil { if requestIDStr, ok := requestID.(string); ok { logFields = append(logFields, zap.String("request_id", requestIDStr)) } } // Ajouter user_id si disponible if userID, exists := c.Get("user_id"); exists { logFields = append(logFields, zap.Any("user_id", userID)) } logger.Error("Panic recovered", logFields...) // Retourner une erreur 500 standardisée c.JSON(http.StatusInternalServerError, gin.H{ "error": gin.H{ "code": 9000, "message": "Internal server error", }, }) c.Abort() } }() c.Next() } }