Skip to content

A Go (Golang) package for rich, structured error handling with full stack-trace support, error wrapping, classification, and formatting.

License

Notifications You must be signed in to change notification settings

hueristiq/hq-go-errors

Repository files navigation

hq-go-errors

made with go go report card license maintenance open issues closed issues contribution

hq-go-errors is a Go (Golang) package for rich, structured error handling with full stack-trace support, error wrapping, classification, and formatting.

Resource

Features

  • Full Stack Traces: Capture detailed call stacks at error creation and wrap points, with customizable formatting (e.g., reverse order, separators).
  • Error Chaining: Wrap errors to add context while preserving the original stack trace and error details.
  • Error Classification: Assign ErrorType values to categorize errors for programmatic handling.
  • Structured Fields: Attach arbitrary key-value metadata (e.g., request IDs, parameters) to errors for enhanced debugging.
  • Flexible Formatting: Render errors as human-readable strings or JSON-like maps, with options to include/exclude stack traces, invert chain order, or handle external errors.
  • Standards-Compliant: Implements Go’s standard error, Unwrap, Is, and As interfaces, plus additional helpers like Cause for root cause analysis.

Installation

To install hq-go-errors, run the following command in your Go project:

go get -v -u github.com/hueristiq/hq-go-errors

Make sure your Go environment is set up properly (Go 1.13 or later is recommended).

Usage

Creating Errors

Use hqgoerrors.New to create a root error with a full call stack captured at the point of invocation.

package main

import (
	"fmt"

	hqgoerrors "github.com/hueristiq/hq-go-errors"
)

func main() {
	err := hqgoerrors.New("failed to initialize database")
	if err != nil {
		fmt.Println(err.Error())
	}
}

Wrapping Errors

Use hqgoerrors.Wrap to add context to an existing error, capturing a single stack frame at the wrap point while preserving the original error’s stack trace.

package main

import (
	"fmt"

	hqgoerrors "github.com/hueristiq/hq-go-errors"
)

func loadConfig() error {
	return hqgoerrors.New("cannot read config file")
}

func main() {
	if err := loadConfig(); err != nil {
		err = hqgoerrors.Wrap(err, "failed to load configuration")

		fmt.Println(err.Error())
	}
}

Structured Types & Fields

You can classify errors and attach structured data:

err := hqgoerrors.New("payment declined",
	hqgoerrors.WithType("PaymentError"),
	hqgoerrors.WithField("order_id", 1234),
	hqgoerrors.WithField("amount", 49.95),
)
  • Retrieve type:

     if e, ok := err.(hqgoerrors.Error); ok {
     	fmt.Println("Type:", e.Type())
     	fmt.Println("Fields:", e.Fields())
     }

Unwrapping, Is, As, and Cause

  • Standard Unwrap:

     next := hqgoerrors.Unwrap(err)
  • Deep equality:

     if hqgoerrors.Is(err, targetErr) { … }
  • Type assertion:

     var myErr *hqgoerrors.Error
    
     if hqgoerrors.As(err, &myErr) {
     	fmt.Println("Got:", myErr.Msg)
     }
  • Root cause:

     cause := hqgoerrors.Cause(err)

Formatting Errors

... to String

package main

import (
	"fmt"

	hqgoerrors "github.com/hueristiq/hq-go-errors"
)

func main() {
	err := hqgoerrors.New("root error example!", hqgoerrors.WithType("ERROR_TYPE"), hqgoerrors.WithField("FIELD_KEY_1", "FIELD_VALUE_1"), hqgoerrors.WithField("FIELD_KEY_2", "FIELD_VALUE_2"))

	err = hqgoerrors.Wrap(err, "wrap error example 1!")
	err = hqgoerrors.Wrap(err, "wrap error example 2!", hqgoerrors.WithType("ERROR_TYPE_2"), hqgoerrors.WithField("FIELD_KEY_1", "FIELD_VALUE_1"), hqgoerrors.WithField("FIELD_KEY_2", "FIELD_VALUE_2"))

	formattedStr := hqgoerrors.ToString(err, true)

	fmt.Println(formattedStr)
}

output:

[ERROR_TYPE_2] wrap error example 2!

Fields:
  FIELD_KEY_1=FIELD_VALUE_1,  FIELD_KEY_2=FIELD_VALUE_2

Stack:
  main.main:/home/.../hq-go-errors/examples/string_format/main.go:13

wrap error example 1!

Stack:
  main.main:/home/.../hq-go-errors/examples/string_format/main.go:12

[ERROR_TYPE] root error example!

Fields:
  FIELD_KEY_1=FIELD_VALUE_1,  FIELD_KEY_2=FIELD_VALUE_2

Stack:
  main.main:/home/.../hq-go-errors/examples/string_format/main.go:13
  main.main:/home/.../hq-go-errors/examples/string_format/main.go:12
  main.main:/home/.../hq-go-errors/examples/string_format/main.go:10

... to JSON

package main

import (
	"encoding/json"
	"fmt"

	hqgoerrors "github.com/hueristiq/hq-go-errors"
)

func main() {
	err := hqgoerrors.New("root error example!", hqgoerrors.WithType("ERROR_TYPE"), hqgoerrors.WithField("FIELD_KEY_1", "FIELD_VALUE_1"), hqgoerrors.WithField("FIELD_KEY_2", "FIELD_VALUE_2"))

	err = hqgoerrors.Wrap(err, "wrap error example 1!")
	err = hqgoerrors.Wrap(err, "wrap error example 2!", hqgoerrors.WithType("ERROR_TYPE_2"), hqgoerrors.WithField("FIELD_KEY_1", "FIELD_VALUE_1"), hqgoerrors.WithField("FIELD_KEY_2", "FIELD_VALUE_2"))

	formattedJSON := hqgoerrors.ToJSON(err, true)

	bytes, _ := json.Marshal(formattedJSON)

	fmt.Println(string(bytes))
}

output:

{
  "root": {
    "fields": {
      "FIELD_KEY_1": "FIELD_VALUE_1",
      "FIELD_KEY_2": "FIELD_VALUE_2"
    },
    "message": "root error example!",
    "stack": [
      "main.main:/home/.../hq-go-errors/examples/JSON_format/main.go:14",
      "main.main:/home/.../hq-go-errors/examples/JSON_format/main.go:13",
      "main.main:/home/.../hq-go-errors/examples/JSON_format/main.go:11"
    ],
    "type": "ERROR_TYPE"
  },
  "wrap": [
    {
      "fields": {
        "FIELD_KEY_1": "FIELD_VALUE_1",
        "FIELD_KEY_2": "FIELD_VALUE_2"
      },
      "message": "wrap error example 2!",
      "stack": "main.main:/home/.../hq-go-errors/examples/JSON_format/main.go:14",
      "type": "ERROR_TYPE_2"
    },
    {
      "message": "wrap error example 1!",
      "stack": "main.main:/home/.../hq-go-errors/examples/JSON_format/main.go:13"
    }
  ]
}

Contributing

Contributions are welcome and encouraged! Feel free to submit Pull Requests or report Issues. For more details, check out the contribution guidelines.

A big thank you to all the contributors for your ongoing support!

contributors

Licensing

This package is licensed under the MIT license. You are free to use, modify, and distribute it, as long as you follow the terms of the license. You can find the full license text in the repository - Full MIT license text.

About

A Go (Golang) package for rich, structured error handling with full stack-trace support, error wrapping, classification, and formatting.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •