Documentation

Overview

    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

    Constants

    This section is empty.

    Variables

    This section is empty.

    Functions

    func Any

    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 error.

      If err is nil, Any will return false.

      func Contains

      func Contains(outer error, inner error) bool

        Contains performs a Walk traversal of |outer|, returning true if any visited error is equal to |inner|.

        func Filter

        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

          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 Flatten

            func Flatten(err error) error

              Flatten collapses a multi-dimensional MultiError space into a flat MultiError, removing "nil" errors.

              If err is not an errors.MultiError, will return err directly.

              As a special case, if merr contains no non-nil errors, nil will be returned.

              func GetTags

              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 precedence.

                func IsPanicking

                func IsPanicking(skip int) bool

                  IsPanicking returns true iff the current goroutine is panicking.

                  Always returns false when not invoked via a defer'd function.

                  This should only be used to indicate some best-effort error status, not to modify control flow of the program. Panics are still crashes!

                  HACK: Detection is implemented by looking up the stack at most skip+10 frames above IsPanicking to find if the golang panic handler is on the stack. This may break when the Go runtime changes!

                  `skip` indicates how many additional frames of the stack to skip (a value of 0 starts the stack at the caller of `IsPanicking`). Clamps to a minimum value of 0.

                  Does NOT invoke `recover()`. WILL detect `panic(nil)`.

                  Example
                  Output:
                  
                  smooth sailing
                  kalm
                  first pass success
                  about to boom
                  PANIK!
                  stack trace originates from CrashingFunction
                  

                  func Log

                  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).

                    If resulting log message is large, splits it into log entries of at most 64KiB.

                    func New

                    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

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

                        RenderStack renders the error to a list of lines.

                        func SingleError

                        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

                          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

                            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 Unwrap is nil, that error will be returned.

                              func Walk

                              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

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

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

                                  Types

                                  type Annotator

                                  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

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

                                      Annotate captures the current stack frame and returns a new annotatable error, attaching the publicly 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.Unwrap 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.

                                      Example
                                      Output:
                                      
                                      Public-facing error:
                                        top level: while processing [3]: could not process: super wrapper(processing 3: bad number: 1)
                                      
                                      full error:
                                      GOROUTINE LINE
                                      #? go.chromium.org/luci/common/errors/annotate_example_test.go:24 - errors.someProcessingFunction()
                                        reason: bad number: 1
                                      
                                      #? go.chromium.org/luci/common/errors/annotate_example_test.go:26 - errors.someProcessingFunction()
                                        internal reason: val(2)
                                      
                                      #? go.chromium.org/luci/common/errors/annotate_example_test.go:26 - errors.someProcessingFunction()
                                        internal reason: val(3)
                                      
                                      From frame 2 to 3, the following wrappers were found:
                                        unknown wrapper *errors.MiscWrappedError
                                      
                                      #? go.chromium.org/luci/common/errors/annotate_example_test.go:35 - errors.someLibFunc()
                                        reason: processing 3
                                        internal reason: secret(value)/i(0)
                                      
                                      From frame 3 to 4, the following wrappers were found:
                                        internal reason: MultiError 1/1: following first non-nil error.
                                      
                                      #? go.chromium.org/luci/common/errors/annotate_example_test.go:59 - errors.someIntermediateFunc.func1()
                                        reason: could not process
                                      
                                      ... skipped SOME frames in pkg "runtime"...
                                      
                                      GOROUTINE LINE
                                      #? go.chromium.org/luci/common/errors/annotate_example_test.go:68 - errors.someIntermediateFunc()
                                        reason: while processing [3]
                                      
                                      #? go.chromium.org/luci/common/errors/annotate_example_test.go:74 - errors.ExampleAnnotate()
                                        reason: top level
                                      
                                      #? testing/run_example.go:XXX - testing.runExample()
                                      #? testing/example.go:XXX - testing.runExamples()
                                      #? testing/testing.go:XXX - testing.(*M).Run()
                                      #? ./_testmain.go:XXX - main.main()
                                      ... skipped SOME frames in pkg "runtime"...
                                      

                                      func Reason

                                      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

                                        func (a *Annotator) Err() error

                                          Err returns the finalized annotated error.

                                          go:noinline

                                          func (*Annotator) InternalReason

                                          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

                                            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

                                              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

                                                func (b BoolTag) Apply(err error) error

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

                                                  func (BoolTag) GenerateErrorTagValue

                                                  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

                                                    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

                                                      func (b BoolTag) Off() TagValue

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

                                                        type LazyMultiError

                                                        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

                                                          func NewLazyMultiError(size int) LazyMultiError

                                                            NewLazyMultiError makes a new LazyMultiError of the provided size.

                                                            type MultiError

                                                            type MultiError []error

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

                                                              func NewMultiError

                                                              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

                                                                func (m MultiError) Error() string

                                                                func (MultiError) First

                                                                func (m MultiError) First() error

                                                                  First returns the first non-nil error.

                                                                  func (MultiError) Summary

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

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

                                                                    type TagKey

                                                                    type TagKey *tagDescription

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

                                                                      func NewTagKey

                                                                      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: m.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
                                                                        errors.ValueIn(err) // == (SomeType(100), true)
                                                                        

                                                                        type TagValue

                                                                        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

                                                                          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

                                                                            func (t TagValue) GenerateErrorTagValue() TagValue

                                                                              GenerateErrorTagValue implements TagValueGenerator

                                                                              type TagValueGenerator

                                                                              type TagValueGenerator interface {
                                                                              	GenerateErrorTagValue() TagValue
                                                                              }

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

                                                                                type Wrapped

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

                                                                                  Wrapped indicates an error that wraps another error.