You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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_token o db::not_found.user y 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.

Powered by TurnKey Linux.