luci: go.chromium.org/luci/common/errors Index | Examples | Files

package errors

import "go.chromium.org/luci/common/errors"

Package errors is an augmented replacement package for the stdlib "errors" package. It contains the same New method, but also has some handy methods and types for dealing with errors.

Index

Examples

Package Files

annotate.go doc.go filter.go lazymultierror.go multierror.go tags.go walk.go wrap.go

func Any Uses

func Any(err error, fn func(error) bool) (any bool)

Any performs a Walk traversal of an error, returning true (and short-circuiting) if the supplied filter function returns true for any visited erorr.

If err is nil, Any will return false.

func Filter Uses

func Filter(err error, exclude error, others ...error) error

Filter examines a supplied error and removes instances of excluded errors from it. If the entire supplied error is excluded, Filter will return nil.

If a MultiError is supplied to Filter, it will be recursively traversed, and its child errors will be turned into nil if they match the supplied filter. If a MultiError has all of its children converted to nil as a result of the filter, it will itself be reduced to nil.

func FilterFunc Uses

func FilterFunc(err error, shouldFilter func(error) bool) error

FilterFunc examines a supplied error and removes instances of errors that match the supplied filter function. If the entire supplied error is removed, FilterFunc will return nil.

If a MultiError is supplied to FilterFunc, it will be recursively traversed, and its child errors will be turned into nil if they match the supplied filter function. If a MultiError has all of its children converted to nil as a result of the filter, it will itself be reduced to nil.

Consqeuently, if err is a MultiError, shouldFilter will be called once with err as its value and once for every non-nil error that it contains.

func GetTags Uses

func GetTags(err error) map[TagKey]interface{}

GetTags returns a map of all TagKeys set in this error to their value.

A nil value means that the tag is present, but has a nil associated value.

This is done in a depth-first traversal of the error stack, with the most-recently-set value of the tag taking precendence.

func Log Uses

func Log(c context.Context, err error, excludePkgs ...string)

Log logs the full error. If this is an Annotated error, it will log the full stack information as well.

This is a shortcut for logging the output of RenderStack(err).

func New Uses

func New(msg string, tags ...TagValueGenerator) error

New is an API-compatible version of the standard errors.New function. Unlike the stdlib errors.New, this will capture the current stack information at the place this error was created.

func RenderStack Uses

func RenderStack(err error, excludePkgs ...string) []string

RenderStack renders the error to a list of lines.

func SingleError Uses

func SingleError(err error) error

SingleError provides a simple way to uwrap a MultiError if you know that it could only ever contain one element.

If err is a MultiError, return its first element. Otherwise, return err.

func TagValueIn Uses

func TagValueIn(t TagKey, err error) (value interface{}, ok bool)

TagValueIn will retrieve the tagged value from the error that's associated with this key, and a boolean indicating if the tag was present or not.

func Unwrap Uses

func Unwrap(err error) error

Unwrap unwraps a wrapped error recursively, returning its inner error.

If the supplied error is not nil, Unwrap will never return nil. If a wrapped error reports that its InnerError is nil, that error will be returned.

func Walk Uses

func Walk(err error, fn func(error) bool)

Walk performs a depth-first traversal of the supplied error, unfolding it and invoke the supplied callback for each layered error recursively. If the callback returns true, Walk will continue its traversal.

- If walk encounters a MultiError, the callback is called once for the
  outer MultiError, then once for each inner error.
- If walk encounters a Wrapped error, the callback is called for the outer
  and inner error.
- If an inner error is, itself, a container, Walk will recurse into it.

If err is nil, the callback will not be invoked.

func WalkLeaves Uses

func WalkLeaves(err error, fn func(error) bool)

WalkLeaves is like Walk, but only calls fn on leaf nodes.

type Annotator Uses

type Annotator struct {
    // contains filtered or unexported fields
}

Annotator is a builder for annotating errors. Obtain one by calling Annotate on an existing error or using Reason.

See the example test for Annotate to see how this is meant to be used.

func Annotate Uses

func Annotate(err error, reason string, args ...interface{}) *Annotator

Annotate captures the current stack frame and returns a new annotatable error, attaching the publically readable `reason` format string to the error. You can add additional metadata to this error with the 'InternalReason' and 'Tag' methods, and then obtain a real `error` with the Err() function.

If this is passed nil, it will return a no-op Annotator whose .Err() function will also return nil.

The original error may be recovered by using Wrapped.InnerError on the returned error.

Rendering the derived error with Error() will render a summary version of all the public `reason`s as well as the initial underlying error's Error() text. It is intended that the initial underlying error and all annotated reasons only contain user-visible information, so that the accumulated error may be returned to the user without worrying about leakage.

You should assume that end-users (including unauthenticated end users) may see the text in the `reason` field here. To only attach an internal reason, leave the `reason` argument blank and don't pass any additional formatting arguments.

The `reason` string is formatted with `args` and may contain Sprintf-style formatting directives.

Code:

package main

import (
    "fmt"
)

func someProcessingFunction(val int) error {
    if val == 1 {
        // New and Reason automatically include stack information.
        return Reason("bad number: %d", val).Err()
    }
    if err := someProcessingFunction(val - 1); err != nil {
        // correctly handles recursion
        return Annotate(err, "").InternalReason("val(%d)", val).Err()
    }
    return nil
}

func someLibFunc(vals ...int) error {
    for i, v := range vals {
        if err := someProcessingFunction(v); err != nil {
            return Annotate(err, "processing %d", v).
                InternalReason("secret(%s)/i(%d)", "value", i).Err()
        }
    }
    return nil
}

type MiscWrappedError struct{ error }

func (e *MiscWrappedError) Error() string     { return fmt.Sprintf("super wrapper(%s)", e.error.Error()) }
func (e *MiscWrappedError) InnerError() error { return e.error }

func errorWrapper(err error) error {
    if err != nil {
        err = &MiscWrappedError{err}
    }
    return err
}

func someIntermediateFunc(vals ...int) error {
    errch := make(chan error)
    go func() {
        defer close(errch)
        errch <- Annotate(errorWrapper(someLibFunc(vals...)), "could not process").Err()
    }()
    me := MultiError(nil)
    for err := range errch {
        if err != nil {
            me = append(me, err)
        }
    }
    if me != nil {
        return Annotate(me, "while processing %v", vals).Err()
    }
    return nil
}

func main() {
    if err := someIntermediateFunc(3); err != nil {
        err = Annotate(err, "top level").Err()
        fmt.Println("Public-facing error:\n ", err)
        fmt.Println("\nfull error:")
        for _, l := range FixForTest(RenderStack(err, "runtime", "_test")) {
            fmt.Println(l)
        }
    }

}

func Reason Uses

func Reason(reason string, args ...interface{}) *Annotator

Reason builds a new Annotator starting with reason. This allows you to use all the formatting directives you would normally use with Annotate, in case your originating error needs tags or an internal reason.

errors.Reason("something bad: %d", value).Tag(transient.Tag).Err()

Prefer this form to errors.New(fmt.Sprintf("..."))

func (*Annotator) Err Uses

func (a *Annotator) Err() error

Err returns the finalized annotated error.

go:noinline

func (*Annotator) InternalReason Uses

func (a *Annotator) InternalReason(reason string, args ...interface{}) *Annotator

InternalReason adds a stack-trace-only internal reason string (for humans) to this error.

The text here will only be visible when using `errors.Log` or `errors.RenderStack`, not when calling the .Error() method of the resulting error.

The `reason` string is formatted with `args` and may contain Sprintf-style formatting directives.

func (*Annotator) Tag Uses

func (a *Annotator) Tag(tags ...TagValueGenerator) *Annotator

Tag adds a tag with an optional value to this error.

`value` is a unary optional argument, and must be a simple type (i.e. has a reflect.Kind which is a base data type like bool, string, or int).

type BoolTag Uses

type BoolTag struct{ Key TagKey }

BoolTag is an error tag implementation which holds a boolean value.

It should be constructed like:

var myTag = errors.BoolTag{Key: errors.NewTagKey("some description")}

func (BoolTag) Apply Uses

func (b BoolTag) Apply(err error) error

Apply is a shortcut for With(true).Apply(err)

func (BoolTag) GenerateErrorTagValue Uses

func (b BoolTag) GenerateErrorTagValue() TagValue

GenerateErrorTagValue implements TagValueGenerator, and returns a default value for the tag of `true`. If you want to set this BoolTag value to false, use BoolTag.Off().

func (BoolTag) In Uses

func (b BoolTag) In(err error) bool

In returns true iff this tag value has been set to true on this error.

func (BoolTag) Off Uses

func (b BoolTag) Off() TagValue

Off allows you to "remove" this boolean tag from an error (by setting it to false).

type LazyMultiError Uses

type LazyMultiError interface {
    // Assign semantically assigns the error to the given index in the MultiError.
    // If the error is nil, no action is taken. Otherwise the MultiError is
    // allocated to its full size (if not already), and the error assigned into
    // it.
    //
    // Returns true iff err != nil (i.e. "was it assigned?"), so you can use this
    // like:
    //   if !lme.Assign(i, err) {
    //     // stuff requiring err == nil
    //   }
    Assign(int, error) bool

    // GetOne returns the error at the given index (which may be nil)
    GetOne(int) error

    // Get returns the MultiError, or nil, if no non-nil error was Assign'd.
    Get() error
}

LazyMultiError is a lazily-constructed MultiError.

LazyMultiError is like MultiError, except that you know the ultimate size up front, and then you call Assign for each error encountered, and it's potential index. The underlying MultiError will only be allocated if one of the Assign'd errors is non-nil. Similarly, Get will retrieve either the allocated MultiError, or nil if no error was encountered. Build one with NewLazyMultiError.

func NewLazyMultiError Uses

func NewLazyMultiError(size int) LazyMultiError

NewLazyMultiError makes a new LazyMultiError of the provided size.

type MultiError Uses

type MultiError []error

MultiError is a simple `error` implementation which represents multiple `error` objects in one.

func NewMultiError Uses

func NewMultiError(errors ...error) MultiError

NewMultiError create new multi error from given errors.

Can be used to workaround 'go vet' confusion "composite literal uses unkeyed fields" or if you do not want to remember that MultiError is in fact []error.

func (MultiError) Error Uses

func (m MultiError) Error() string

func (MultiError) First Uses

func (m MultiError) First() error

First returns the first non-nil error.

func (MultiError) Summary Uses

func (m MultiError) Summary() (n int, first error)

Summary gets the total count of non-nil errors and returns the first one.

type TagKey Uses

type TagKey *tagDescription

TagKey objects are used for applying tags and finding tags/values in errors. See NewTag for details.

func NewTagKey Uses

func NewTagKey(description string) TagKey

NewTagKey creates a new TagKey.

Use this with a BoolTag or your own custom tag implementation.

Example (bool tag):

var myTag = errors.BoolTag{Key: errors.NewTagKey("this error is a user error")}

err = myTag.Apply(err)
myTag.In(err) // == true

err2 := myTag.Off().Apply(err)
myTag.In(err2) // == false

Example (custom tag)

type SomeType int
type myTag struct { Key errors.TagKey }
func (m myTag) With(value SomeType) errors.TagValue {
  return errors.TagValue{Key: vm.Key, Value: value}
}
func (m myTag) In(err error) (v SomeType, ok bool) {
  d, ok := errors.TagValueIn(m.Key, err)
  if ok {
    v = d.(SomeType)
  }
  return
}
var MyTag = myTag{errors.NewTagKey("has a SomeType")}

You could then use it like:

err = MyTag.With(100).Apply(err)
MyTag.In(err) // == true
MyTag.ValueIn(err) // == (SomeType(100), true)

type TagValue Uses

type TagValue struct {
    Key   TagKey
    Value interface{}
}

TagValue represents a (tag, value) to be used with Annotate.Tag, or may be applied to an error directly with the Apply method.

Usually tag implementations will have a typesafe With method that generates these. Avoid constructing these ad-hoc so that a given tag definition can control the type safety around these.

func (TagValue) Apply Uses

func (t TagValue) Apply(err error) error

Apply applies this tag value (key+value) directly to the error. This is a shortcut for `errors.Annotate(err, "").Tag(t).Err()`.

func (TagValue) GenerateErrorTagValue Uses

func (t TagValue) GenerateErrorTagValue() TagValue

GenerateErrorTagValue implements TagValueGenerator

type TagValueGenerator Uses

type TagValueGenerator interface {
    GenerateErrorTagValue() TagValue
}

TagValueGenerator generates (TagKey, value) pairs, for use with Annoatator.Tag and New().

type Wrapped Uses

type Wrapped interface {
    // InnerError returns the wrapped error.
    InnerError() error
}

Wrapped indicates an error that wraps another error.

Package errors imports 15 packages (graph) and is imported by 302 packages. Updated 2018-08-15. Refresh now. Tools for package owners.