package middleware import ( "fmt" "io" "log/slog" "runtime/debug" "github.com/gin-gonic/gin" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" "switchbot-api/internal/transport/http/contextkeys" "switchbot-api/internal/transport/http/response" ) func Recovery(logger *slog.Logger) gin.HandlerFunc { return gin.CustomRecoveryWithWriter(io.Discard, func(c *gin.Context, recovered any) { ctx := c.Request.Context() span := trace.SpanFromContext(ctx) span.RecordError(fmt.Errorf("panic: %v", recovered)) span.SetStatus(codes.Error, "panic recovered") spanCtx := trace.SpanContextFromContext(ctx) traceID := "" spanID := "" if spanCtx.IsValid() { traceID = spanCtx.TraceID().String() spanID = spanCtx.SpanID().String() } logger.Error( "panic recovered", slog.Any("panic", recovered), slog.String("request_id", contextkeys.RequestIDFromContext(ctx)), slog.String("trace_id", traceID), slog.String("span_id", spanID), slog.String("stack", string(debug.Stack())), ) response.WriteInternalError(c) c.Abort() }) }