xerrs

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2020 License: MIT Imports: 4 Imported by: 5

README

xerrs Build Status

Extended Errors for Go

What? Why?

It is extremely important to be able to effectively debug problems in production. However, depending on the simplicty of your language's error handling, managing errors and debugging can become tedious and difficult. For instance, GoLang provides a basic error which contains a simple value - but it lacks verbose information about the cause of the error or the state of the stack at error-time.

xerrs uses original GoLang built-in error types but stores extra data.

These are the extra extended features which could be useful for debugging a big project:

  1. Cause - the original error which happened in the system. This is the original error which you want to preserve
  2. Mask - a mask error. It might be used whenever you want to mask some errors happening on production with a more generic error. Mask is very useful if you want to prevent original error return back to the client. Calling Error() will always return Mask if set.
  3. Stack - a detailed snapshot of the execution stack at error-time. Helpful for debugging.
  4. Data - a map which could be used to store custom data associated with an error.
  5. Wrap and Wrapf can be used to create an annotated error chain, but take a lower precedence than Mask.

Quick Usage

Basics
import "github.com/roserocket/xerrs"

//....

if data, err := MyFunc(); err != nil {
    err := xerrs.Extend(err) // extend error

    //....

    // Details returns cause error, mask if specified, and the stack (accepting the maximum stack height as parameter)
    // In this example only 5 last stack function calls will be printed out
    fmt.Println(xerrs.Details(err, 5))

    //....
}
Deferred logging + masking example
func DoSomething(w http.ResponseWriter, r *http.Request) {
    var err error

    const maxCallstack = 5 // only 5 last stack function calls will be printed out

    defer func() {
        // Details returns cause error, mask if specified, and the stack (accepting the maximum stack height as parameter)
        // In this example only 5 calls in the stack will be printed out
        fmt.Println(xerrs.Details(err, maxCallstack))
    }()

    var someModel Model
    if err = ReadJSONFromReader(r, &someModel); err != nil {
        err = xerrs.Extend(err)
        DoSomethingWithError(w, err.Error()) // Calling Error() without setting a mask will return the original error.
        return
    }

    if _, err = DBCreateMyModel(&someModel); err != nil {
        err = xerrs.Mask(err, errors.New("We are experiencing technical difficulties"))
        DoSomethingWithError(w, err.Error()) // Error() will return the masked error in this case.
        return
    }

    OutputDataToClient(w, &someModel)
}
Custom data in error
func DoSomething(w http.ResponseWriter, r *http.Request) {
    var err error

    //......

    if err = ReadJSONFromReader(r, someModel); err != nil {
        err = xerrs.Extend(err)

        xerrs.SetData(err, "some_key", "VALUE") // set custom error value
    }

    //......

    fmt.Println(xerrs.Details(err))
    fmt.Println(xerrs.GetData(err, "some_key")) // print custom error value

    //......
}
Compare errors
func VeryComplexLongFunction(arg1, arg2) error {
    var err error
    badErr := errors.New("EPIC FAIL")

    //......

    // convert error to an extended one and use it to for debugging purposes
    err = xerrs.Extend(err)

    //......

    if xerrs.IsEqual(err, badErr) {
        // errors are equal. We need to do something here
    }

    //......
}
Wrapped errors
Basic wrapping
func main() {
	if err := a(); err != nil {
		log.Fatalln(err)
	}
}

func a() error {
	return xerrs.Wrap(b(), "called b")
}

func b() error {
	return xerrs.New("uh oh, something bad happened")
}
Formatted wrapping
func main() {
	numbers := []int{1, 2, 3}
	if err := a(numbers...); err != nil {
		log.Fatalln(err)
	}
}

func a(n ...int) error {
	for i, v := range n {
		if err := b(v); err != nil {
			return xerrs.Wrapf(err, "called b(%d)", v)
		}
	}

	return nil
}

func b(n int) error {
	if n % 2 != 0 {
		return xerrs.New("number is odd")
	}
	return nil
}

Docs

func New
func New(string) error

New creates a new xerr with a supplied message

Note it will also set the stack

func Errorf
func Errorf(string, ...interface{}) error

Errorf creates a new xerr based on a formatted message

Note it will also set the stack

func Extend
func Extend(error) error

Extend creates a new xerr based on a supplied error

Note if error is nil then nil is returned

Note it will also set the stack

func Mask
func Mask(error, error) error

Mask creates a new xerr based on a supplied error but also sets the mask error as well. Only mask error value is returned back when Error() is called

Note if error is nil then nil is returned

Note if error is xerr then its mask value is updated

Note it will also set the stack

func IsEqual
func IsEqual(error, error) bool

IsEqual is a helper function to compare if two errors are equal

Note if one of those errors is xerr then it's Cause is used for comparison

func Cause
func Cause(error) error

Cause returns xerr's cause error

Note if error is not xerr then argument error is returned back

func SetData
func SetData(error, string, interface{})

SetData sets custom data stored in xerr

Note if error is not xerr then function does not do anything

func GetData
func GetData(error, string) (interface{}, bool)

GetData returns custom data stored in xerr

Note if error is not xerr then (nil, false) is returned

func Stack
func Stack(error) []StackLocation

Stack returns stack location array

Note if error is not xerr then nil is returned

func Details
func Details(error, int) string

Details returns a printable string which contains error, mask and stack

Note maxStack can be supplied to change number of printer stack rows

Note if error is not xerr then Error() is returned

What are the alternatives?

xerrs library was partially inspired by juju/errors

pkg/errors

Also there are new ideas and drafts for Go error handling which might change the way error is being handled in the future.

LICENSE

see LICENSE

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Cause

func Cause(err error) error

Cause - returns xerr's cause error If err is not xerr then err is returned

func Details

func Details(err error, maxStack int) string

Details - returns a printable string which contains error, mask and stack maxStack can be supplied to change number of printer stack rows If err is not xerr then err.Error() is returned

func Errorf

func Errorf(format string, args ...interface{}) error

Errorf - creates a new xerr based on a formatted message. It will also set the stack.

func Extend

func Extend(err error) error

Extend - creates a new xerr based on a supplied error. If err is nil then nil is returned It will also set the stack.

func GetData

func GetData(err error, name string) (value interface{}, ok bool)

GetData returns custom data value, stored at name. If err is not an *xerr then (nil, false) is returned. If err is an *xerr, but its data map is empty, or does not contain the key name, GetData will attempt to recurse through the error's causes, but will stop at the first non-*xerr error.

func IsEqual

func IsEqual(err1, err2 error) bool

IsEqual - helper function to compare if two erros are equal If one of those errors are xerr then its Cause is used for comparison

func Mask

func Mask(err, mask error) error

Mask - creates a new xerr based on a supplied error but also sets the mask error as well When Error() is called on the error only mask error value is returned back If err is nil then nil is returned If err is xerr then its mask value is updated It will also set the stack.

func New

func New(message string) error

New - creates a new xerr with a supplied message. It will also set the stack.

func SetData

func SetData(err error, name string, value interface{})

SetData - sets custom data stored in xerr If err is not xerr then nothing happens

func Wrap added in v1.2.0

func Wrap(err error, message string) error

Wrap returns an error annotated with a stack trace, and is prefixed with the given message. If err is nil, Wrap will return nil.

func Wrapf added in v1.2.0

func Wrapf(err error, format string, args ...interface{}) error

Wrapf returns an error annotated with a stack trace, and the given, formatted message. If err is nil, Wrapf will return nil.

Types

type StackLocation

type StackLocation struct {
	Function string `json:"function"`
	File     string `json:"file"`
	Line     int    `json:"line"`
}

StackLocation - A helper struct function which represents one step in the execution stack

func Stack

func Stack(err error) []StackLocation

Stack - returns stack location array If err is not xerr then nil is returned

func (StackLocation) String

func (location StackLocation) String() string

Returns a string which represents StackLocation. Used for logging.

Jump to

Keyboard shortcuts

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