feat: backend service
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
// Package panicrecovery converts unrecovered panics into a structured 500
|
||||
// response and a single error-level log entry. It is wired exactly once at the
|
||||
// top of the gin middleware chain.
|
||||
package panicrecovery
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"galaxy/backend/internal/server/httperr"
|
||||
"galaxy/backend/internal/server/middleware/requestid"
|
||||
"galaxy/backend/internal/telemetry"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Middleware returns a gin middleware that recovers from panics, logs the
|
||||
// failure with trace fields, and writes the standard 500 envelope.
|
||||
func Middleware(logger *zap.Logger) gin.HandlerFunc {
|
||||
if logger == nil {
|
||||
logger = zap.NewNop()
|
||||
}
|
||||
|
||||
return gin.CustomRecovery(func(c *gin.Context, recovered any) {
|
||||
fields := []zap.Field{
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("path", c.FullPath()),
|
||||
zap.Any("panic", recovered),
|
||||
}
|
||||
if requestID, ok := requestid.FromGin(c); ok {
|
||||
fields = append(fields, zap.String("request_id", requestID))
|
||||
}
|
||||
fields = append(fields, telemetry.TraceFieldsFromContext(c.Request.Context())...)
|
||||
|
||||
logger.Error("http handler panicked", fields...)
|
||||
httperr.Abort(c, http.StatusInternalServerError, httperr.CodeInternalError, "internal server error")
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user