errz

package
v0.48.0 Latest Latest
Warning

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

Go to latest
Published: Mar 8, 2024 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package errz is sq's error package. It annotates errors with stack traces, and provides functionality for working with multiple errors, and error chains.

This package is the lovechild of Dave Cheney's pkg/errors and Uber's go.uber.org/multierr, and much of the code is borrowed from those packages.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoMsg = errors.New("")

ErrNoMsg is a sentinel error indicating that a command has failed (and thus the program should exit with a non-zero code), but no error message should be printed. This is useful in the case where any error information may already have been printed as part of the command output.

View Source
var ErrStop = errors.New("explicit stop")

ErrStop is a sentinel error a la io.EOF used to indicate that an explicit stop condition has been reached. The stop condition is typically not an indication of a failure state, but rather a signal to stop processing. It is usually used in conjunction with context.CancelCauseFunc.

See: IsContextStop.

Functions

func Append

func Append(left, right error) error

Append appends the given errors together. Either value may be nil. The value of the returned error's [error.Error] method is a semicolon-delimited list of the non-nil errors' messages. This is different from the behavior of stdlib errors.Join, which separates errors with newlines. But, we choose to use semicolons because it's more readable in logs and error messages.

This function is a specialization of Combine for the common case where there are only two errors.

err = multierr.Append(reader.Close(), writer.Close())

The following pattern may also be used to record failure of deferred operations without losing information about the original error.

func doSomething(..) (err error) {
	f := acquireResource()
	defer func() {
		err = multierr.Append(err, f.Close())
	}()

Note that the variable MUST be a named return to append an error to it from the defer statement.

func As added in v0.47.0

func As[E error](err error) (E, bool)

As is a convenience wrapper around errors.As.

_, err := os.Open("non-existing")
pathErr, ok := errz.As[*fs.PathError](err)
require.True(t, ok)
require.Equal(t, "non-existing", pathErr.Path)

If err is nil, As returns false. See also: errz.Has.

func Chain added in v0.47.0

func Chain(err error) []error

Chain returns a slice of all the errors in err's tree.

func Combine

func Combine(errs ...error) error

Combine combines the passed errors into a single error.

If zero arguments were passed or if all items are nil, a nil error is returned.

Combine(nil, nil)  // == nil

If only a single error was passed, it is returned as-is.

Combine(err)  // == err

Combine skips over nil arguments so this function may be used to combine together errors from operations that fail independently of each other.

multierr.Combine(
	reader.Close(),
	writer.Close(),
	pipe.Close(),
)

If any of the passed errors is a multierr error, it will be flattened along with the other errors.

multierr.Combine(multierr.Combine(err1, err2), err3)
// is the same as
multierr.Combine(err1, err2, err3)

The returned error formats into a readable multi-line error message if formatted with %+v.

fmt.Sprintf("%+v", multierr.Combine(err1, err2))

func Drain added in v0.48.0

func Drain(errCh <-chan error) error

Drain reads all currently available non-nil errors from errCh. If errCh is nil, or there are no errors to read, Drain returns nil. If there's only a single error, Drain returns it. If there are multiple errors, Drain returns a multi-error created via errz.Append. Drain does not block; it does not wait for errCh to be closed. Thus, invoking Drain again on the same errCh may yield additional errors.

func Err

func Err(err error, opts ...Opt) error

Err annotates err with a stack trace at the point Err was called. It is equivalent to Wrap(err, ""). If err is nil, Err returns nil.

func Errorf

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

Errorf works like fmt.Errorf, but it also records the stack trace at the point it was called. If the format string includes the %w verb, fmt.Errorf is first called to construct the error, and then the returned error is again wrapped to record the stack trace.

func Errors

func Errors(err error) []error

Errors returns a slice containing zero or more errors that the supplied error is composed of. If the error is nil, a nil slice is returned.

err := multierr.Append(r.Close(), w.Close())
errors := multierr.Errors(err)

If the error is not composed of other errors, the returned slice contains just the error that was passed in.

Callers of this function are free to modify the returned slice.

func Every added in v0.47.0

func Every(err, target error) bool

Every compares every error in the given err against the given target error using errors.Is, and returns true only if every comparison returned true.

func ExitCode added in v0.47.4

func ExitCode(err error) (code int)

ExitCode returns the exit code of the first error in err's chain that implements ExitCoder, otherwise -1.

func Has added in v0.47.0

func Has[E error](err error) bool

Has returns true if err, or an error in its error tree, matches error type E. An error is considered a match by the rules of errors.As:

f, err := os.Open("non-existing")
if errz.Has[*fs.PathError](err) {
	// Do something
}

If err is nil, Has returns false. See also: errz.As.

func IsContextStop added in v0.48.0

func IsContextStop(ctx context.Context) bool

IsContextStop returns true if ctx's cause error is ErrStop.

func IsErrContext added in v0.48.0

func IsErrContext(err error) bool

IsErrContext returns true if err's chain contains context.Canceled or context.DeadlineExceeded.

func New

func New(message string, opts ...Opt) error

New returns an error with the supplied message, recording the stack trace at the point it was called.

func Return added in v0.47.0

func Return[T any](t T, err error) (T, error)

Return returns t with err wrapped via errz.Err. This is useful for the common case of returning a value and an error from a function.

written, err = errz.Return(io.Copy(w, r))

func SprintTreeTypes added in v0.47.0

func SprintTreeTypes(err error) string

SprintTreeTypes returns a string representation of err's type tree. A multi-error is represented as a slice of its children.

func UnwrapChain added in v0.47.0

func UnwrapChain(err error) error

UnwrapChain returns the underlying *root* cause of the error. That is to say, UnwrapChain returns the final non-nil error in the error chain. UnwrapChain returns nil if err is nil.

func WithExitCode added in v0.48.0

func WithExitCode(err error, code int) error

WithExitCode returns an error that implements ExitCoder, if err is non-nil. If err is nil, WithExitCode returns nil. If err already implements ExitCoder and its exit code is the same as code, WithExitCode returns err unchanged.

func Wrap

func Wrap(err error, message string) error

Wrap returns an error annotating err with a stack trace at the point Wrap is called, and the supplied message. If err is nil, Wrap returns nil. See also: Wrapf.

func Wrapf

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

Wrapf returns an error annotating err with a stack trace at the point Wrapf is called. Wrapf will panic if format includes the %w verb: use errz.Errorf for that situation. If err is nil, Wrapf returns nil. See also: Wrap, Errorf.

Types

type ExitCoder added in v0.47.4

type ExitCoder interface {
	// ExitCode returns the exit code indicated by the error, or -1 if
	// the error does not indicate a particular exit code.
	ExitCode() int
}

ExitCoder is an interface that an error type can implement to indicate that the program should exit with a specific status code. In particular, note that *exec.ExitError implements this interface.

type Frame added in v0.31.0

type Frame uintptr

Frame represents a program counter inside a stack frame. For historical reasons if Frame is interpreted as a uintptr its value represents the program counter + 1.

func (Frame) Format added in v0.31.0

func (f Frame) Format(s fmt.State, verb rune)

Format formats the frame according to the fmt.Formatter interface.

%s    source file
%d    source line
%n    function name
%v    equivalent to %s:%d

Format accepts flags that alter the printing of some verbs, as follows:

%+s   function name and path of source file relative to the compile time
      GOPATH separated by \n\t (<funcname>\n\t<path>)
%+v   equivalent to %+s:%d

func (Frame) MarshalText added in v0.31.0

func (f Frame) MarshalText() ([]byte, error)

MarshalText formats a stacktrace Frame as a text string. The output is the same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.

type Frames added in v0.47.0

type Frames []Frame

Frames is the ordered list of frames that make up a stack trace.

func (Frames) Format added in v0.47.0

func (fs Frames) Format(s fmt.State, verb rune)

Format formats the stack of Frames according to the fmt.Formatter interface.

%s	lists source files for each Frame in the stack
%v	lists the source file and line number for each Frame in the stack

Format accepts flags that alter the printing of some verbs, as follows:

%+v   Prints filename, function, and line number for each Frame in the stack.

type Opt added in v0.47.0

type Opt interface {
	// contains filtered or unexported methods
}

Opt is a functional option. Use with Err or New.

type Skip added in v0.47.0

type Skip int

Skip is an Opt that can be passed to Err or New that indicates how many frames to skip when recording the stack trace. This is useful when wrapping errors in helper functions.

func handleErr(err error) error {
	slog.Default().Error("Oh noes", "err", err)
	return errz.Err(err, errz.Skip(1))
}

Skipping too many frames will panic.

type StackTrace added in v0.31.0

type StackTrace struct {
	// Error is the error value that resulted in this stack trace.
	Error error

	// Frames is the ordered list of frames that make up this stack trace.
	Frames Frames
}

StackTrace contains a stack of Frames from innermost (newest) to outermost (oldest), as well as the error value that resulted in this stack trace.

func LastStack added in v0.47.0

func LastStack(err error) *StackTrace

LastStack returns the last of any stack trace(s) attached to err, or nil. Contrast with errz.Stacks, which returns all stack traces attached to any error in the chain. But if you only want to examine one stack, the final stack trace is usually the most interesting, which is why this function exists.

The returned StackTrace.Frames can be printed using fmt "%+v".

func Stacks added in v0.47.0

func Stacks(err error) []*StackTrace

Stacks returns all stack trace(s) attached to err. If err has been wrapped more than once, there may be multiple stack traces. Generally speaking, the final stack trace is the most interesting; you can use errz.LastStack if you're just interested in that one.

The returned StackTrace.Frames can be printed using fmt "%+v".

func (*StackTrace) LogValue added in v0.47.0

func (st *StackTrace) LogValue() slog.Value

LogValue implements slog.LogValuer.

Jump to

Keyboard shortcuts

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