errstack

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2019 License: MIT Imports: 7 Imported by: 4

README

errstack

A Go library to attach call stack frames to errors.

Warning

  • This project is open source, but closed development, no support, no pull request welcome. If you are unsatisfied, feel free to fork it, pick another library, or roll your own.
  • I understand this may be a "Don't do that" style in the Go error handling best practices.
  • I don't promise the future compatibility. Also this library may not work in the future versions of Go, and a migration path may not be provided, leading to the dead end, users of this library will have to rewrite all of your code. You are on your own with no help.

How to install

go get -u github.com/hnakamur/errstack

Usage

func ExampleStack() {
	level1 := func() error { return os.ErrNotExist }
	level2 := func() error {
		// NOTE: You can use "%s" here just to get call stack frames.
		// However you cannot use errors.Is() or errors.As().
		return errstack.Errorf("level2: %s", level1())
	}
	level3 := func() error { return fmt.Errorf("level3: %w", level2()) }
	err := level3()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		fmt.Printf("is NotExist: %v\n", errors.Is(err, os.ErrNotExist))
		fmt.Printf("stack: %v\n", errstack.Stack(err))
	}
}

func Example_as() {
	level1 := func() error {
		return &os.PathError{Op: "create", Path: "/tmp/foo", Err: os.ErrExist}
	}
	level2 := func() error { return errstack.Errorf("level2: %w", level1()) }
	level3 := func() error { return fmt.Errorf("level3: %w", level2()) }
	err := level3()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		var e2 *os.PathError
		if errors.As(err, &e2) {
			fmt.Printf("pathError: %v\n", e2)
		}
		fmt.Printf("stack: %v\n", errstack.Stack(err))
	}
}

func Example_is() {
	level1 := func() error { return os.ErrNotExist }
	level2 := func() error { return errstack.Errorf("level2: %w", level1()) }
	level3 := func() error { return fmt.Errorf("level3: %w", level2()) }
	err := level3()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		fmt.Printf("is NotExist: %v\n", errors.Is(err, os.ErrNotExist))
		fmt.Printf("stack: %v\n", errstack.Stack(err))
	}
}

License

MIT License

Documentation

Overview

Package errstack provides functions which creates or wraps an error from which you can get call stack frames later at an upper call frame. Functions New and Errorf are a drop-in replacement of errors.New and fmt.Errorf.

Example (As)
package main

import (
	"errors"
	"fmt"
	"os"

	"github.com/hnakamur/errstack"
)

func main() {
	level1 := func() error {
		return &os.PathError{Op: "create", Path: "/tmp/foo", Err: os.ErrExist}
	}
	level2 := func() error { return errstack.Errorf("level2: %w", level1()) }
	level3 := func() error { return fmt.Errorf("level3: %w", level2()) }
	err := level3()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		var e2 *os.PathError
		if errors.As(err, &e2) {
			fmt.Printf("pathError: %v\n", e2)
		}
		fmt.Printf("stack: %v\n", errstack.Stack(err))
	}
}
Example (Is)
package main

import (
	"errors"
	"fmt"
	"os"

	"github.com/hnakamur/errstack"
)

func main() {
	level1 := func() error { return os.ErrNotExist }
	level2 := func() error { return errstack.Errorf("level2: %w", level1()) }
	level3 := func() error { return fmt.Errorf("level3: %w", level2()) }
	err := level3()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		fmt.Printf("is NotExist: %v\n", errors.Is(err, os.ErrNotExist))
		fmt.Printf("stack: %v\n", errstack.Stack(err))
	}
}

Index

Examples

Constants

This section is empty.

Variables

View Source
var MaxFrames = uint32(128)

MaxFrames is the maximum stack frame count used in New and Errorf. Use functions in the sync/atomic package to modify this value.

Functions

func Errorf

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

Errorf creates an error with fmt.Errorf and returns a wrapped error.

If any of arguments has LV() []string method, then the error is wrapped with the result from the last argument which has LV() []string method. That result can be obtained later with the LV function.

If any of arguments has the Stack() []Frame method, then stack call frames are taken from the last argument of those having stack call frames and set to the wrapped error.

If none of arguments has the Stack() []Frame method, then stack call frames are generated and set to the wrapped error.

The original error returned by fmt.Errorf can be obtained by calling Unwrap method of the wrapped error.

Call stack frames can be obtained by calling the Stack function later at the upper call frame.

func LV added in v0.1.2

func LV(err error) []string

LV get the pairs of labels and values of the first error which has LV() []string method in the err's chain.

func New

func New(text string) error

New creates an error with errors.New and returns a wrapped error.

Call stack frames are generated and set to the wrapped error.

The original error returned by errors.New can be obtained by calling Unwrap method of the wrapped error.

Call stack frames can be obtained by calling the Stack function later at the upper call frame.

Types

type ErrorWithLV added in v0.2.0

type ErrorWithLV interface {
	error

	String(label, value string) ErrorWithLV
	Stringer(label string, value fmt.Stringer) ErrorWithLV
	HexByte(label string, value byte) ErrorWithLV
	HexBytes(label string, value []byte) ErrorWithLV
	Fmt(label string, format string, a ...interface{}) ErrorWithLV
	Bool(label string, value bool) ErrorWithLV
	Int(label string, value int) ErrorWithLV
	Int8(label string, value int8) ErrorWithLV
	Int16(label string, value int16) ErrorWithLV
	Int32(label string, value int32) ErrorWithLV
	Int64(label string, value int64) ErrorWithLV
	Uint(label string, value uint) ErrorWithLV
	Uint8(label string, value uint8) ErrorWithLV
	Uint16(label string, value uint16) ErrorWithLV
	Uint32(label string, value uint32) ErrorWithLV
	Uint64(label string, value uint64) ErrorWithLV
	Float32(label string, value float32) ErrorWithLV
	Float64(label string, value float64) ErrorWithLV
	Time(label string, value time.Time, format string) ErrorWithLV
	UTCTime(label string, value time.Time) ErrorWithLV
}

ErrorWithLV is an error with methods for adding a pair of label and value.

func WithLV added in v0.1.2

func WithLV(err error, lv ...string) ErrorWithLV

WithLV wraps the error and attach pairs of labels and values to the wrapped error.

If any of the err's chain has the LV() []string method, the pairs of labeld and values of the wrapped error will be the concatination of the pairs of labels and values of the first error which has LV() []string method and the lv argument.

The pairs of labels and values can be get calling the LV function to the wrapped error.

type Frame

type Frame struct {
	Name string
	Line int
	Path string
}

Frame is a call stack frame.

func Stack

func Stack(err error) []Frame

Stack finds the first error in err's chain that has stack call frames, and returns those if found.

Note you need to build an error chain only with fmt.Errorf with "%w", errstack.Errorf, and errstack.New in order to get stack frames. Otherwise Stack returns nil.

Example
package main

import (
	"errors"
	"fmt"
	"os"

	"github.com/hnakamur/errstack"
)

func main() {
	level1 := func() error { return os.ErrNotExist }
	level2 := func() error {
		// NOTE: You can use "%s" here just to get call stack frames.
		// However you cannot use errors.Is() or errors.As().
		return errstack.Errorf("level2: %s", level1())
	}
	level3 := func() error { return fmt.Errorf("level3: %w", level2()) }
	err := level3()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		fmt.Printf("is NotExist: %v\n", errors.Is(err, os.ErrNotExist))
		fmt.Printf("stack: %v\n", errstack.Stack(err))
	}
}

func (*Frame) String added in v0.1.1

func (f *Frame) String() string

String retruns a string representation for the stack.

Jump to

Keyboard shortcuts

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