errors

package module
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 24, 2024 License: MIT Imports: 7 Imported by: 4

README

errors GoDoc Report card

An errors package that will help you handle them gracefully. It allows you to add additional data to your errors, to wrap it and you even get a stack trace. Inspired by the github.com/pkg/errors package and Node.js' verror module.

Features

  • Add additional data to error values preventing long and hard to read error messages
  • Wrap existing error values into new ones
  • Stack traces for each error value
  • MultiError, wrap multiple errors values into a single one; great for concurrent workflows that may generate multiple errors
  • Pretty print of the whole error value and support JSON marshalling to ease the serialization (check the "Quick demo" section)

Installation

go get -u github.com/zignd/errors

Documentation

For a better understanding of the features provided by the package check the documentation at: godoc.org/github.com/zignd/errors

Quick demo

There's an example at examples/example1/example1.go that shows how to use the package.

Here's the code for the example:
package main

import (
	"encoding/json"
	"fmt"

	"github.com/zignd/errors"
)

func createTransaction(id string) error {
	bank := "bank_123456"
	if err := updateDatabase(); err != nil {
		return errors.Wrapdf(err, errors.Data{
			"transactionId": id,
			"userId":        "67890",
		}, "failed to complete the transaction on %s", bank)
	}

	return nil
}

func updateDatabase() error {
	if err := createConnection(); err != nil {
		return errors.Wrapd(err, errors.Data{
			"tableName": "transactions",
			"operation": "update",
		}, "failed to update the database")
	}

	return nil
}

func createConnection() error {
	if err := open(); err != nil {
		return errors.Wrapd(err, errors.Data{
			"server":         "db-server-01",
			"timeoutSeconds": 30,
		}, "connection timeout")
	}

	return nil
}

func open() error {
	return errors.Errord(errors.Data{
		"network":  "internal",
		"severity": "high",
	}, "network instability detected")
}

func main() {
	if err := createTransaction("tx_123456"); err != nil {
		b, _ := json.MarshalIndent(err, "", "  ")
		fmt.Println("Error logged as a JSON structure using the json.MarshalIndent:")
		fmt.Printf("%s\n", b)

		b, _ = json.Marshal(err)
		fmt.Println("\nError logged as a JSON structure using the json.Marshal:")
		fmt.Printf("%s\n", b)

		fmt.Println("\nError logged using the s format specifier:")
		fmt.Printf("%s\n", err)

		fmt.Println("\nError logged using the +v format specifier:")
		fmt.Printf("%+v\n", err)
	}
}
Here's the execution of the example:
$ go run examples/example1/example1.go
Error logged as a JSON structure using the json.MarshalIndent:
[
  {
    "data": {
      "transactionId": "tx_123456",
      "userId": "67890"
    },
    "message": "failed to complete the transaction on bank_123456",
    "stack": [
      "main.createTransaction @ /root/hack/errors/examples/example1/example1.go:13",
      "main.main @ /root/hack/errors/examples/example1/example1.go:52",
      "runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194",
      "runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"
    ]
  },
  {
    "data": {
      "operation": "update",
      "tableName": "transactions"
    },
    "message": "failed to update the database",
    "stack": [
      "main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:24",
      "main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12",
      "main.main @ /root/hack/errors/examples/example1/example1.go:52",
      "runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194",
      "runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"
    ]
  },
  {
    "data": {
      "server": "db-server-01",
      "timeoutSeconds": 30
    },
    "message": "connection timeout",
    "stack": [
      "main.createConnection @ /root/hack/errors/examples/example1/example1.go:35",
      "main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23",
      "main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12",
      "main.main @ /root/hack/errors/examples/example1/example1.go:52",
      "runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194",
      "runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"
    ]
  },
  {
    "data": {
      "network": "internal",
      "severity": "high"
    },
    "message": "network instability detected",
    "stack": [
      "main.open @ /root/hack/errors/examples/example1/example1.go:45",
      "main.createConnection @ /root/hack/errors/examples/example1/example1.go:34",
      "main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23",
      "main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12",
      "main.main @ /root/hack/errors/examples/example1/example1.go:52",
      "runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194",
      "runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"
    ]
  }
]

Error logged as a JSON structure using the json.Marshal:
[{"data":{"transactionId":"tx_123456","userId":"67890"},"message":"failed to complete the transaction on bank_123456","stack":["main.createTransaction @ /root/hack/errors/examples/example1/example1.go:13","main.main @ /root/hack/errors/examples/example1/example1.go:52","runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194","runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"]},{"data":{"operation":"update","tableName":"transactions"},"message":"failed to update the database","stack":["main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:24","main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12","main.main @ /root/hack/errors/examples/example1/example1.go:52","runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194","runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"]},{"data":{"server":"db-server-01","timeoutSeconds":30},"message":"connection timeout","stack":["main.createConnection @ /root/hack/errors/examples/example1/example1.go:35","main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23","main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12","main.main @ /root/hack/errors/examples/example1/example1.go:52","runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194","runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"]},{"data":{"network":"internal","severity":"high"},"message":"network instability detected","stack":["main.open @ /root/hack/errors/examples/example1/example1.go:45","main.createConnection @ /root/hack/errors/examples/example1/example1.go:34","main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23","main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12","main.main @ /root/hack/errors/examples/example1/example1.go:52","runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194","runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"]}]

Error logged using the s format specifier:
failed to complete the transaction on bank_123456: failed to update the database: connection timeout: network instability detected

Error logged using the +v format specifier:
message:
        "failed to complete the transaction on bank_123456"
data:
        userId: 67890
        transactionId: tx_123456
stack:
        main.createTransaction @ /root/hack/errors/examples/example1/example1.go:13
        main.main @ /root/hack/errors/examples/example1/example1.go:52
        runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194
        runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651
cause:
        message:
                "failed to update the database"
        data:
                tableName: transactions
                operation: update
        stack:
                main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:24
                main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12
                main.main @ /root/hack/errors/examples/example1/example1.go:52
                runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194
                runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651
        cause:
                message:
                        "connection timeout"
                data:
                        server: db-server-01
                        timeoutSeconds: 30
                stack:
                        main.createConnection @ /root/hack/errors/examples/example1/example1.go:35
                        main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23
                        main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12
                        main.main @ /root/hack/errors/examples/example1/example1.go:52
                        runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194
                        runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651
                cause:
                        message:
                                "network instability detected"
                        data:
                                severity: high
                                network: internal
                        stack:
                                main.open @ /root/hack/errors/examples/example1/example1.go:45
                                main.createConnection @ /root/hack/errors/examples/example1/example1.go:34
                                main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23
                                main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12
                                main.main @ /root/hack/errors/examples/example1/example1.go:52
                                runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194
                                runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AppendMulti

func AppendMulti(multi error, err error) error

AppendMulti appends err to multi.Errors and returns an error if multi is not of the type errors.MultiError.

func As added in v1.0.0

func As(err error, target interface{}) bool

As finds the first error in err's chain that matches target, and if so, sets target to that error value and returns true.

The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.

An error matches target if the error's concrete value is assignable to the value pointed to by target, or if the error has a method As(interface{}) bool such that As(target) returns true. In the latter case, the As method is responsible for setting target.

As will panic if target is not a non-nil pointer to either a type that implements error, or to any interface type. As returns false if err is nil.

func Errord added in v1.0.0

func Errord(data Data, msg string) error

Errord returns an error with additional data and the provided message.

func Errordf added in v1.0.0

func Errordf(data Data, format string, args ...any) error

Errordf returns an error with additional data and the provided format specifier.

func Errorf

func Errorf(format string, args ...any) error

Errorf returns an error with the provided format specifier.

func Is added in v1.0.0

func Is(err, target error) bool

Is reports whether any error in err's chain matches target.

The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.

An error is considered to match a target if it is equal to that target or if it implements a method Is(error) bool such that Is(target) returns true.

func IsErrComposition added in v1.3.0

func IsErrComposition(err error) bool

IsErrComposition returns true if the provided error is a composition of Err or *Err.

func New

func New(msg string) error

New returns an error with the provided message.

func NewMulti

func NewMulti(errs ...error) error

NewMulti returns a new errors.MultiError with the provided errs.

func Unwrap added in v1.0.0

func Unwrap(err error) error

Unwrap returns the result of calling the Unwrap method on err, if err's type contains an Unwrap method returning error. Otherwise, Unwrap returns nil.

func WithCause added in v1.2.0

func WithCause(err error, cause error) error

WithCause adds a cause to the provided error if it is an Err or *Err.

func WithStack added in v1.1.0

func WithStack(err error) error

WithStack adds a stack trace to the provided error if it is an Err or *Err.

func Wrap

func Wrap(err error, msg string) error

Wrap returns an error wrapping err and adding the provided format specifier.

func Wrapd added in v1.0.0

func Wrapd(err error, data Data, msg string) error

Wrapd returns an error wrapping err, adding additional data and the provided message.

func Wrapdf added in v1.0.0

func Wrapdf(err error, data Data, format string, args ...any) error

Wrapdf returns an error wrapping err, adding additional data and the provided format specifier.

func Wrapf

func Wrapf(err error, format string, args ...any) error

Wrapf returns an error wrapping err and adding the provided format specifier.

Types

type Data added in v1.0.0

type Data map[string]any

type Err added in v1.1.0

type Err struct {
	Message string `json:"message"`
	Data    Data   `json:"data,omitempty"`
	Stack   Stack  `json:"stack"`
	Cause   error  `json:"cause,omitempty"`
}

Err is the error struct used internally by the package. This type should only be used for type assertions.

func (Err) Error added in v1.1.0

func (e Err) Error() string

func (Err) Format added in v1.1.0

func (e Err) Format(s fmt.State, verb rune)

Format implements fmt.Formatter. It only accepts the '+v' and 's' formats.

func (*Err) MarshalJSON added in v1.2.1

func (e *Err) MarshalJSON() ([]byte, error)

func (Err) Unwrap added in v1.1.0

func (e Err) Unwrap() error

type MultiError

type MultiError struct {
	Errors []error
}

MultiError is the error struct for multiple errors used internally by the package. This type should be only be used for type assertions.

func (MultiError) Error

func (m MultiError) Error() string

type Stack

type Stack []string

Stack represents a stack trace in the form of a slice of strings.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL