128 lines
2.7 KiB
Go
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")
|
|
)
|