mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
rebase: vendor files required for kmip
Signed-off-by: Rakshith R <rar@redhat.com>
This commit is contained in:
21
vendor/github.com/ansel1/merry/v2/LICENSE
generated
vendored
Normal file
21
vendor/github.com/ansel1/merry/v2/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Russ Egan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
41
vendor/github.com/ansel1/merry/v2/Makefile
generated
vendored
Normal file
41
vendor/github.com/ansel1/merry/v2/Makefile
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
# Expands to list this project's go packages, excluding the vendor folder
|
||||
SHELL = bash
|
||||
|
||||
all: fmt build test lint
|
||||
|
||||
build:
|
||||
go build
|
||||
|
||||
|
||||
lint:
|
||||
golint -set_exit_status ./...
|
||||
|
||||
clean:
|
||||
rm -rf build
|
||||
|
||||
fmt:
|
||||
go fmt ./...
|
||||
|
||||
test:
|
||||
go test ./...
|
||||
|
||||
testall:
|
||||
go test -count 1 ./...
|
||||
|
||||
coverage:
|
||||
@if [ ! -d build ]; then mkdir build; fi
|
||||
# runs go test and generate coverage report
|
||||
go test -covermode=count -coverprofile=build/coverage.out ./...
|
||||
go tool cover -html=build/coverage.out -o build/coverage.html
|
||||
|
||||
bench:
|
||||
go test -bench ./...
|
||||
|
||||
### TOOLS
|
||||
|
||||
tools:
|
||||
go get -u golang.org/x/tools/cmd/cover
|
||||
go get -u golang.org/x/lint/golint
|
||||
|
||||
.PHONY: all build lint clean fmt test coverage tools
|
||||
|
88
vendor/github.com/ansel1/merry/v2/README.md
generated
vendored
Normal file
88
vendor/github.com/ansel1/merry/v2/README.md
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
merry [](https://github.com/ansel1/merry/actions?query=branch%3Amaster+workflow%3ABuild+) [](https://godoc.org/github.com/ansel1/merry/v2) [](https://goreportcard.com/report/github.com/ansel1/merry/v2)
|
||||
=====
|
||||
|
||||
Add context to errors, including automatic stack capture, cause chains, HTTP status code, user
|
||||
messages, and arbitrary values.
|
||||
|
||||
The package is largely based on http://github.com/go-errors/errors, with additional
|
||||
inspiration from https://github.com/go-errgo/errgo and https://github.com/amattn/deeperror.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
go get github.com/ansel1/merry/v2
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
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
|
||||
|
||||
Merry errors are fully compatible with errors.Is, As, and Unwrap.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
To add a stacktrace, a user message, and an HTTP code to an error:
|
||||
|
||||
err = merry.Wrap(err, WithUserMessagef("Username %s not found.", username), WithHTTPCode(404))
|
||||
|
||||
To fetch context information from error:
|
||||
|
||||
userMsg := UserMessage(err)
|
||||
statusCode := HTTPCode(err)
|
||||
stacktrace := Stacktrace(err)
|
||||
|
||||
To print full details of the error:
|
||||
|
||||
log.Printf("%v+", err) // or log.Println(merry.Details(err))
|
||||
|
||||
v1 -> v2
|
||||
--------
|
||||
|
||||
v1 used a fluent API style which proved awkward in some cases. In general, fluent APIs
|
||||
don't work that well in go, because they interfere with how interfaces are typically used to
|
||||
compose with other packages. v2 uses a functional options API style which more easily
|
||||
allows other packages to augment this one.
|
||||
|
||||
This also fixed bad smell with v1's APIs: they mostly returned a big, ugly `merry.Error` interface,
|
||||
instead of plain `error` instances. v2 has a smaller, simpler API, which exclusively uses plain
|
||||
errors.
|
||||
|
||||
v2 also implements a simpler and more robust integration with errors.Is/As/Unwrap. v2's functions will
|
||||
work with error wrapper chains even if those chains contain errors not created with this package, so
|
||||
long as those errors conform to the Unwrap() convention.
|
||||
|
||||
v2 allows more granular control over stacktraces: stack capture can be turned on or off on individual errors,
|
||||
overriding the global setting. External stacktraces can be used as well.
|
||||
|
||||
v1 has been reimplemented in terms of v2, and the versions are completely compatible, and can be mixed.
|
||||
|
||||
Plugs
|
||||
-----
|
||||
|
||||
- Check out my HTTP client library: [github.com/gemalto/requester](https://github.com/gemalto/requester)
|
||||
- Check out my log library: [github.com/gemalto/flume](https://github.com/gemalto/flume)
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
This package is licensed under the MIT license, see LICENSE.MIT for details.
|
88
vendor/github.com/ansel1/merry/v2/config.go
generated
vendored
Normal file
88
vendor/github.com/ansel1/merry/v2/config.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
package merry
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var maxStackDepth = 50
|
||||
var captureStacks = true
|
||||
|
||||
// StackCaptureEnabled returns whether stack capturing is enabled.
|
||||
func StackCaptureEnabled() bool {
|
||||
return captureStacks
|
||||
}
|
||||
|
||||
// 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 SetStackCaptureEnabled(enabled bool) {
|
||||
captureStacks = enabled
|
||||
}
|
||||
|
||||
// MaxStackDepth returns the number of frames captured in stacks.
|
||||
func MaxStackDepth() int {
|
||||
return maxStackDepth
|
||||
}
|
||||
|
||||
// SetMaxStackDepth sets the MaxStackDepth.
|
||||
func SetMaxStackDepth(depth int) {
|
||||
maxStackDepth = depth
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterDetail("User Message", errKeyUserMessage)
|
||||
RegisterDetail("HTTP Code", errKeyHTTPCode)
|
||||
}
|
||||
|
||||
var detailsLock sync.Mutex
|
||||
var detailFields = map[string]func(err error) 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 RegisterDetail(label string, key interface{}) {
|
||||
RegisterDetailFunc(label, func(err error) interface{} {
|
||||
return Value(err, key)
|
||||
})
|
||||
}
|
||||
|
||||
// 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 RegisterDetailFunc(label string, f func(err error) interface{}) {
|
||||
detailsLock.Lock()
|
||||
defer detailsLock.Unlock()
|
||||
|
||||
detailFields[label] = f
|
||||
}
|
97
vendor/github.com/ansel1/merry/v2/doc.go
generated
vendored
Normal file
97
vendor/github.com/ansel1/merry/v2/doc.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// 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.
|
||||
package merry
|
334
vendor/github.com/ansel1/merry/v2/errors.go
generated
vendored
Normal file
334
vendor/github.com/ansel1/merry/v2/errors.go
generated
vendored
Normal file
@ -0,0 +1,334 @@
|
||||
package merry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// New creates a new error, with a stack attached. The equivalent of golang's errors.New()
|
||||
func New(msg string, wrappers ...Wrapper) error {
|
||||
return WrapSkipping(errors.New(msg), 1, wrappers...)
|
||||
}
|
||||
|
||||
// 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 Errorf(format string, args ...interface{}) error {
|
||||
fmtArgs, wrappers := splitWrappers(args)
|
||||
|
||||
return WrapSkipping(fmt.Errorf(format, fmtArgs...), 1, wrappers...)
|
||||
}
|
||||
|
||||
// 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 Sentinel(msg string, wrappers ...Wrapper) error {
|
||||
return ApplySkipping(errors.New(msg), 1, wrappers...)
|
||||
}
|
||||
|
||||
// Sentinelf is like Sentinel, but takes a formatted message. args can be a mix of
|
||||
// format arguments and Wrappers.
|
||||
func Sentinelf(format string, args ...interface{}) error {
|
||||
fmtArgs, wrappers := splitWrappers(args)
|
||||
|
||||
return ApplySkipping(fmt.Errorf(format, fmtArgs...), 1, wrappers...)
|
||||
}
|
||||
|
||||
func splitWrappers(args []interface{}) ([]interface{}, []Wrapper) {
|
||||
var wrappers []Wrapper
|
||||
|
||||
// pull out the args which are wrappers
|
||||
n := 0
|
||||
for _, arg := range args {
|
||||
if w, ok := arg.(Wrapper); ok {
|
||||
wrappers = append(wrappers, w)
|
||||
} else {
|
||||
args[n] = arg
|
||||
n++
|
||||
}
|
||||
}
|
||||
args = args[:n]
|
||||
|
||||
return args, wrappers
|
||||
}
|
||||
|
||||
// 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.
|
||||
func Wrap(err error, wrappers ...Wrapper) error {
|
||||
return WrapSkipping(err, 1, wrappers...)
|
||||
}
|
||||
|
||||
// WrapSkipping is like Wrap, but the captured stacks will start `skip` frames
|
||||
// further up the call stack. If skip is 0, it behaves the same as Wrap.
|
||||
func WrapSkipping(err error, skip int, wrappers ...Wrapper) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(onceHooks) > 0 {
|
||||
if _, ok := Lookup(err, errKeyHooked); !ok {
|
||||
err = ApplySkipping(err, skip+1, onceHooks...)
|
||||
err = ApplySkipping(err, skip+1, WithValue(errKeyHooked, err))
|
||||
}
|
||||
}
|
||||
err = ApplySkipping(err, skip+1, hooks...)
|
||||
err = ApplySkipping(err, skip+1, wrappers...)
|
||||
return captureStack(err, skip+1, false)
|
||||
}
|
||||
|
||||
// Apply is like Wrap, but does not execute hooks or do automatic stack capture. It just
|
||||
// applies the wrappers to the error.
|
||||
func Apply(err error, wrappers ...Wrapper) error {
|
||||
return ApplySkipping(err, 1, wrappers...)
|
||||
}
|
||||
|
||||
// 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 ApplySkipping(err error, skip int, wrappers ...Wrapper) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, w := range wrappers {
|
||||
err = w.Wrap(err, skip+1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Prepend is a convenience function for the PrependMessage wrapper. It eases migration
|
||||
// from merry v1. It accepts a varargs of additional Wrappers.
|
||||
func Prepend(err error, msg string, wrappers ...Wrapper) error {
|
||||
return WrapSkipping(err, 1, append(wrappers, PrependMessage(msg))...)
|
||||
}
|
||||
|
||||
// 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 Prependf(err error, format string, args ...interface{}) error {
|
||||
fmtArgs, wrappers := splitWrappers(args)
|
||||
|
||||
return WrapSkipping(err, 1, append(wrappers, PrependMessagef(format, fmtArgs...))...)
|
||||
}
|
||||
|
||||
// Append is a convenience function for the AppendMessage wrapper. It eases migration
|
||||
// from merry v1. It accepts a varargs of additional Wrappers.
|
||||
func Append(err error, msg string, wrappers ...Wrapper) error {
|
||||
return WrapSkipping(err, 1, append(wrappers, AppendMessage(msg))...)
|
||||
}
|
||||
|
||||
// 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 Appendf(err error, format string, args ...interface{}) error {
|
||||
fmtArgs, wrappers := splitWrappers(args)
|
||||
|
||||
return WrapSkipping(err, 1, append(wrappers, AppendMessagef(format, fmtArgs...))...)
|
||||
}
|
||||
|
||||
// Value returns the value for key, or nil if not set.
|
||||
// If e is nil, returns nil. Will not search causes.
|
||||
func Value(err error, key interface{}) interface{} {
|
||||
v, _ := Lookup(err, key)
|
||||
return v
|
||||
}
|
||||
|
||||
// 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 Lookup(err error, key interface{}) (interface{}, bool) {
|
||||
var merr interface {
|
||||
error
|
||||
isMerryError()
|
||||
}
|
||||
|
||||
// I've tried implementing this logic a few different ways. It's tricky:
|
||||
//
|
||||
// - Lookup should only search the current error, but not causes. errWithCause's
|
||||
// Unwrap() will eventually unwrap to the cause, so we don't want to just
|
||||
// search the entire stream of errors returned by Unwrap.
|
||||
// - We need to handle cases where error implementations created outside
|
||||
// this package are in the middle of the chain. We need to use Unwrap
|
||||
// in these cases to traverse those errors and dig down to the next
|
||||
// merry error.
|
||||
// - Some error packages, including our own, do funky stuff with Unwrap(),
|
||||
// returning shim types to control the unwrapping order, rather than
|
||||
// the actual, raw wrapped error. Typically, these shims implement
|
||||
// Is/As to delegate to the raw error they encapsulate, but implement
|
||||
// Unwrap by encapsulating the raw error in another shim. So if we're looking
|
||||
// for a raw error type, we can't just use Unwrap() and do type assertions
|
||||
// against the result. We have to use errors.As(), to allow the shims to delegate
|
||||
// the type assertion to the raw error correctly.
|
||||
//
|
||||
// Based on all these constraints, we use errors.As() with an internal interface
|
||||
// that can only be implemented by our internal error types. When one is found,
|
||||
// we handle each of our internal types as a special case. For errWithCause, we
|
||||
// traverse to the wrapped error, ignoring the cause and the funky Unwrap logic.
|
||||
// We could have just used errors.As(err, *errWithValue), but that would have
|
||||
// traversed into the causes.
|
||||
|
||||
for {
|
||||
switch t := err.(type) {
|
||||
case *errWithValue:
|
||||
if t.key == key {
|
||||
return t.value, true
|
||||
}
|
||||
err = t.err
|
||||
case *errWithCause:
|
||||
err = t.err
|
||||
default:
|
||||
if errors.As(err, &merr) {
|
||||
err = merr
|
||||
} else {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 Values(err error) map[interface{}]interface{} {
|
||||
var values map[interface{}]interface{}
|
||||
|
||||
for err != nil {
|
||||
if e, ok := err.(*errWithValue); ok {
|
||||
if _, ok := values[e.key]; !ok {
|
||||
if values == nil {
|
||||
values = map[interface{}]interface{}{}
|
||||
}
|
||||
values[e.key] = e.value
|
||||
}
|
||||
}
|
||||
err = errors.Unwrap(err)
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
// Stack returns the stack attached to an error, or nil if one is not attached
|
||||
// If e is nil, returns nil.
|
||||
func Stack(err error) []uintptr {
|
||||
stack, _ := Value(err, errKeyStack).([]uintptr)
|
||||
return stack
|
||||
}
|
||||
|
||||
// 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 HTTPCode(err error) int {
|
||||
if err == nil {
|
||||
return 200
|
||||
}
|
||||
|
||||
code, _ := Value(err, errKeyHTTPCode).(int)
|
||||
if code == 0 {
|
||||
return 500
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
// UserMessage returns the end-user safe message. Returns empty if not set.
|
||||
// If e is nil, returns "".
|
||||
func UserMessage(err error) string {
|
||||
msg, _ := Value(err, errKeyUserMessage).(string)
|
||||
return msg
|
||||
}
|
||||
|
||||
// Cause returns the cause of the argument. If e is nil, or has no cause,
|
||||
// nil is returned.
|
||||
func Cause(err error) error {
|
||||
var causer *errWithCause
|
||||
if errors.As(err, &causer) {
|
||||
return causer.cause
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 RegisteredDetails(err error) map[string]interface{} {
|
||||
detailsLock.Lock()
|
||||
defer detailsLock.Unlock()
|
||||
|
||||
if len(detailFields) == 0 || err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
dets := map[string]interface{}{}
|
||||
|
||||
for label, f := range detailFields {
|
||||
dets[label] = f(err)
|
||||
}
|
||||
|
||||
return dets
|
||||
}
|
||||
|
||||
// captureStack: return an error with a stack attached. Stack will skip
|
||||
// specified frames. skip = 0 will start at caller.
|
||||
// If the err already has a stack, to auto-stack-capture is disabled globally,
|
||||
// this is a no-op. Use force to override and force a stack capture
|
||||
// in all cases.
|
||||
func captureStack(err error, skip int, force bool) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var c interface {
|
||||
Callers() []uintptr
|
||||
}
|
||||
|
||||
switch {
|
||||
case force:
|
||||
// always capture
|
||||
case HasStack(err):
|
||||
return err
|
||||
case errors.As(err, &c):
|
||||
// if the go-errors already captured a stack
|
||||
// reuse it
|
||||
if stack := c.Callers(); len(stack) > 0 {
|
||||
return Set(err, errKeyStack, stack)
|
||||
}
|
||||
case !captureStacks:
|
||||
return err
|
||||
}
|
||||
|
||||
s := make([]uintptr, MaxStackDepth())
|
||||
length := runtime.Callers(2+skip, s[:])
|
||||
return Set(err, errKeyStack, s[:length])
|
||||
}
|
||||
|
||||
// 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 HasStack(err error) bool {
|
||||
_, ok := Lookup(err, errKeyStack)
|
||||
return ok
|
||||
}
|
37
vendor/github.com/ansel1/merry/v2/hooks.go
generated
vendored
Normal file
37
vendor/github.com/ansel1/merry/v2/hooks.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
package merry
|
||||
|
||||
var hooks []Wrapper
|
||||
var onceHooks []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 AddHooks(hook ...Wrapper) {
|
||||
hooks = append(hooks, hook...)
|
||||
}
|
||||
|
||||
// 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 AddOnceHooks(hook ...Wrapper) {
|
||||
onceHooks = append(onceHooks, hook...)
|
||||
}
|
||||
|
||||
// ClearHooks removes all installed hooks.
|
||||
//
|
||||
// This function is not thread safe, and should only be called very early in program
|
||||
// initialization.
|
||||
func ClearHooks() {
|
||||
hooks = nil
|
||||
onceHooks = nil
|
||||
}
|
167
vendor/github.com/ansel1/merry/v2/impl.go
generated
vendored
Normal file
167
vendor/github.com/ansel1/merry/v2/impl.go
generated
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
package merry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type errKey int
|
||||
|
||||
const (
|
||||
errKeyNone errKey = iota
|
||||
errKeyStack
|
||||
errKeyMessage
|
||||
errKeyHTTPCode
|
||||
errKeyUserMessage
|
||||
errKeyForceCapture
|
||||
errKeyHooked
|
||||
)
|
||||
|
||||
func (e errKey) String() string {
|
||||
switch e {
|
||||
case errKeyNone:
|
||||
return "none"
|
||||
case errKeyStack:
|
||||
return "stack"
|
||||
case errKeyMessage:
|
||||
return "message"
|
||||
case errKeyHTTPCode:
|
||||
return "http status code"
|
||||
case errKeyUserMessage:
|
||||
return "user message"
|
||||
case errKeyForceCapture:
|
||||
return "force stack capture"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type errWithValue struct {
|
||||
err error
|
||||
key, value interface{}
|
||||
}
|
||||
|
||||
// Format implements fmt.Formatter
|
||||
func (e *errWithValue) Format(s fmt.State, verb rune) {
|
||||
Format(s, verb, e)
|
||||
}
|
||||
|
||||
// Error implements golang's error interface
|
||||
// returns the message value if set, otherwise
|
||||
// delegates to inner error
|
||||
func (e *errWithValue) Error() string {
|
||||
if e.key == errKeyMessage {
|
||||
if s, ok := e.value.(string); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (e *errWithValue) String() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
// Unwrap returns the next wrapped error.
|
||||
func (e *errWithValue) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
// isMerryError is a marker method for identifying error types implemented by this package.
|
||||
func (e *errWithValue) isMerryError() {}
|
||||
|
||||
type errWithCause struct {
|
||||
err error
|
||||
cause error
|
||||
}
|
||||
|
||||
func (e *errWithCause) Unwrap() error {
|
||||
// skip through any directly nested errWithCauses.
|
||||
// our implementation of Is/As already recursed through them,
|
||||
// so we want to dig down to the first non-errWithCause.
|
||||
|
||||
nextErr := e.err
|
||||
for {
|
||||
if e, ok := nextErr.(*errWithCause); ok {
|
||||
nextErr = e.err
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// errWithCause.Is/As() also already checked nextErr, so we want to
|
||||
// unwrap it and get to the next error down.
|
||||
nextErr = errors.Unwrap(nextErr)
|
||||
|
||||
// we've reached the end of this wrapper chain. Return the cause.
|
||||
if nextErr == nil {
|
||||
return e.cause
|
||||
}
|
||||
|
||||
// return a new errWithCause wrapper, wrapping next error, but bundling
|
||||
// it will our cause, ignoring the causes of the errWithCauses we skip
|
||||
// over above. This is how we carry the latest cause along as we unwrap
|
||||
// the chain. When we get to the end of the chain, we'll return this latest
|
||||
// cause.
|
||||
return &errWithCause{err: nextErr, cause: e.cause}
|
||||
}
|
||||
|
||||
func (e *errWithCause) String() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
func (e *errWithCause) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func (e *errWithCause) Format(f fmt.State, verb rune) {
|
||||
Format(f, verb, e)
|
||||
}
|
||||
|
||||
// errWithCause needs to provide custome implementations of Is and As.
|
||||
// errors.Is() doesn't work on errWithCause because error.Is() uses errors.Unwrap() to traverse the error
|
||||
// chain. But errWithCause.Unwrap() doesn't return the next error in the chain. Instead,
|
||||
// it wraps the next error in a shim. The standard Is/As tests would compare the shim to the target.
|
||||
// We need to override Is/As to compare the target to the error inside the shim.
|
||||
|
||||
func (e *errWithCause) Is(target error) bool {
|
||||
// This does most of what errors.Is() does, by delegating
|
||||
// to the nested error. But it does not use Unwrap to recurse
|
||||
// any further. This just compares target with next error in the stack.
|
||||
isComparable := reflect.TypeOf(target).Comparable()
|
||||
if isComparable && e.err == target {
|
||||
return true
|
||||
}
|
||||
|
||||
// since errWithCause implements Is(), this will effectively recurse through
|
||||
// any directly nested errWithCauses.
|
||||
if x, ok := e.err.(interface{ Is(error) bool }); ok && x.Is(target) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *errWithCause) As(target interface{}) bool {
|
||||
// This does most of what errors.As() does, by delegating
|
||||
// to the nested error. But it does not use Unwrap to recurse
|
||||
// any further. This just compares target with next error in the stack.
|
||||
val := reflect.ValueOf(target)
|
||||
typ := val.Type()
|
||||
targetType := typ.Elem()
|
||||
if reflect.TypeOf(e.err).AssignableTo(targetType) {
|
||||
val.Elem().Set(reflect.ValueOf(e.err))
|
||||
return true
|
||||
}
|
||||
|
||||
// since errWithCause implements As(), this will effectively recurse through
|
||||
// any directly nested errWithCauses.
|
||||
if x, ok := e.err.(interface{ As(interface{}) bool }); ok && x.As(target) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isMerryError is a marker method for identifying error types implemented by this package.
|
||||
func (e *errWithCause) isMerryError() {}
|
144
vendor/github.com/ansel1/merry/v2/print.go
generated
vendored
Normal file
144
vendor/github.com/ansel1/merry/v2/print.go
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
package merry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Location returns zero values if e has no stacktrace
|
||||
func Location(err error) (file string, line int) {
|
||||
s := Stack(err)
|
||||
if len(s) > 0 {
|
||||
fnc, _ := runtime.CallersFrames(s[:1]).Next()
|
||||
return fnc.File, fnc.Line
|
||||
}
|
||||
return "", 0
|
||||
}
|
||||
|
||||
// SourceLine returns the string representation of
|
||||
// Location's result or an empty string if there's
|
||||
// no stracktrace.
|
||||
func SourceLine(err error) string {
|
||||
s := Stack(err)
|
||||
if len(s) > 0 {
|
||||
fnc, _ := runtime.CallersFrames(s[:1]).Next()
|
||||
_, f := path.Split(fnc.File)
|
||||
return fmt.Sprintf("%s (%s:%d)", fnc.Function, f, fnc.Line)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 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 FormattedStack(err error) []string {
|
||||
formattedStack, _ := Value(err, errKeyStack).([]string)
|
||||
if len(formattedStack) > 0 {
|
||||
return formattedStack
|
||||
}
|
||||
|
||||
s := Stack(err)
|
||||
if len(s) > 0 {
|
||||
lines := make([]string, 0, len(s))
|
||||
|
||||
frames := runtime.CallersFrames(s)
|
||||
for {
|
||||
frame, more := frames.Next()
|
||||
lines = append(lines, fmt.Sprintf("%s\n\t%s:%d", frame.Function, frame.File, frame.Line))
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
return lines
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stacktrace returns the error's stacktrace as a string formatted.
|
||||
// If e has no stacktrace, returns an empty string.
|
||||
func Stacktrace(err error) string {
|
||||
return strings.Join(FormattedStack(err), "\n")
|
||||
}
|
||||
|
||||
// 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 Details(e error) string {
|
||||
if e == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
msg := e.Error()
|
||||
var dets []string
|
||||
|
||||
detailsLock.Lock()
|
||||
|
||||
for label, f := range detailFields {
|
||||
v := f(e)
|
||||
if v != nil {
|
||||
dets = append(dets, fmt.Sprintf("%s: %v", label, v))
|
||||
}
|
||||
}
|
||||
|
||||
detailsLock.Unlock()
|
||||
|
||||
if len(dets) > 0 {
|
||||
// sort so output is predictable
|
||||
sort.Strings(dets)
|
||||
msg += "\n" + strings.Join(dets, "\n")
|
||||
}
|
||||
|
||||
s := Stacktrace(e)
|
||||
if s != "" {
|
||||
msg += "\n\n" + s
|
||||
}
|
||||
|
||||
if c := Cause(e); c != nil {
|
||||
msg += "\n\nCaused By: " + Details(c)
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
// 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 Format(s fmt.State, verb rune, err error) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
io.WriteString(s, Details(err))
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, msgWithCauses(err))
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func msgWithCauses(err error) string {
|
||||
messages := make([]string, 0, 5)
|
||||
|
||||
for err != nil {
|
||||
if ce := err.Error(); ce != "" {
|
||||
messages = append(messages, ce)
|
||||
}
|
||||
err = Cause(err)
|
||||
}
|
||||
|
||||
return strings.Join(messages, ": ")
|
||||
}
|
183
vendor/github.com/ansel1/merry/v2/wrappers.go
generated
vendored
Normal file
183
vendor/github.com/ansel1/merry/v2/wrappers.go
generated
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
package merry
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Wrapper knows how to wrap errors with context information.
|
||||
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
|
||||
}
|
||||
|
||||
// WrapperFunc implements Wrapper.
|
||||
type WrapperFunc func(error, int) error
|
||||
|
||||
// Wrap implements the Wrapper interface.
|
||||
func (w WrapperFunc) Wrap(err error, callerDepth int) error {
|
||||
return w(err, callerDepth+1)
|
||||
}
|
||||
|
||||
// WithValue associates a key/value pair with an error.
|
||||
func WithValue(key, value interface{}) Wrapper {
|
||||
return WrapperFunc(func(err error, _ int) error {
|
||||
return Set(err, key, value)
|
||||
})
|
||||
}
|
||||
|
||||
// WithMessage overrides the value returned by err.Error().
|
||||
func WithMessage(msg string) Wrapper {
|
||||
return WithValue(errKeyMessage, msg)
|
||||
}
|
||||
|
||||
// WithMessagef overrides the value returned by err.Error().
|
||||
func WithMessagef(format string, args ...interface{}) Wrapper {
|
||||
return WrapperFunc(func(err error, _ int) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return Set(err, errKeyMessage, fmt.Sprintf(format, args...))
|
||||
})
|
||||
}
|
||||
|
||||
// WithUserMessage associates an end-user message with an error.
|
||||
func WithUserMessage(msg string) Wrapper {
|
||||
return WithValue(errKeyUserMessage, msg)
|
||||
}
|
||||
|
||||
// WithUserMessagef associates a formatted end-user message with an error.
|
||||
func WithUserMessagef(format string, args ...interface{}) Wrapper {
|
||||
return WrapperFunc(func(err error, _ int) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return Set(err, errKeyUserMessage, fmt.Sprintf(format, args...))
|
||||
})
|
||||
}
|
||||
|
||||
// AppendMessage a message after the current error message, in the format "original: new".
|
||||
func AppendMessage(msg string) Wrapper {
|
||||
return WrapperFunc(func(err error, _ int) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return Set(err, errKeyMessage, err.Error()+": "+msg)
|
||||
})
|
||||
}
|
||||
|
||||
// AppendMessagef is the same as AppendMessage, but with a formatted message.
|
||||
func AppendMessagef(format string, args ...interface{}) Wrapper {
|
||||
return WrapperFunc(func(err error, _ int) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return Set(err, errKeyMessage, err.Error()+": "+fmt.Sprintf(format, args...))
|
||||
})
|
||||
}
|
||||
|
||||
// PrependMessage a message before the current error message, in the format "new: original".
|
||||
func PrependMessage(msg string) Wrapper {
|
||||
return WrapperFunc(func(err error, _ int) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return Set(err, errKeyMessage, msg+": "+err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
// PrependMessagef is the same as PrependMessage, but with a formatted message.
|
||||
func PrependMessagef(format string, args ...interface{}) Wrapper {
|
||||
return WrapperFunc(func(err error, _ int) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return Set(err, errKeyMessage, fmt.Sprintf(format, args...)+": "+err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
// WithHTTPCode associates an HTTP status code with an error.
|
||||
func WithHTTPCode(statusCode int) Wrapper {
|
||||
return WithValue(errKeyHTTPCode, statusCode)
|
||||
}
|
||||
|
||||
// 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 WithStack(stack []uintptr) Wrapper {
|
||||
return WithValue(errKeyStack, stack)
|
||||
}
|
||||
|
||||
// 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 WithFormattedStack(stack []string) Wrapper {
|
||||
return WithValue(errKeyStack, stack)
|
||||
}
|
||||
|
||||
// NoCaptureStack will suppress capturing a stack, even if StackCaptureEnabled() == true.
|
||||
func NoCaptureStack() Wrapper {
|
||||
return WrapperFunc(func(err error, _ int) error {
|
||||
// if this err already has a stack set, there is no need to set the
|
||||
// stack property again, and we don't want to override the prior the stack
|
||||
if HasStack(err) {
|
||||
return err
|
||||
}
|
||||
return Set(err, errKeyStack, nil)
|
||||
})
|
||||
}
|
||||
|
||||
// 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 CaptureStack(force bool) Wrapper {
|
||||
return WrapperFunc(func(err error, callerDepth int) error {
|
||||
return captureStack(err, callerDepth+1, force || StackCaptureEnabled())
|
||||
})
|
||||
}
|
||||
|
||||
// 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, as well as down the chain of causes.
|
||||
func WithCause(err error) Wrapper {
|
||||
return WrapperFunc(func(nerr error, _ int) error {
|
||||
if nerr == nil {
|
||||
return nil
|
||||
}
|
||||
return &errWithCause{err: nerr, cause: err}
|
||||
})
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// Keeping this private for now. If it proves useful, it may be made public later, but
|
||||
// for now, external packages can get the same behavor with this:
|
||||
//
|
||||
// WithValue(key, value).Wrap(err)
|
||||
//
|
||||
func Set(err error, key, value interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &errWithValue{
|
||||
err: err,
|
||||
key: key,
|
||||
value: value,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user