5.1 KiB
🧠 errs: Gestión de Errores Estructurada para Go
Parte del núcleo de Active-Go Core
errs es un módulo esencial de la librería core de Active-Go, diseñado para modernizar y enriquecer el manejo de errores en Go, especialmente en sistemas distribuidos y arquitecturas de microservicios. Proporciona una estructura robusta que permite clasificar, componer y contextualizar los errores de forma precisa y eficaz.
🚀 Filosofía
La motivación detrás de errs surge de nuestra experiencia en ActiveThing.com enfrentando la complejidad de sistemas reales. Go proporciona un tipo error simple, pero limitado. errs expande este modelo con:
✅ Clasificación Estructurada
- Define jerarquías de errores (
modulo::clase.subclase) para evitar comparaciones de strings frágiles. - Permite identificar errores como
auth::invalid_tokenodb::not_found.usery aplicar lógicas según su clase o módulo.
🧩 Composición y Contexto
- Usa el patrón de composición para añadir metadatos sin alterar la clase del error.
- Agrega mensajes, códigos, causas, stack traces, fechas, trazabilidad, etc.
🌐 Trazabilidad en Microservicios
- Unifica el lenguaje de errores entre servicios.
- Los errores conservan su contexto a lo largo de la cadena (auth → pedidos → API Gateway).
🔍 Visibilidad para Operaciones
- Logs ricos con jerarquías, metadatos y stack traces.
- Salida formateada para mejorar la observabilidad.
🧱 Inmutabilidad y Predictibilidad
- Los errores compuestos son inmutables.
- Facilita debugging seguro y reduce efectos colaterales.
📊 Errores como Datos
- Los errores transportan información tipificada útil para monitoreo y lógica programática.
🛠️ Uso Básico
📌 Crear Errores
var (
ErrNotFound = errs.CreateErr("app::not_found")
ErrInvalidInput = errs.CreateErr("app::invalid_input")
)
🧬 Subclases
var (
ErrUserNotFound = errs.CreateSubclassOf(ErrNotFound, "user")
ErrProductNotFound = errs.CreateSubclassOf(ErrNotFound, "product")
)
if errs.IsSubclassOf(err, ErrNotFound) {
// Es una variante de "no encontrado"
}
🧠 Composición con Contexto
err := errs.ComposeWithMessage(ErrInvalidInput, "Campo 'nombre_usuario' es obligatorio")
original := errors.New("DB desconectada")
errWithCause := errs.ComposeWithCause(errs.CreateErr("db::internal_error"), original)
complexErr := errs.Compose(
ErrUserNotFound,
errs.WithMessage("ID %d no encontrado", 12345),
errs.WithCode(404),
errs.WithDate(),
errs.WithStack(),
errs.WithRetryable(errs.RetryableCanRetry|errs.RetryableIsTemporary, 5*time.Second),
errs.WithInfo("El usuario no existe", "Verifique el ID", "https://docs/errors/user-404"),
errs.WithOrigin("user_service", "alpha"),
errs.WithObservedBy("api_gateway"),
errs.WithMeta("trace_id", "abc123xyz"),
errs.WithMetas(
errs.CreateMeta("http_status", 500, errs.MetaTypeInt),
errs.CreateMeta("is_critical", true, errs.MetaTypeBool),
),
)
🔍 Acceso a Metadatos
if ewc, ok := complexErr.(errs.ErrorWithCode); ok {
fmt.Println("Código:", ewc.Code())
}
if ewc, ok := complexErr.(errs.ErrorWithCause); ok {
fmt.Println("Causa:", ewc.Cause())
}
if ewst, ok := complexErr.(errs.ErrorWithStack); ok {
fmt.Println("Stack:", ewst.Stack())
}
if ewms, ok := complexErr.(errs.ErrorWithMetas); ok {
for _, meta := range ewms.Metas() {
fmt.Printf("%s = %v (%s)\n", meta.Name(), meta.Value(), meta.Type())
}
}
🧾 Formato Avanzado para Logs
fmt.Printf("Error básico: %v\n", complexErr)
fmt.Printf("Solo clase: %s\n", complexErr)
fmt.Printf("Detallado: %+v\n", complexErr)
fmt.Printf("Debug: %#v\n", complexErr)
Soporte para salida con color en terminales compatibles para mayor claridad.
📚 Manejo de Listas de Errores
var errsList errs.ErrorList
errsList = errsList.Append(err1)
errsList = errsList.AppendNotNil(err2)
if errsList.Any() {
fmt.Printf("%d errores encontrados: %v\n", errsList.Count(), errsList.Clean())
first := errsList.First()
last := errsList.Last()
}
🧩 Funcionalidades Clave
-
✅ Interfaces de Go:
error,fmt.Formatter,errors.Is,errors.Unwrap -
📐
Err: tipo base con jerarquía (modulo::clase.subclase) -
🔗 Jerarquía de errores:
CreateErr(string)CreateSubclassOf(parent, name)IsSubclassOf(err, parent)- Métodos:
Parent(),Class(),Module()
-
🏷️ Metadatos tipados:
int,bool,string, etc. -
🧠 Composición segura y declarativa
-
🔁 Soporte para errores reintentables
-
📊 Visualización enriquecida para monitoreo
🧪 Recomendado para:
- Sistemas distribuidos con múltiples servicios
- Aplicaciones con alto requerimiento de trazabilidad
- Equipos que priorizan depuración clara y mantenibilidad
Repositorio oficial: Active-Go Core Documentación: https://docs.active-go.com/errors
Diseñado con propósito. Inspirado por la complejidad. Refinado en producción.