stackerr

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Feb 24, 2020 License: MIT Imports: 7 Imported by: 6

README

Go Report Card

stackerr

A simple Go error library that provides stack traces.

Motivation

One of the biggest differences between errors in Go and exceptions in other languages is that you don't get a stack trace with a Go error. The stackerr package fixes this limitation. The stackerr package supports the error improvements in Go 1.13, with custom Is and Unwrap methods.

Creating an error with a stack trace

There are three different functions in the stackerr package for creating a stack trace:

Wrap

Use the stackerr.Wrap function to wrap errors returned by third-party libraries. It takes an existing error and wraps it in an error that contains a stack trace. In order to simplify your error handling code, Wrap has two special cases:

  • If a nil error is passed to stackerr.Wrap, nil is returned.
  • If an error with a stack trace error somewhere in its unwrap chain is passed to stackerr.Wrap, it returns the passed-in error.

These two rules make it possible to write the following code and not worry if there's already a stack trace (or no error) stored in err:

func DoSomething(input string) (string, error) {
    result, err := ThingToCall(input)
    return result, stackerr.Wrap(err)
}
Errorf

If you want to wrap an existing error with your own contextual information, use stackerr.Errorf. This works exactly like fmt.Errorf:

func DoSomething(input string) (string, error) {
    result, err := ThingToCall(input)
    if err != nil {
        err = stackerr.Errorf("DoSomething failed on call to ThingToCall: %w", err)
    }
    return result, err
}

If there's an error in the unwrap chain that provides a stack trace, stackerr.Errorf preserves the existing trace information.

New

If you are creating a new error that's only a string, use stackerr.New. Just as stackerr.Errorf is a replacement for fmt.Errorf, this function is a replacement for errors.New:

func DoSomething(input string) (string, error) {
    if input == "" {
        return "", stackerr.New("cannot supply an empty string to DoSomething")
    }
    result, err := ThingToCall(input)
    return result, stackerr.Wrap(err)
}

Retrieving the stack trace

Once you have an error in your unwrap chain with a stack trace, there are two ways to get the trace back.

Trace

Use the stackerr.Trace function to get a []string that contains each line of the stack trace:

s := stackerr.New("This is a stack trace error")
callStack, err := stackerr.Trace(s, stackerr.StandardFormat)
fmt.Println(callStack)

stackerr.Trace takes two parameters. The first is an error and the second is a text.Template. There's a default template defined, stackerr.StandardFormat. For each line, it produces output that looks like:

FUNCTION_NAME (FILE_PATH_AND_NAME:LINE_NUMBER)

If you want to write your own template, there are three valid variables:

  • .Function (for the function name),
  • .File (for the file path and name)
  • .Line (for the line number).

There are three possible outputs from stackerr.Trace:

  • If you supply an error that doesn't have stack trace in its unwrap chain, nil is returned for both the slice of strings and the error.
  • If an invalid template is supplied, nil is returned for the slice and the error is returned. (with a stack trace!)
  • Otherwise, the stack trace is returned as a slice of strings along with a nil error.

Note that by default, the File path will include the absolute path to the file on the machine that built the code. If you want to hide this path, build using the -trimpath flag.

fmt Formatting and %+v

Use the %+v formatting directive with fmt.Printf and variants to get the stack trace as a string.

s := stackerr.New("This is a stack trace error")
fmt.Printf("%+v\n",s)

This prints the stack trace using the stackerr.StandardFormat, with each level of the call stack separated by newlines (\n).

Note that this will not print out the stack trace if there is a fmt.Errorf wrapping the error with a stack trace. In those situations, you need to use stackerr.Trace.

HasStack

Use stackerr.HasStack to determine if there is a stack trace in the unwrap chain for an error.

Testing

The tests for stackerr require you to run go test with the -trimpath flag:

go test -trimpath ./...

Documentation

Index

Constants

This section is empty.

Variables

View Source
var StandardFormat = template.Must(template.New("standardFormat").Parse("{{.Function}} ({{.File}}:{{.Line}})"))

StandardFormat is the default template used to convert a *runtime.Frame to a string. Each entry is formatted as "FUNCTION_NAME (FILE_NAME:LINE_NUMBER)"

Functions

func Errorf

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

Errorf wraps the error returned by fmt.Errorf in an errorStack. If there is an existing errorStack in the unwrap chain, its stack trace is used.

func HasStack

func HasStack(e error) bool

HasStack returns true if there is a stack trace in the unwrap chain for the error.

func New

func New(msg string) error

New builds a errorStack out of a string

func Trace

func Trace(e error, t *template.Template) ([]string, error)

Trace returns the stack trace information as a slice of strings formatted using the provided Go template. The valid fields in the template are Function, File, and Line. See StandardFormat for an example.

func Wrap

func Wrap(err error) error

Wrap takes in an error and returns an error wrapped in a errorStack with the location where the error was first created or returned from third-party code. If there is already an errorStack in the error chain, Wrap returns the passed-in error. Wrap returns nil when a nil error is passed in.

Types

This section is empty.

Jump to

Keyboard shortcuts

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