101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
package middleware
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/getsentry/sentry-go"
|
|
"github.com/gin-gonic/gin"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// SentryRecover middleware pour capturer les panics et les erreurs avec Sentry
|
|
func SentryRecover(logger *zap.Logger) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
// Capturer le panic dans Sentry
|
|
hub := sentry.CurrentHub().Clone()
|
|
hub.Scope().SetTag("component", "gin")
|
|
hub.Scope().SetContext("request", map[string]interface{}{
|
|
"method": c.Request.Method,
|
|
"path": c.Request.URL.Path,
|
|
"query": c.Request.URL.RawQuery,
|
|
"ip": c.ClientIP(),
|
|
})
|
|
|
|
// Récupérer le request ID si présent
|
|
if requestID, exists := c.Get("request_id"); exists {
|
|
hub.Scope().SetTag("request_id", requestID.(string))
|
|
}
|
|
|
|
// Récupérer l'user ID si présent
|
|
if userID, exists := c.Get("user_id"); exists {
|
|
hub.Scope().SetUser(sentry.User{
|
|
ID: toString(userID),
|
|
Username: toString(userID),
|
|
})
|
|
}
|
|
|
|
// Capturer l'erreur
|
|
if errObj, ok := err.(error); ok {
|
|
hub.CaptureException(errObj)
|
|
} else {
|
|
hub.CaptureMessage(fmt.Sprintf("Panic: %v", err))
|
|
}
|
|
|
|
// Logger l'erreur localement aussi
|
|
if logger != nil {
|
|
logger.Error("Panic recovered",
|
|
zap.Any("error", err),
|
|
zap.String("method", c.Request.Method),
|
|
zap.String("path", c.Request.URL.Path),
|
|
zap.String("ip", c.ClientIP()),
|
|
)
|
|
}
|
|
|
|
// Répondre avec une erreur générique
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"error": "internal server error",
|
|
"message": "An unexpected error occurred",
|
|
})
|
|
c.Abort()
|
|
}
|
|
}()
|
|
|
|
c.Next()
|
|
|
|
// Capturer les erreurs HTTP 5xx
|
|
if c.Writer.Status() >= 500 {
|
|
hub := sentry.CurrentHub().Clone()
|
|
hub.Scope().SetTag("component", "gin")
|
|
hub.Scope().SetTag("status_code", toString(c.Writer.Status()))
|
|
hub.Scope().SetContext("request", map[string]interface{}{
|
|
"method": c.Request.Method,
|
|
"path": c.Request.URL.Path,
|
|
"status": c.Writer.Status(),
|
|
})
|
|
|
|
// Récupérer les erreurs du contexte Gin
|
|
if len(c.Errors) > 0 {
|
|
for _, err := range c.Errors {
|
|
hub.CaptureException(err)
|
|
}
|
|
} else {
|
|
// Créer une erreur générique pour les 5xx sans erreur explicite
|
|
hub.CaptureMessage("HTTP 5xx error without explicit error")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// toString convertit une valeur en string de manière sûre
|
|
func toString(v interface{}) string {
|
|
if v == nil {
|
|
return ""
|
|
}
|
|
if s, ok := v.(string); ok {
|
|
return s
|
|
}
|
|
return ""
|
|
}
|