Documentation
¶
Overview ¶
Package merry adds context to errors, including automatic stack capture, cause chains, HTTP status code, user messages, and arbitrary values.
Wrapped errors work a lot like google's golang.org/x/net/context package: each wrapper error contains the inner error, a key, and a value. Like contexts, errors are immutable: adding a key/value to an error always creates a new error which wraps the original.
This package comes with built-in support for adding information to errors:
* stacktraces * changing the error message * HTTP status codes * End user error messages * causes
You can also add your own additional information.
The stack capturing feature can be turned off for better performance, though it's pretty fast. Benchmarks on an 2017 MacBook Pro, with go 1.10:
BenchmarkNew_withStackCapture-8 2000000 749 ns/op BenchmarkNew_withoutStackCapture-8 20000000 64.1 ns/op
Usage ¶
This package contains functions for creating errors, or wrapping existing errors. To create:
err := New("boom!") err := Errorf("error fetching %s", filename)
Additional context information can be attached to errors using functional options, called Wrappers:
err := New("record not found", WithHTTPCode(404))
Errorf() also accepts wrappers, mixed in with the format args:
err := Errorf("user %s not found", username, WithHTTPCode(404))
Wrappers can be applied to existing errors with Wrap():
err = Wrap(err, WithHTTPCode(404))
Wrap() will add a stacktrace to any error which doesn't already have one attached. WrapSkipping() can be used to control where the stacktrace starts.
This package contains wrappers for adding specific context information to errors, such as an HTTPCode. You can create your own wrappers using the primitive Value(), WithValue(), and Set() functions.
Errors produced by this package implement fmt.Formatter, to print additional information about the error:
fmt.Printf("%v", err) // print error message and causes fmt.Printf("%s", err) // same as %s fmt.Printf("%q", err) // same as fmt.Printf("%q", err.Error()) fmt.Printf("%v+", err) // print Details(err)
Details() prints the error message, all causes, the stacktrace, and additional error values configured with RegisterDetailFunc(). By default, it will show the HTTP status code and user message.
Stacktraces ¶
By default, any error created by or wrapped by this package will automatically have a stacktrace captured and attached to the error. This capture only happens if the error doesn't already have a stack attached to it, so wrapping the error with additional context won't capture additional stacks.
When and how stacks are captured can be customized. SetMaxStackDepth() can globally configure how many frames to capture. SetStackCaptureEnabled() can globally configure whether stacks are captured by default.
Wrap(err, NoStackCapture()) can be used to selectively suppress stack capture for a particular error.
Wrap(err, CaptureStack(false)) will capture a new stack at the Wrap call site, even if the err already had an earlier stack attached. The new stack overrides the older stack.
Wrap(err, CaptureStack(true)) will force a stack capture at the call site even if stack capture is disabled globally.
Finally, Wrappers are passed a depth argument so they know how deep they are in the call stack from the call site where this package's API was called. This allows Wrappers to implement their own stack capturing logic.
The package contains functions for creating new errors with stacks, or adding a stack to `error` instances. Functions with add context (e.g. `WithValue()`) work on any `error`, and will automatically convert them to merry errors (with a stack) if necessary.
Hooks ¶
AddHooks() can install wrappers which are applied to all errors processed by this package. Hooks are applied before any other wrappers or processing takes place. They can be used to integrate with errors from other packages, normalizing errors (such as applying standard status codes to application errors), localizing user messages, or replacing the stack capturing mechanism.
Index ¶
- func AddHooks(hook ...Wrapper)
- func AddOnceHooks(hook ...Wrapper)
- func Append(err error, msg string, wrappers ...Wrapper) error
- func Appendf(err error, format string, args ...interface{}) error
- func Apply(err error, wrappers ...Wrapper) error
- func ApplySkipping(err error, skip int, wrappers ...Wrapper) error
- func Cause(err error) error
- func ClearHooks()
- func Details(e error) string
- func Errorf(format string, args ...interface{}) error
- func Format(s fmt.State, verb rune, err error)
- func FormattedStack(err error) []string
- func HTTPCode(err error) int
- func HasStack(err error) bool
- func Location(err error) (file string, line int)
- func Lookup(err error, key interface{}) (interface{}, bool)
- func MaxStackDepth() int
- func New(msg string, wrappers ...Wrapper) error
- func Prepend(err error, msg string, wrappers ...Wrapper) error
- func Prependf(err error, format string, args ...interface{}) error
- func RegisterDetail(label string, key interface{})
- func RegisterDetailFunc(label string, f func(err error) interface{})
- func RegisteredDetails(err error) map[string]interface{}
- func Sentinel(msg string, wrappers ...Wrapper) error
- func Sentinelf(format string, args ...interface{}) error
- func Set(err error, key, value interface{}) error
- func SetMaxStackDepth(depth int)
- func SetStackCaptureEnabled(enabled bool)
- func SourceLine(err error) string
- func Stack(err error) []uintptr
- func StackCaptureEnabled() bool
- func Stacktrace(err error) string
- func UserMessage(err error) string
- func Value(err error, key interface{}) interface{}
- func Values(err error) map[interface{}]interface{}
- func Wrap(err error, wrappers ...Wrapper) error
- func WrapSkipping(err error, skip int, wrappers ...Wrapper) error
- type Wrapper
- func AppendMessage(msg string) Wrapper
- func AppendMessagef(format string, args ...interface{}) Wrapper
- func CaptureStack(force bool) Wrapper
- func NoCaptureStack() Wrapper
- func PrependMessage(msg string) Wrapper
- func PrependMessagef(format string, args ...interface{}) Wrapper
- func WithCause(err error) Wrapper
- func WithFormattedStack(stack []string) Wrapper
- func WithHTTPCode(statusCode int) Wrapper
- func WithMessage(msg string) Wrapper
- func WithMessagef(format string, args ...interface{}) Wrapper
- func WithStack(stack []uintptr) Wrapper
- func WithUserMessage(msg string) Wrapper
- func WithUserMessagef(format string, args ...interface{}) Wrapper
- func WithValue(key, value interface{}) Wrapper
- type WrapperFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AddHooks ¶
func AddHooks(hook ...Wrapper)
AddHooks installs a global set of Wrappers which are applied to every error processed by this package. They are applied before any other Wrappers or stack capturing are applied. Hooks can add additional wrappers to errors, or translate annotations added by other error libraries into merry annotations.
Note that these hooks will be applied each time an err is passed to Wrap/Apply. If you only want your hook to run once per error, see AddOnceHooks.
This function is not thread safe, and should only be called very early in program initialization.
func AddOnceHooks ¶
func AddOnceHooks(hook ...Wrapper)
AddOnceHooks is like AddHooks, but these hooks will only be applied once per error. Once hooks are applied to an error, the error is marked, and future Wrap/Apply calls on the error will not apply these hooks again.
This function is not thread safe, and should only be called very early in program initialization.
func Append ¶
Append is a convenience function for the AppendMessage wrapper. It eases migration from merry v1. It accepts a varargs of additional Wrappers.
func Appendf ¶
Appendf is a convenience function for the AppendMessagef wrapper. It eases migration from merry v1. The args can be format arguments mixed with Wrappers.
func Apply ¶
Apply is like Wrap, but does not execute hooks or do automatic stack capture. It just applies the wrappers to the error.
func ApplySkipping ¶
ApplySkipping is like WrapSkipping, but does not execute hooks or do automatic stack capture. It just applies the wrappers to the error. It is useful in Wrapper implementations which // want to apply other Wrappers without starting an infinite recursion.
func Cause ¶
Cause returns the cause of the argument. If e is nil, or has no cause, nil is returned.
func ClearHooks ¶
func ClearHooks()
ClearHooks removes all installed hooks.
This function is not thread safe, and should only be called very early in program initialization.
func Details ¶
Details returns e.Error(), e's stacktrace, and any additional details which have be registered with RegisterDetail. User message and HTTP code are already registered.
The details of each error in e's cause chain will also be printed.
func Errorf ¶
Errorf creates a new error with a formatted message and a stack. The equivalent of golang's fmt.Errorf(). args may contain either arguments to format, or Wrapper options, which will be applied to the error.
func Format ¶
Format adapts errors to fmt.Formatter interface. It's intended to be used help error impls implement fmt.Formatter, e.g.:
func (e *myErr) Format(f fmt.State, verb rune) { Format(f, verb, e) }
func FormattedStack ¶
FormattedStack returns the stack attached to an error, formatted as a slice of strings. Each string represents a frame in the stack, newest first. The strings may have internal newlines.
Returns nil if no formatted stack and no stack is associated, or err is nil.
func HTTPCode ¶
HTTPCode converts an error to an http status code. All errors map to 500, unless the error has an http code attached. If e is nil, returns 200.
func HasStack ¶
HasStack returns true if a stack is already attached to the err. If err == nil, returns false.
If a stack capture was suppressed with NoCaptureStack(), this will still return true, indicating that stack capture processing has already occurred on this error.
func Lookup ¶
Lookup returns the value for the key, and a boolean indicating whether the value was set. Will not search causes.
if err is nil, returns nil and false.
func MaxStackDepth ¶
func MaxStackDepth() int
MaxStackDepth returns the number of frames captured in stacks.
func Prepend ¶
Prepend is a convenience function for the PrependMessage wrapper. It eases migration from merry v1. It accepts a varargs of additional Wrappers.
func Prependf ¶
Prependf is a convenience function for the PrependMessagef wrapper. It eases migration from merry v1. The args can be format arguments mixed with Wrappers.
func RegisterDetail ¶
func RegisterDetail(label string, key interface{})
RegisterDetail registers an error property key in a global registry, with a label. See RegisterDetailFunc. This function just wraps a call to Value(key) and passes it to RegisterDetailFunc.
func RegisterDetailFunc ¶
RegisterDetailFunc registers a label and a function for extracting a value from an error. When formatting errors produced by this package using the `%+v` placeholder, or when using Details(), these functions will be called on the error, and any non-nil values will be added to the text. For example:
err := New("boom") err = err.WithValue(colorKey, "red") fmt.Println(Details(err)) // Output: // boom // // <stacktrace> func Color(err) string { s, _ := Value(err, colorKey) return s } RegisterDetailFunc("color", Color) fmt.Println(Details(err)) // Output: // boom // color: red // // <stacktrace>
Error property keys are typically not exported by the packages which define them. Packages instead export functions which let callers access that property. It's therefore up to the package to register those properties which would make sense to include in the Details() output. In other words, it's up to the author of the package which generates the errors to publish printable error details, not the callers of the package.
func RegisteredDetails ¶
RegisteredDetails extracts details registered with RegisterDetailFunc from an error, and returns them as a map. Values may be nil.
If err is nil or there are no registered details, nil is returned.
func Sentinel ¶
Sentinel creates an error without running hooks or capturing a stack. It is intended to create sentinel errors, which will be wrapped with a stack later from where the error is returned. At that time, a stack will be captured and hooks will be run.
var ErrNotFound = merry.Sentinel("not found", merry.WithHTTPCode(404)) func FindUser(name string) (*User, error) { // some db code which fails to find a user return nil, merry.Wrap(ErrNotFound) } func main() { _, err := FindUser("bob") fmt.Println(errors.Is(err, ErrNotFound) // "true" fmt.Println(merry.Details(err)) // stacktrace will start at the return statement // in FindUser() }
func Sentinelf ¶
Sentinelf is like Sentinel, but takes a formatted message. args can be a mix of format arguments and Wrappers.
func Set ¶
Set wraps an error with a key/value pair. This is the simplest form of associating a value with an error. It does not capture a stacktrace, invoke hooks, or do any other processing. It is mainly intended as a primitive for writing Wrapper implementations.
if err is nil, returns nil.
func SetStackCaptureEnabled ¶
func SetStackCaptureEnabled(enabled bool)
SetStackCaptureEnabled sets stack capturing globally. Disabling stack capture can increase performance. Capture can be forced or suppressed to override this global setting on a particular error.
func SourceLine ¶
SourceLine returns the string representation of Location's result or an empty string if there's no stracktrace.
func Stack ¶
Stack returns the stack attached to an error, or nil if one is not attached If e is nil, returns nil.
func StackCaptureEnabled ¶
func StackCaptureEnabled() bool
StackCaptureEnabled returns whether stack capturing is enabled.
func Stacktrace ¶
Stacktrace returns the error's stacktrace as a string formatted. If e has no stacktrace, returns an empty string.
func UserMessage ¶
UserMessage returns the end-user safe message. Returns empty if not set. If e is nil, returns "".
func Value ¶
func Value(err error, key interface{}) interface{}
Value returns the value for key, or nil if not set. If e is nil, returns nil. Will not search causes.
func Values ¶
func Values(err error) map[interface{}]interface{}
Values returns a map of all values attached to the error If a key has been attached multiple times, the map will contain the last value mapped If e is nil, returns nil.
func Wrap ¶
Wrap adds context to errors by applying Wrappers. See WithXXX() functions for Wrappers supplied by this package.
If StackCaptureEnabled is true, a stack starting at the caller will be automatically captured and attached to the error. This behavior can be overridden with wrappers which either capture their own stacks, or suppress auto capture.
If err is nil, returns nil.
Types ¶
type Wrapper ¶
type Wrapper interface { // Wrap returns a new error, wrapping the argument, and typically adding some context information. // skipCallers is how many callers to skip when capturing a stack to skip to the caller of the merry // API surface. It's intended to make it possible to write wrappers which capture stacktraces. e.g. // // func CaptureStack() Wrapper { // return WrapperFunc(func(err error, skipCallers int) error { // s := make([]uintptr, 50) // // Callers // l := runtime.Callers(2+skipCallers, s[:]) // return WithStack(s[:l]).Wrap(err, skipCallers + 1) // }) // } Wrap(err error, skipCallers int) error }
Wrapper knows how to wrap errors with context information.
func AppendMessage ¶
AppendMessage a message after the current error message, in the format "original: new".
func AppendMessagef ¶
AppendMessagef is the same as AppendMessage, but with a formatted message.
func CaptureStack ¶
CaptureStack will override an earlier stack with a stack captured from the current call site. If StackCaptureEnabled() == false, this is a no-op.
If force is set, StackCaptureEnabled() will be ignored: a stack will always be captured.
func NoCaptureStack ¶
func NoCaptureStack() Wrapper
NoCaptureStack will suppress capturing a stack, even if StackCaptureEnabled() == true.
func PrependMessage ¶
PrependMessage a message before the current error message, in the format "new: original".
func PrependMessagef ¶
PrependMessagef is the same as PrependMessage, but with a formatted message.
func WithCause ¶
WithCause sets one error as the cause of another error. This is useful for associating errors from lower API levels with sentinel errors in higher API levels. errors.Is() and errors.As() will traverse both the main chain of error wrappers, and down the chain of causes.
If err is nil, this is a no-op
func WithFormattedStack ¶
WithFormattedStack associates a stack of pre-formatted strings describing frames of a stacktrace. Generally, a formatted stack is generated from the raw []uintptr stack associated with the error, but a pre-formatted stack can be associated with the error instead, and takes precedence over the raw stack. This is useful if pre-formatted stack information is coming from some other source.
func WithHTTPCode ¶
WithHTTPCode associates an HTTP status code with an error.
func WithMessage ¶
WithMessage overrides the value returned by err.Error().
func WithMessagef ¶
WithMessagef overrides the value returned by err.Error().
func WithStack ¶
WithStack associates a stack of caller frames with an error. Generally, this package will automatically capture and associate a stack with errors which are created or wrapped by this package. But this allows the caller to associate an externally generated stack.
func WithUserMessage ¶
WithUserMessage associates an end-user message with an error.
func WithUserMessagef ¶
WithUserMessagef associates a formatted end-user message with an error.
Source Files
¶
Directories
¶
Path | Synopsis |
---|---|
Package status is a drop-in replacement for the google.golang.org/grpc/status package, but is compatible with merry errors.
|
Package status is a drop-in replacement for the google.golang.org/grpc/status package, but is compatible with merry errors. |
Package pkgerrors provides a merry hook to integrate pkg/errors stacktraces with merry.
|
Package pkgerrors provides a merry hook to integrate pkg/errors stacktraces with merry. |