errors

package module
v1.1.1 Latest Latest
Warning

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

Go to latest
Published: Jun 18, 2019 License: Apache-2.0 Imports: 17 Imported by: 0

README

cockroachdb/errors: Go errors with network portability

This library was designed in the fashion discussed in https://github.com/cockroachdb/cockroach/pull/36987 and https://github.com/cockroachdb/cockroach/pull/37121

Feature Go's <1.13 errors github.com/pkg/errors Go 1.13 errors/xerrors cockroachdb/errors
error constructors (New, Errorf etc)
error causes (Cause / Unwrap)
cause barriers (Opaque / Handled)
errors.Is()
standard wrappers with efficient stack trace capture
transparent protobuf encode/decode with forward compatibility
errors.Is() recognizes errors across the network
comprehensive support for PII-free reportable strings
support for both Cause() and Unwrap() go#31778
standard error reports to Sentry.io
wrappers to denote assertion failures
wrappers with issue tracker references
wrappers for user-facing hints and details
wrappers to attach secondary causes
wrappers to attach logtags details from context.Context
errors.As() (in construction)
errors.FormatError(), Formatter, Printer (in construction)

"Forward compatibility" above refers to the ability of this library to recognize and properly handle network communication of error types it does not know about, for example when a more recent version of a software package sends a new error object to another system running an older version of the package.

How to use

  • construct errors with errors.New(), etc as usual, but also see the other error leaf constructors below.
  • wrap errors with errors.Wrap() as usual, but also see the other wrappers below.
  • test error identity with errors.Is() as usual. Unique in this library: this works even if the error has traversed the network! Also, errors.IsAny() to recognize two or more reference errors.
  • access error causes with errors.UnwrapOnce() / errors.UnwrapAll() (note: errors.Cause() and errors.Unwrap() also provided for compatibility with other error packages).
  • encode/decode errors to protobuf with errors.EncodeError() / errors.DecodeError().
  • extract PII-free safe details with errors.GetSafeDetails().
  • extract human-facing hints and details with errors.GetAllHints()/errors.GetAllDetails() or errors.FlattenHints()/errors.FlattenDetails().
  • produce detailed Sentry.io reports with errors.BuildSentryReport() / errors.ReportError().
  • implement your own error leaf types and wrapper types:
    • implement the error and errors.Wrapper interfaces as usual.
    • register encode/decode functions: call errors.Register{Leaf,Wrapper}{Encoder,Decoder}() in a init() function in your package.

What comes out of an error?

Error detail Error() and format %s/%q/%v format %+v GetSafeDetails() Sentry report via ReportError()
main message, eg New() visible visible (first line) redacted redacted
wrap prefix, eg WithMessage() visible (as prefix) visible redacted redacted
stack trace, eg WithStack() not visible visible yes full
hint , eg WithHint() not visible visible no type only
detail, eg WithDetail() not visible visible no type only
assertion failure annotation, eg WithAssertionFailure() not visible visible no type only
issue links, eg WithIssueLink(), UnimplementedError() not visible visible yes full
safe details, eg WithSafeDetails() not visible visible yes full
telemetry keys, eg. WithTelemetryKey() not visible visible yes full
secondary errors, eg. WithSecondaryError(), CombineErrors() not visible visible redacted, recursively redacted, recursively
barrier origins, eg. Handled() not visible visible redacted, recursively redacted, recursively
error domain, eg. WithDomain() not visible visible yes full
context tags, eg. WithContextTags() not visible visible no keys visible, values redacted

Available error leaves

  • New(), Newf(), Errorf(): leaf errors with message

    • when to use: common error cases.
    • what it does: also captures the stack trace at point of call and redacts the provided message for safe reporting.
    • how to access the detail: Error(), regular Go formatting. Details redacted in Sentry report.
    • see also: Section Error composition below. errors.NewWithDepth() variants to customize at which call depth the stack trace is captured.
  • AssertionFailedf(), NewAssertionFailureWithWrappedErrf(): signals an assertion failure / programming error.

    • when to use: when an invariant is violated; when an unreachable code path is reached.
    • what it does: also captures the stack trace at point of call, redacts the provided strings for safe reporting, prepares a hint to inform a human user.
    • how to access the detail: IsAssertionFailure()/HasAssertionFailure(), format with %+v, Safe details included in Sentry reports.
    • see also: Section Error composition below. errors.AssertionFailedWithDepthf() variant to customize at which call depth the stack trace is captured.
  • Handled(), Opaque(), HandledWithMessage(): captures an error cause but make it invisible to Unwrap() / Is().

    • when to use: when a new error occurs while handling an error, and the original error must be "hidden".
    • what it does: captures the cause in a hidden field. The error message is preserved unless the ...WithMessage() variant is used.
    • how to access the detail: format with %+v, redacted details reported in Sentry reports.
  • UnimplementedError(): captures a message string and a URL reference to an external resource to denote a feature that was not yet implemented.

    • when to use: to inform (human) users that some feature is not implemented yet and refer them to some external resource.
    • what it does: captures the message, URL and detail in a wrapper. The URL and detail are considered safe for reporting.
    • how to access the detail: errors.GetAllHints(), errors.FlattenHints(), format with %+v, URL and detail included in Sentry report (not the message).
    • see also: errors.WithIssueLink() below for errors that are not specifically about unimplemented features.

Available wrapper constructors

All wrapper constructors can be applied safely to a nil error: they behave as no-ops in this case:

// The following:
// if err := foo(); err != nil {
//    return errors.Wrap(err, "foo")
// }
// return nil
//
// is not needed. Instead, you can use this:
return errors.Wrap(foo())
  • Wrap(), Wrapf():

    • when to use: on error return paths.
    • what it does: combines WithMessage(), WithStack(), WithSafeDetails().
    • how to access the details: Error(), regular Go formatting. Details redacted in Sentry report.
    • see also: Section Error composition below. WrapWithDepth() variants to customize at which depth the stack trace is captured.
  • WithSecondaryError(): annotate an error with a secondary error.

    • when to use: when an additional error occurs in the code that is handling a primary error. Consider using errors.CombineErrors() instead (see below).
    • what it does: it captures the secondary error but hides it from errors.Is().
    • how to access the detail: format with %+v, redacted recursively in Sentry reports.
    • see also: errors.CombineErrors()
  • CombineErrors(): combines two errors into one.

    • when to use: when two operations occur concurrently and either can return an error, and only one final error must be returned.
    • what it does: returns either of its arguments if the other is nil, otherwise calls WithSecondaryError().
    • how to access the detail: see WithSecondaryError() above.
  • Mark(): gives the identity of one error to another error.

    • when to use: when a caller expects to recognize a sentinel error with errors.Is() but the callee provides a diversity of error messages.
    • what it does: it overrides the "error mark" used internally by errors.Is().
    • how to access the detail: format with %+v, Sentry reports.
  • WithStack(): annotate with stack trace

    • when to use: usually not needed, use errors.Wrap()/errors.Wrapf() instead.

      Special cases:

      • when returning a sentinel, for example:

        var myErr = errors.New("foo")
        
        func myFunc() error {
          if ... {
             return errors.WithStack(myErr)
          }
        }
        
      • on error return paths, when not trivial but also not warranting a wrap. For example:

        err := foo()
        if err != nil {
          doSomething()
          if !somecond {
             return errors.WithStack(err)
          }
        }
        
    • what it does: captures (efficiently) a stack trace.

    • how to access the details: format with %+v, errors.GetSafeDetails(), Sentry reports. The stack trace is considered safe for reporting.

    • see also: WithStackDepth() to customize the call depth at which the stack trace is captured.

  • WithSafeDetails(): safe details for reporting.

    • when to use: probably never. Use errors.Wrap()/errors.Wrapf() instead.
    • what it does: saves some strings for safe reporting.
    • how to access the detail: format with %+v, errors.GetSafeDetails(), Sentry report.
  • WithMessage(): message prefix.

    • when to use: probably never. Use errors.Wrap()/errors.Wrapf() instead.
    • what it does: adds a message prefix.
    • how to access the detail: Error(), regular Go formatting. Not included in Sentry reports.
  • WithDetail(), WithDetailf(), user-facing detail with contextual information.

    • when to use: need to embark a message string to output when the error is presented to a human.
    • what it does: captures detail strings.
    • how to access the detail: errors.GetAllDetails(), errors.FlattenDetails() (all details are preserved), format with %+v.
  • WithHint(), WithHintf(): user-facing detail with suggestion for action to take.

    • when to use: need to embark a message string to output when the error is presented to a human.
    • what it does: captures hint strings.
    • how to access the detail: errors.GetAllHints(), errors.FlattenHints() (hints are de-duplicated), format with %+v.
  • WithIssueLink(): annotate an error with an URL and arbitrary string.

    • when to use: to refer (human) users to some external resources.
    • what it does: captures the URL and detail in a wrapper. Both are considered safe for reporting.
    • how to access the detail: errors.GetAllHints(), errors.FlattenHints(), errors.GetSafeDetails(), format with %+v, Sentry report.
    • see also: errors.UnimplementedError() to construct leaves (see previous section).
  • WithTelemetry(): annotate an error with a key suitable for telemetry.

    • when to use: to gather strings during error handling, for capture in the telemetry sub-system of a server package.
    • what it does: captures the string. The telemetry key is considered safe for reporting.
    • how to access the detail: errors.GetTelemetryKeys(), errors.GetSafeDetails(), format with %+v, Sentry report.
  • WithDomain(), HandledInDomain(), HandledInDomainWithMessage() (experimental): annotate an error with an origin package.

    • when to use: at package boundaries.
    • what it does: captures the identity of the error domain. Can be asserted with errors.EnsureNotInDomain(), errors.NotInDomain().
    • how to access the detail: format with %+v, Sentry report.
  • WithAssertionFailure(): annotate an error as being an assertion failure.

    • when to use: probably never. Use errors.AssertionFailedf() and variants.
    • what it does: wraps the error with a special type. Triggers an auto-generated hint.
    • how to access the detail: IsAssertionFailure()/HasAssertionFailure(), errors.GetAllHints(), errors.FlattenHints(), format with %+v, Sentry report.
  • WithContextTags(): annotate an error with the k/v pairs attached to a context.Context instance with the logtags package.

    • when to use: when capturing/producing an error and a context.Context is available.
    • what it does: it captures the logtags.Buffer object in the wrapper.
    • how to access the detail: errors.GetContextTags(), format with %+v, Sentry reports.

Error composition (summary)

Constructor Composes
New NewWithDepth (see below)
Errorf = Newf
Newf NewWithDepthf (see below)
WithMessage = pkgErr.WithMessage
Wrap WrapWithDepth (see below)
Wrapf WrapWithDepthf (see below)
AssertionFailed AssertionFailedWithDepthf (see below)
NewWithDepth goErr.New + WithStackDepth (see below)
NewWithDepthf fmt.Errorf + WithSafeDetails + WithStackDepth
WithMessagef pkgErr.WithMessagef + WithSafeDetails
WrapWithDepth WithMessage + WithStackDepth
WrapWithDepthf WithMessage + WithStackDepth + WithSafeDetails
AssertionFailedWithDepthf fmt.Errorf + WithStackDepth + WithSafeDetails + WithAssertionFailure
NewAssertionErrorWithWrappedErrf HandledWithMessagef (barrier) + WithStackDepth + WithSafeDetails + WithAssertionFailure

API (not constructing error objects)

// Access causes.
func UnwrapAll(err error) error
func UnwrapOnce(err error) error
func Cause(err error) error // compatibility
func Unwrap(err error) error // compatibility
type Wrapper interface { ... } // compatibility

// Identify errors.
func Is(err, reference error) bool
func IsAny(err error, references ...error) bool
func If(err error, pred func(err error) (interface{}, bool)) (interface{}, bool)

// Encode/decode errors.
type EncodedError // this is protobuf-encodable
func EncodeError(ctx context.Context, err error) EncodedError
func DecodeError(ctx context.Context, enc EncodedError) error

// Register encode/decode functions for custom/new error types.
func RegisterLeafDecoder(typeName TypeKey, decoder LeafDecoder)
func RegisterLeafEncoder(typeName TypeKey, encoder LeafEncoder)
func RegisterWrapperDecoder(typeName TypeKey, decoder WrapperDecoder)
func RegisterWrapperEncoder(typeName TypeKey, encoder WrapperEncoder)
type LeafEncoder = func(ctx context.Context, err error) (msg string, safeDetails []string, payload proto.Message)
type LeafDecoder = func(ctx context.Context, msg string, safeDetails []string, payload proto.Message) error
type WrapperEncoder = func(ctx context.Context, err error) (msgPrefix string, safeDetails []string, payload proto.Message)
type WrapperDecoder = func(ctx context.Context, cause error, msgPrefix string, safeDetails []string, payload proto.Message) error

// Sentry reports.
func BuildSentryReport(err error) (string, []raven.Interface, map[string]interface{})
func ReportError(err error) (string, error)

// Stack trace captures.
func GetOneLineSource(err error) (file string, line int, fn string, ok bool)
type ReportableStackTrace = raven.StackTrace
func GetReportableStackTrace(err error) *ReportableStackTrace

// Safe (PII-free) details.
type SafeDetailPayload struct { ... }
func GetAllSafeDetails(err error) []SafeDetailPayload
func GetSafeDetails(err error) (payload SafeDetailPayload)
type SafeMessager interface { ... }
func Safe(v interface{}) SafeMessager
func Redact(r interface{}) string

// Assertion failures.
func HasAssertionFailure(err error) bool
func IsAssertionFailure(err error) bool

// User-facing details and hints.
func GetAllDetails(err error) []string
func FlattenDetails(err error) string
func GetAllHints(err error) []string
func FlattenHints(err error) string

// Issue links / URL wrappers.
func HasIssueLink(err error) bool
func IsIssueLink(err error) bool
func GetAllIssueLinks(err error) (issues []IssueLink)

// Unimplemented errors.
func HasUnimplementedError(err error) bool
func IsUnimplementedError(err error) bool

// Telemetry keys.
func GetTelemetryKeys(err error) []string

// Domain errors.
type Domain
const NoDomain Domain
func GetDomain(err error) Domain
func NamedDomain(domainName string) Domain
func PackageDomain() Domain
func PackageDomainAtDepth(depth int) Domain
func EnsureNotInDomain(err error, constructor DomainOverrideFn, forbiddenDomains ...Domain) error
func NotInDomain(err error, doms ...Domain) bool

// Context tags.
func GetContextTags(err error) []*logtags.Buffer

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AssertionFailedWithDepthf

func AssertionFailedWithDepthf(depth int, format string, args ...interface{}) error

AssertionFailedWithDepthf forwards a definition.

func AssertionFailedf

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

AssertionFailedf forwards a definition.

func BuildSentryReport

func BuildSentryReport(err error) (string, []raven.Interface, map[string]interface{})

BuildSentryReport forwards a definition.

func Cause

func Cause(err error) error

Cause is provided for compatibility with github.com/pkg/errors.

func CombineErrors added in v1.1.1

func CombineErrors(err, otherErr error) error

CombineErrors forwards a definition.

func DecodeError

func DecodeError(ctx context.Context, enc EncodedError) error

DecodeError forwards a definition.

func EnsureNotInDomain

func EnsureNotInDomain(err error, constructor DomainOverrideFn, forbiddenDomains ...Domain) error

EnsureNotInDomain forwards a definition.

func Errorf

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

Errorf forwards a definition.

func FlattenDetails

func FlattenDetails(err error) string

FlattenDetails forwards a definition.

func FlattenHints

func FlattenHints(err error) string

FlattenHints forwards a definition.

func GetAllDetails

func GetAllDetails(err error) []string

GetAllDetails forwards a definition.

func GetAllHints

func GetAllHints(err error) []string

GetAllHints forwards a definition.

func GetContextTags added in v1.1.1

func GetContextTags(err error) []*logtags.Buffer

GetContextTags forwards a definition.

func GetOneLineSource

func GetOneLineSource(err error) (file string, line int, fn string, ok bool)

GetOneLineSource forwards a definition.

func GetTelemetryKeys

func GetTelemetryKeys(err error) []string

GetTelemetryKeys forwards a definition.

func Handled

func Handled(err error) error

Handled forwards a definition.

func HandledInDomain

func HandledInDomain(err error, domain Domain) error

HandledInDomain forwards a definition.

func HandledInDomainWithMessage

func HandledInDomainWithMessage(err error, domain Domain, msg string) error

HandledInDomainWithMessage forwards a definition.

func HandledWithMessage

func HandledWithMessage(err error, msg string) error

HandledWithMessage forwards a definition.

func HasAssertionFailure

func HasAssertionFailure(err error) bool

HasAssertionFailure forwards a definition.

func HasIssueLink(err error) bool

HasIssueLink forwards a definition.

func HasUnimplementedError

func HasUnimplementedError(err error) bool

HasUnimplementedError forwards a definition.

func If

func If(err error, pred func(err error) (interface{}, bool)) (interface{}, bool)

If forwards a definition.

func Is

func Is(err, reference error) bool

Is forwards a definition.

func IsAny

func IsAny(err error, references ...error) bool

IsAny forwards a definition.

func IsAssertionFailure

func IsAssertionFailure(err error) bool

IsAssertionFailure forwards a definition.

func IsIssueLink(err error) bool

IsIssueLink forwards a definition.

func IsUnimplementedError

func IsUnimplementedError(err error) bool

IsUnimplementedError forwards a definition.

func Mark

func Mark(err error, reference error) error

Mark forwards a definition.

func New

func New(msg string) error

New forwards a definition.

func NewAssertionErrorWithWrappedErrf

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

NewAssertionErrorWithWrappedErrf forwards a definition.

func NewWithDepth

func NewWithDepth(depth int, msg string) error

NewWithDepth forwards a definition.

func NewWithDepthf

func NewWithDepthf(depth int, format string, args ...interface{}) error

NewWithDepthf forwards a definition.

func Newf

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

Newf forwards a definition.

func NotInDomain

func NotInDomain(err error, doms ...Domain) bool

NotInDomain forwards a definition.

func Opaque added in v1.1.1

func Opaque(err error) error

Opaque is provided for compatibility with xerrors.

func Redact

func Redact(r interface{}) string

Redact returns a redacted version of the supplied item that is safe to use in anonymized reporting.

func RegisterLeafDecoder

func RegisterLeafDecoder(typeName TypeKey, decoder LeafDecoder)

RegisterLeafDecoder forwards a definition.

func RegisterLeafEncoder

func RegisterLeafEncoder(typeName TypeKey, encoder LeafEncoder)

RegisterLeafEncoder forwards a definition.

func RegisterWrapperDecoder

func RegisterWrapperDecoder(typeName TypeKey, decoder WrapperDecoder)

RegisterWrapperDecoder forwards a definition.

func RegisterWrapperEncoder

func RegisterWrapperEncoder(typeName TypeKey, encoder WrapperEncoder)

RegisterWrapperEncoder forwards a definition.

func ReportError

func ReportError(err error) (string, error)

ReportError forwards a definition.

func UnimplementedError

func UnimplementedError(issueLink IssueLink, msg string) error

UnimplementedError forwards a definition.

func UnimplementedErrorf

func UnimplementedErrorf(issueLink IssueLink, format string, args ...interface{}) error

UnimplementedErrorf forwards a definition.

func Unwrap added in v1.1.1

func Unwrap(err error) error

Unwrap is provided for compatibility with xerrors.

func UnwrapAll

func UnwrapAll(err error) error

UnwrapAll forwards a definition.

func UnwrapOnce

func UnwrapOnce(err error) error

UnwrapOnce forwards a definition.

func WithAssertionFailure

func WithAssertionFailure(err error) error

WithAssertionFailure forwards a definition.

func WithContextTags added in v1.1.1

func WithContextTags(err error, ctx context.Context) error

WithContextTags forwards a definition.

func WithDetail

func WithDetail(err error, msg string) error

WithDetail forwards a definition.

func WithDetailf

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

WithDetailf forwards a definition.

func WithDomain

func WithDomain(err error, domain Domain) error

WithDomain forwards a definition.

func WithHint

func WithHint(err error, msg string) error

WithHint forwards a definition.

func WithHintf

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

WithHintf forwards a definition.

func WithIssueLink(err error, issue IssueLink) error

WithIssueLink forwards a definition.

func WithMessage

func WithMessage(err error, msg string) error

WithMessage forwards a definition.

func WithMessagef

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

WithMessagef forwards a definition.

func WithSafeDetails

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

WithSafeDetails forwards a definition.

func WithSecondaryError

func WithSecondaryError(err error, additionalErr error) error

WithSecondaryError forwards a definition.

func WithStack

func WithStack(err error) error

WithStack forwards a definition.

func WithStackDepth

func WithStackDepth(err error, depth int) error

WithStackDepth forwards a definition.

func WithTelemetry

func WithTelemetry(err error, keys ...string) error

WithTelemetry forwards a definition.

func Wrap

func Wrap(err error, msg string) error

Wrap forwards a definition.

func WrapWithDepth

func WrapWithDepth(depth int, err error, msg string) error

WrapWithDepth forwards a definition.

func WrapWithDepthf

func WrapWithDepthf(depth int, err error, format string, args ...interface{}) error

WrapWithDepthf forwards a definition.

func Wrapf

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

Wrapf forwards a definition.

Types

type Domain

type Domain = domains.Domain

Domain forwards a definition.

const NoDomain Domain = domains.NoDomain

NoDomain forwards a definition.

func GetDomain

func GetDomain(err error) Domain

GetDomain forwards a definition.

func NamedDomain

func NamedDomain(domainName string) Domain

NamedDomain forwards a definition.

func PackageDomain

func PackageDomain() Domain

PackageDomain forwards a definition.

func PackageDomainAtDepth

func PackageDomainAtDepth(depth int) Domain

PackageDomainAtDepth forwards a definition.

type DomainOverrideFn

type DomainOverrideFn = func(originalDomain Domain, err error) error

DomainOverrideFn forwards a definition.

type EncodedError

type EncodedError = errbase.EncodedError

EncodedError forwards a definition.

func EncodeError

func EncodeError(ctx context.Context, err error) EncodedError

EncodeError forwards a definition.

type IssueLink = issuelink.IssueLink

IssueLink forwards a definition.

func GetAllIssueLinks(err error) (issues []IssueLink)

GetAllIssueLinks forwards a definition.

type LeafDecoder

type LeafDecoder = errbase.LeafDecoder

LeafDecoder forwards a definition.

type LeafEncoder

type LeafEncoder = errbase.LeafEncoder

LeafEncoder forwards a definition.

type ReportableStackTrace

type ReportableStackTrace = withstack.ReportableStackTrace

ReportableStackTrace forwards a definition.

func GetReportableStackTrace

func GetReportableStackTrace(err error) *ReportableStackTrace

GetReportableStackTrace forwards a definition.

type SafeDetailPayload

type SafeDetailPayload = errbase.SafeDetailPayload

SafeDetailPayload forwards a definition.

func GetAllSafeDetails

func GetAllSafeDetails(err error) []SafeDetailPayload

GetAllSafeDetails forwards a definition.

func GetSafeDetails

func GetSafeDetails(err error) (payload SafeDetailPayload)

GetSafeDetails forwards a definition.

type SafeDetailer

type SafeDetailer = errbase.SafeDetailer

SafeDetailer forwards a definition.

type SafeMessager

type SafeMessager = safedetails.SafeMessager

SafeMessager forwards a definition.

func Safe

func Safe(v interface{}) SafeMessager

Safe forwards a definition.

type TypeKey

type TypeKey = errbase.TypeKey

TypeKey forwards a definition.

type Wrapper added in v1.1.1

type Wrapper interface {
	Unwrap() error
}

Wrapper is provided for compatibility with xerrors.

type WrapperDecoder

type WrapperDecoder = errbase.WrapperDecoder

WrapperDecoder forwards a definition.

type WrapperEncoder

type WrapperEncoder = errbase.WrapperEncoder

WrapperEncoder forwards a definition.

Directories

Path Synopsis
Package errutil combines primitives from the library, the Go errors package and github.com/pkg/errors.
Package errutil combines primitives from the library, the Go errors package and github.com/pkg/errors.

Jump to

Keyboard shortcuts

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