2025-05-17 11:36:26 -04:00

128 lines
2.7 KiB
Go

package errors
import (
"fmt"
"runtime"
"strings"
)
// Error es una interfaz extendida para errores
type Error interface {
error
Code() string
Unwrap() error
}
// CustomError implementa la interfaz Error
type CustomError struct {
code string
message string
cause error
stack []uintptr
}
// New crea un nuevo error personalizado
func New(code, message string) Error {
return &CustomError{
code: code,
message: message,
stack: callers(),
}
}
// Wrap envuelve un error con información adicional
func Wrap(err error, message string) Error {
if err == nil {
return nil
}
return &CustomError{
code: extractCode(err),
message: message,
cause: err,
stack: callers(),
}
}
// Wrapf envuelve un error con un mensaje formateado
func Wrapf(err error, format string, args ...interface{}) Error {
if err == nil {
return nil
}
return &CustomError{
code: extractCode(err),
message: fmt.Sprintf(format, args...),
cause: err,
stack: callers(),
}
}
// NewWithCode crea un nuevo error con un código específico
func NewWithCode(code, message string) Error {
return &CustomError{
code: code,
message: message,
stack: callers(),
}
}
// Error implementa la interfaz error
func (e *CustomError) Error() string {
if e.cause != nil {
return fmt.Sprintf("%s: %v", e.message, e.cause)
}
return e.message
}
// Code retorna el código de error
func (e *CustomError) Code() string {
return e.code
}
// Unwrap implementa la interfaz de unwrapping
func (e *CustomError) Unwrap() error {
return e.cause
}
// Stack retorna la pila de llamadas
func (e *CustomError) Stack() string {
var sb strings.Builder
frames := runtime.CallersFrames(e.stack)
for {
frame, more := frames.Next()
sb.WriteString(fmt.Sprintf("%s:%d %s\n", frame.File, frame.Line, frame.Function))
if !more {
break
}
}
return sb.String()
}
// extractCode extrae el código de un error
func extractCode(err error) string {
if customErr, ok := err.(Error); ok {
return customErr.Code()
}
return "UNKNOWN"
}
// callers obtiene la pila de llamadas
func callers() []uintptr {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
return pcs[0:n]
}
// Errores comunes
var (
ErrNotFound = NewWithCode("NOT_FOUND", "recurso no encontrado")
ErrUnauthorized = NewWithCode("UNAUTHORIZED", "no autorizado")
ErrForbidden = NewWithCode("FORBIDDEN", "acceso prohibido")
ErrBadRequest = NewWithCode("BAD_REQUEST", "solicitud incorrecta")
ErrInternal = NewWithCode("INTERNAL", "error interno del servidor")
ErrTimeout = NewWithCode("TIMEOUT", "tiempo de espera agotado")
ErrNotImplemented = NewWithCode("NOT_IMPLEMENTED", "no implementado")
)