errs

package module
v2.0.5 Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2023 License: MIT Imports: 6 Imported by: 48

README

errs/v2

go.dev Go Report Card SourceGraph

errs is a package for making errors friendly and easy.

Creating Errors

The easiest way to use it, is to use the package level Errorf function. It's much like fmt.Errorf, but better. For example:

func checkThing() error {
	return errs.Errorf("what's up with %q?", "zeebo")
}

Why is it better? Errors come with a stack trace that is only printed when a "+" character is used in the format string. This should retain the benefits of being able to diagnose where and why errors happen, without all of the noise of printing a stack trace in every situation. For example:

func doSomeRealWork() {
	err := checkThing()
	if err != nil {
		fmt.Printf("%+v\n", err) // contains stack trace if it's a errs error.
		fmt.Printf("%v\n", err)  // does not contain a stack trace
		return
	}
}
Error Tags

You can create a Tag for errors and check if any error has been associated with that tag. The tag is prefixed to all of the error strings it creates, and tags are just strings: two tags with the same contents are the same tag. For example:

const Unauthorized = errs.Tag("unauthorized")

func checkUser(username, password string) error {
	if username != "zeebo" {
		return Unauthorized.Errorf("who is %q?", username)
	}
	if password != "hunter2" {
		return Unauthorized.Errorf("that's not a good password, jerkmo!")
	}
	return nil
}

func handleRequest() {
	if err := checkUser("zeebo", "hunter3"); errors.Is(err, Unauthorized) {
		fmt.Println(err)
		fmt.Println(errors.Is(err, Tag("unauthorized"))))
	}

	// output:
	// unauthorized: that's not a good password, jerkmo!
	// true
}

Tags can also Wrap other errors, and errors may be wrapped multiple times. For example:

const (
	Package      = errs.Tag("mypackage")
	Unauthorized = errs.Tag("unauthorized")
)

func deep3() error {
	return fmt.Errorf("ouch")
}

func deep2() error {
	return Unauthorized.Wrap(deep3())
}

func deep1() error {
	return Package.Wrap(deep2())
}

func deep() {
	fmt.Println(deep1())

	// output:
	// mypackage: unauthorized: ouch
}

In the above example, both errors.Is(deep1(), Package) and errors.Is(deep1()), Unauthorized) would return true, and the stack trace would only be recorded once at the deep2 call.

In addition, when an error has been wrapped, wrapping it again with the same tag will not do anything. For example:

func doubleWrap() {
	fmt.Println(Package.Wrap(Package.Errorf("foo")))

	// output:
	// mypackage: foo
}

This is to make it an easier decision if you should wrap or not (you should).

Tags will also be "hoisted" when they match an incoming error being wrapped with the "%w" format verb. For example:

func hoistWrap() {
	err1 := Package.Errorf("foo")
	err2 := Package.Errorf("blah: %w", err)
	fmt.Println(err1)
	fmt.Println(err2)

	// output:
	// mypackage: foo
	// mypackage: blah: foo
}

This only works if the format string ends with "%w" and an error is the last argument.

Utilities

Tags is a helper function to get a slice of tags that an error has. The latest wrap is first in the slice. For example:

func getTags() {
	tags := errs.Tags(deep1())
	fmt.Println(tags[0] == Package)
	fmt.Println(tags[1] == Unauthorized)

	// output:
	// true
	// true
}

If you don't have a tag available but don't really want to make an exported one but do want to have the error tagged for monitoring purposes, you can create a one of tag with the Tagged helper:

func oneOff() error {
	fh, err := fh.Open("somewhere")
	if err != nil {
		return errs.Tagged("open", err)
	}
	return errs.Tagged("close", fh.Close())
}
Groups

Groups allow one to collect a set of errors. For example:

func tonsOfErrors() error {
	var group errs.Group
	for _, work := range someWork {
		group.Add(maybeErrors(work))
	}
	return group.Err()
}

Some things to note:

  • The Add method only adds to the group if the passed in error is non-nil.
  • The Err method returns an error only if non-nil errors have been added, and aditionally returns just the error if only one error was added. Thus, we always have that if you only call group.Add(err), then group.Err() == err.

The returned error will format itself similarly:

func groupFormat() {
	var group errs.Group
	group.Add(errs.Errorf("first"))
	group.Add(errs.Errorf("second"))
	err := group.Err()

	fmt.Printf("%v\n", err)
	fmt.Println()
	fmt.Printf("%+v\n", err)

	// output:
	// first; second
	//
	// group:
	// --- first
	// 	... stack trace
	// --- second
	// 	... stack trace
}
Contributing

errs is released under an MIT License. If you want to contribute, be sure to add yourself to the list in AUTHORS.

Documentation

Overview

Package errs provides a simple error package with stack traces.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Combine

func Combine(errs ...error) error

Combine combines multiple non-empty errors into a single error.

func Errorf

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

Errorf does the same thing as fmt.Errorf(...) except it captures a stack trace on creation.

func Tagged

func Tagged(tag string, err error) error

Tagged is a shorthand for Tag(tag).Wrap(err).

func Wrap

func Wrap(err error) error

Wrap returns an error not contained in any class. It just associates a stack trace with the error. Wrap returns nil if err is nil.

Types

type Group

type Group []error

Group is a list of errors.

func (*Group) Add

func (g *Group) Add(errs ...error)

Add adds non-empty errors to the Group.

func (*Group) Append

func (g *Group) Append(err error)

Append adds a non-empty error to the Group.

func (Group) Err

func (g Group) Err() error

Err returns an error containing all of the non-nil errors. If there was only one error, it will return it. If there were none, it returns nil.

type Tag

type Tag string

Tag represents some extra information about an error.

func Tags

func Tags(err error) (tags []Tag)

Tags returns all the tags that have wrapped the error.

func (Tag) Error

func (t Tag) Error() string

Error returns the class string as the error text. It allows the use of errors.Is, or as just an easy way to have a string constant error.

func (Tag) Errorf

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

New constructs an error with the format string that will be contained by this class. This is the same as calling Wrap(fmt.Errorf(...)).

func (Tag) Name

func (t Tag) Name() (string, bool)

Name returns the name of the tag.

func (Tag) Wrap

func (t Tag) Wrap(err error) error

Wrap returns a new error based on the passed in error that is contained in this class. Wrap returns nil if err is nil.

Directories

Path Synopsis
Package errdata helps with associating some data to error classes
Package errdata helps with associating some data to error classes

Jump to

Keyboard shortcuts

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