e

package module
v0.0.0-...-6c20ecc Latest Latest
Warning

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

Go to latest
Published: May 19, 2022 License: Apache-2.0 Imports: 27 Imported by: 2

README

e - opinionated Go errors

This has been in production for several years at Nozzle, with millions of errors pushed through it. This is a copy from our internal monorepo package. For now, we don't plan to use this package directly, but if there is interest and an appetite for public use, we're open to collaboration.

Expected Usage

Google Slides presentation

Future Work

  • remove hardcoded Nozzle use cases
  • make stack trace truncation / frame skipping configurable
  • make error log printout + repo base url configurable
  • make frame class assignment configurable
  • add a context labeling interface to add user id, trace id, etc
  • make error reporters pluggable vs hardcoding Sentry and Google Error Reporting

Benchmarks

The initial wrap is heavy due to the stacktrace/memstats collection, parsing, and allocation, while subsequent operations are much lighter. There hasn't been much focus on performance, so there is likely some low-hanging fruit.

cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
BenchmarkInitialWrap
BenchmarkInitialWrap-16               	    720	   1451582 ns/op  420843 B/op    9061 allocs/op
BenchmarkAlreadyWrappedNoOpts
BenchmarkAlreadyWrappedNoOpts-16      275561215	     4.321 ns/op       0 B/op       0 allocs/op
BenchmarkAlreadyWrappedWithVars
BenchmarkAlreadyWrappedWithVars-16       666651	      1529 ns/op     540 B/op       6 allocs/op

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Cause

func Cause(rawErr error) error

Cause returns the root cause of the error without the extra wrapped data. Supports our own errors, Dave Cheney's pkg/errors, and anything that implements either the Cause() error or Unwrap() error interface.

func CodeFromError

func CodeFromError(err error) codes.Code

CodeFromError returns the error code from an error if there is one. Returns OK if err is nil and Unknown if it isn't a wrapped error.

func CodeFromHTTPStatus

func CodeFromHTTPStatus(statusCode int) codes.Code

CodeFromHTTPStatus does the inverse of HTTPStatusFromCode. It's a lossy conversion as there isn't a 1 to 1 mapping

func Flush

func Flush(c context.Context)

Flush sends all buffered errors to servers before returning. Should always be called before program exit to ensure no lost errors.

func Location

func Location(rawErr error) (string, string, int)

Location returns the path/file/line where the first New/Wrap happened

func MutatorFromError

func MutatorFromError(err error) tag.Mutator

MutatorFromError keeps a package global map of error strings, capped at maxErrorMutators (10) to prevent unbounded cardinality, and has one of three outcomes: 1. returns an already created mutator from the map 2. returns an "other" mutator if the map is full 3. returns a newly created mutator and stores it in the map

func NewErrForbiddenArg

func NewErrForbiddenArg(c context.Context, fields ...string) error

NewErrForbiddenArg creates an error with not allowed fields

func NewErrInvalidArg

func NewErrInvalidArg(c context.Context, fields ...string) error

NewErrInvalidArg will return an error with an invalid field and why it was invalid

func NewErrRequiredArg

func NewErrRequiredArg(c context.Context, fields ...string) error

NewErrRequiredArg will build a structured error with errdetails

func Recover

func Recover(c context.Context, opts ...RecoverOption)

Recover is intended to be used for recovering from panics. Should only be temporary when looking for panics, shouldn't be used long-term in production This must be used directly as the panic function so it cannot return an error defer e.Recover(c)

func SetSentryClient

func SetSentryClient(c context.Context, cl *sentry.Client)

SetSentryClient stores a global reference to a sentry client. Should only be called once at app startup.

func SetSentryCriticalClient

func SetSentryCriticalClient(c context.Context, cl *sentry.Client)

SetSentryCriticalClient stores a global reference to a sentry client used only for critical errors. Should only be called once at app startup.

func SetSentryInfraClient

func SetSentryInfraClient(c context.Context, cl *sentry.Client)

SetSentryInfraClient stores a global reference to a sentry client used only for infrastructure errors. Should only be called once at app startup.

func SetStackdriverErrorReportingClient

func SetStackdriverErrorReportingClient(c context.Context, cl *er.Client) error

SetStackdriverErrorReportingClient enables reporting to GCP. Should only be called once at app startup.

func StatusToError

func StatusToError(c context.Context, st *status.Status) error

StatusToError converts a status to a nozzle Err.

Types

type Err

type Err struct {

	// contextual data set from WrapOptions
	Level Level
	// contains filtered or unexported fields
}

Err defines an error with an optional stacktrace and contextual data

func New

func New(s string, opts ...WrapOption) *Err

New returns an initialized *Err with the provided string

func Wrap

func Wrap(err error, opts ...WrapOption) *Err

Wrap adds context to the provided error

func (*Err) Code

func (err *Err) Code() codes.Code

Code returns the error code

func (*Err) Details

func (err *Err) Details() []proto.Message

Details returns a slice of google.golang.org/genproto/googleapis/rpc/errdetails set on an Err.

func (*Err) Error

func (err *Err) Error() string

Error fulfills the error interface

func (*Err) GRPCStatus

func (err *Err) GRPCStatus() *status.Status

GRPCStatus converts the error into a grpc compatible status

func (*Err) IsRetriable

func (err *Err) IsRetriable() bool

IsRetriable returns whether or not a retry might succeed

func (*Err) Report

func (err *Err) Report(c context.Context, opts ...ReportOption)

Report ships your error when you aren't returning through a handler

func (*Err) String

func (err *Err) String() string

String fulfills the Stringer interface

func (*Err) Unwrap

func (err *Err) Unwrap() error

Unwrap fulfills the stdlib Unwrap interface

type ErrCode

type ErrCode interface {
	ErrCode() codes.Code
}

ErrCode sets the error code, overriding any existing code

type ErrInfra

type ErrInfra interface {
	ErrIsInfra() bool
}

ErrInfra determines whether an error is infrastructure related

type ErrLevel

type ErrLevel interface {
	ErrLevel() Level
}

ErrLevel sets the error level, adding a var if the level is invalid

type ErrMsg

type ErrMsg interface {
	ErrMsg() string
}

ErrMsg sets the error message, overriding any existing message

type ErrReportable

type ErrReportable interface {
	ErrShouldReport() bool
}

ErrReportable sets whether the error should be reported

type ErrRetriable

type ErrRetriable interface {
	ErrRetriable() bool
}

ErrRetriable determines if the error is retriable

type ErrTags

type ErrTags interface {
	ErrTags() map[string]string
}

ErrTags adds all the returned tags, overriding any existing keys

type ErrVars

type ErrVars interface {
	ErrVars() map[string]interface{}
}

ErrVars adds all the returned vars to the current stack frame, overriding any existing keys

type Level

type Level int

Level represents an error severity level

const (
	// LevelCritical = 1
	LevelCritical Level = 1
	// LevelError = 1
	LevelError Level = 2
	// LevelWarning = 1
	LevelWarning Level = 3
)

type RecoverOption

type RecoverOption func(c context.Context, rd *recoverData)

RecoverOption lets you add additional context to a panic handler

func RecoverFunc

func RecoverFunc(fn func(c context.Context, err *Err)) RecoverOption

RecoverFunc runs before returning / propagating the panic This function provides access to the error created from the panic, save it if you want to use or return it

func RecoverNoLog

func RecoverNoLog() RecoverOption

RecoverNoLog doesn't log the panic

func RecoverNoPanic

func RecoverNoPanic() RecoverOption

RecoverNoPanic doesn't propagate the panic

func RecoverNoReport

func RecoverNoReport() RecoverOption

RecoverNoReport doesn't report the panic

type ReportOption

type ReportOption func(err *Err)

A ReportOption let you determine report behavior

func ReportIsHandler

func ReportIsHandler() ReportOption

ReportIsHandler sets the report as having come via a system handler Should not be set outside pkg

func ReportWithSentryClient

func ReportWithSentryClient(cl *sentry.Client) ReportOption

ReportWithSentryClient reports the error with a custom Sentry client

func Wait

func Wait() ReportOption

Wait forces your process to wait synchronously until the report is sent, instead of queuing and asynchronously reporting which is the default behavior

type WrapOption

type WrapOption func(err *Err)

WrapOption lets you add context

func Code

func Code(code codes.Code) WrapOption

Code sets the error code. This is only set once per error, so if called multiple times, the last call persists. Panics if an invalid code is given.

func Critical

func Critical() WrapOption

Critical sets the importance of the error, overwriting the previous level

func Error

func Error() WrapOption

Error sets the importance of the error, overwriting the previous level

func FieldViolation

func FieldViolation(field, description string) WrapOption

FieldViolation adds a error details for a field violation.

func Infra

func Infra() WrapOption

Infra designates an error specifically as infrastructure related, not app related

func Msg

func Msg(msg string) WrapOption

Msg lets you assign a message to the error

func NoReport

func NoReport() WrapOption

NoReport denotes that this error should not be reported to Sentry

func NotRetriable

func NotRetriable() WrapOption

NotRetriable denotes that this error should be retried

func Override

func Override(overrideErr error) WrapOption

Override lets you override the rootErr with a new error

func SkipFrames

func SkipFrames(skipFrames int) WrapOption

SkipFrames works like runtime.Caller, where the top N frames aren't included in the stack trace. This should rarely be used, except for in cases where we are normalizing errors, but don't want all stacks to originate from a single line. All WrapOptions will be merged into the new top of the stack var, so that they aren't lost. If skipFrames is > 1, any WrapOptions in between the first wrap will be applied to an unknown frame, since when they execute, that frame will already have been removed. If you really need to skip multiple frames, you should pass those options up to the primary wrap site.

func Stack

func Stack(stack []byte) WrapOption

Stack lets you provide a stacktrace as opposed to capturing it internally

func Tag

func Tag(key, val string) WrapOption

Tag adds a tag to the error. It will overwrite previous tags with the same key. This is error scoped, not frame scoped.

func Warning

func Warning() WrapOption

Warning sets the importance of the error, overwriting the previous level

func With

func With(k string, v interface{}) WrapOption

With lets you attach a variable

Jump to

Keyboard shortcuts

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