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:
50
vendor/github.com/ansel1/merry/.gitignore
generated
vendored
Normal file
50
vendor/github.com/ansel1/merry/.gitignore
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion
|
||||
|
||||
*.iml
|
||||
|
||||
## Directory-based project format:
|
||||
.idea/
|
||||
# if you remove the above rule, at least ignore the following:
|
||||
|
||||
# User-specific stuff:
|
||||
# .idea/workspace.xml
|
||||
# .idea/tasks.xml
|
||||
# .idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
# .idea/dataSources.ids
|
||||
# .idea/dataSources.xml
|
||||
# .idea/sqlDataSources.xml
|
||||
# .idea/dynamic.xml
|
||||
# .idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# .idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
|
||||
vendor/
|
21
vendor/github.com/ansel1/merry/LICENSE
generated
vendored
Normal file
21
vendor/github.com/ansel1/merry/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.
|
44
vendor/github.com/ansel1/merry/Makefile
generated
vendored
Normal file
44
vendor/github.com/ansel1/merry/Makefile
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
# Expands to list this project's go packages, excluding the vendor folder
|
||||
SHELL = bash
|
||||
|
||||
all: fmt build test lint v2
|
||||
|
||||
v2:
|
||||
$(MAKE) -C v2
|
||||
|
||||
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 v2
|
||||
|
255
vendor/github.com/ansel1/merry/README.md
generated
vendored
Normal file
255
vendor/github.com/ansel1/merry/README.md
generated
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
merry [](https://github.com/ansel1/merry/actions?query=branch%3Amaster+workflow%3ABuild+) [](https://godoc.org/github.com/ansel1/merry) [](https://goreportcard.com/report/github.com/ansel1/merry)
|
||||
=====
|
||||
|
||||
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.
|
||||
|
||||
V2
|
||||
--
|
||||
|
||||
[github.com/ansel1/merry/v2](https://github.com/ansel1/merry/tree/master/v2) now replaces v1. v1 will continue to be supported. v1 has been re-implemented
|
||||
in terms of v2, and the two packages can be used together and interchangeably.
|
||||
|
||||
There are some small enhancements and changes to v1 with the introduction of v2:
|
||||
|
||||
- err.Error() now *always* just prints out the basic error message. It no longer prints out details,
|
||||
user message, or cause. VerboseDefault() and SetVerboseDefault() no longer have any effect. To
|
||||
print more detailed error information, you must use fmt:
|
||||
|
||||
// print err message and cause chain
|
||||
fmt.Printf("%v", err) // %s works too
|
||||
|
||||
// print details, same as Details(err)
|
||||
fmt.Printf("%v+", err)
|
||||
|
||||
- MaxStackDepth is no longer supported. Setting it has no effect. It has been replaced with
|
||||
GetMaxStackDepth() and SetMaxStackDepth(), which delegate to corresponding v2 functions.
|
||||
- New, Errorf, Wrap, and WrapSkipping now accept v2.Wrapper arguments, allowing a mixture of
|
||||
v1's fluent API style and v2's option-func API style.
|
||||
- Compatibility with other error wrapping libraries is improved. All functions which extract
|
||||
a value from an error will now search the entire chain of errors, even if errors created by
|
||||
other libraries are inserted in the middle of the chain, so long as those errors implement
|
||||
Unwrap().
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
go get github.com/ansel1/merry
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
Merry errors work a lot like google's golang.org/x/net/context package.
|
||||
Merry errors wrap normal errors with a context of key/value pairs.
|
||||
Like contexts, merry errors are immutable: adding a key/value to an error
|
||||
always creates a new error which wraps the original.
|
||||
|
||||
`merry` comes with built-in support for adding information to errors:
|
||||
|
||||
* stacktraces
|
||||
* overriding the error message
|
||||
* HTTP status codes
|
||||
* End user error messages
|
||||
|
||||
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
|
||||
|
||||
Details
|
||||
-------
|
||||
|
||||
* Support for go 2's errors.Is and errors.As functions
|
||||
* New errors have a stacktrace captured where they are created
|
||||
* Add a stacktrace to existing errors (captured where they are wrapped)
|
||||
|
||||
```go
|
||||
err := lib.Read()
|
||||
return merry.Wrap(err) // no-op if err is already merry
|
||||
```
|
||||
|
||||
* Add a stacktrace to a sentinel error
|
||||
|
||||
```go
|
||||
var ParseError = merry.New("parse error")
|
||||
|
||||
func Parse() error {
|
||||
// ...
|
||||
return ParseError.Here() // captures a stacktrace here
|
||||
}
|
||||
```
|
||||
|
||||
* The golang idiom for testing errors against sentinel values or type checking them
|
||||
doesn't work with merry errors, since they are wrapped. Use Is() for sentinel value
|
||||
checks, or the new go 2 errors.As() function for testing error types.
|
||||
|
||||
```go
|
||||
err := Parse()
|
||||
|
||||
// sentinel value check
|
||||
if merry.Is(err, ParseError) {
|
||||
// ...
|
||||
}
|
||||
|
||||
// type check
|
||||
if serr, ok := merry.Unwrap(err).(*SyntaxError); ok {
|
||||
// ...
|
||||
}
|
||||
|
||||
// these only work in go1.13
|
||||
|
||||
// sentinel value check
|
||||
if errors.Is(err, ParseError) {}
|
||||
|
||||
// type check
|
||||
var serr *SyntaxError
|
||||
if errors.As(err, &serr) {}
|
||||
```
|
||||
|
||||
* Add to the message on an error.
|
||||
|
||||
```go
|
||||
err := merry.Prepend(ParseError, "reading config").Append("bad input")
|
||||
fmt.Println(err.Error()) // reading config: parse error: bad input
|
||||
```
|
||||
|
||||
* Hierarchies of errors
|
||||
|
||||
```go
|
||||
var ParseError = merry.New("Parse error")
|
||||
var InvalidCharSet = merry.WithMessage(ParseError, "Invalid char set")
|
||||
var InvalidSyntax = merry.WithMessage(ParseError, "Invalid syntax")
|
||||
|
||||
func Parse(s string) error {
|
||||
// use chainable methods to add context
|
||||
return InvalidCharSet.Here().WithMessagef("Invalid char set: %s", "UTF-8")
|
||||
// or functions
|
||||
// return merry.WithMessagef(merry.Here(InvalidCharSet), "Invalid char set: %s", "UTF-8")
|
||||
}
|
||||
|
||||
func Check() {
|
||||
err := Parse("fields")
|
||||
merry.Is(err, ParseError) // yup
|
||||
merry.Is(err, InvalidCharSet) // yup
|
||||
merry.Is(err, InvalidSyntax) // nope
|
||||
}
|
||||
```
|
||||
|
||||
* Add an HTTP status code
|
||||
|
||||
```go
|
||||
merry.HTTPCode(errors.New("regular error")) // 500
|
||||
merry.HTTPCode(merry.New("merry error").WithHTTPCode(404)) // 404
|
||||
```
|
||||
|
||||
* Set an alternate error message for end users
|
||||
|
||||
```go
|
||||
e := merry.New("crash").WithUserMessage("nothing to see here")
|
||||
merry.UserMessage(e) // returns "nothing to see here"
|
||||
```
|
||||
|
||||
* Functions for printing error details
|
||||
|
||||
```go
|
||||
err := merry.New("boom")
|
||||
m := merry.Stacktrace(err) // just the stacktrace
|
||||
m = merry.Details(err) // error message and stacktrace
|
||||
fmt.Sprintf("%+v", err) == merry.Details(err) // errors implement fmt.Formatter
|
||||
```
|
||||
|
||||
* Add your own context info
|
||||
|
||||
```go
|
||||
err := merry.New("boom").WithValue("explosive", "black powder")
|
||||
```
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
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.
|
||||
|
||||
Capturing the stack can be globally disabled with `SetStackCaptureEnabled(false)`
|
||||
|
||||
Functions which get context values from errors also accept `error`, and will return default
|
||||
values if the error is not merry, or doesn't have that key attached.
|
||||
|
||||
All the functions which create or attach context return concrete instances of `*Error`. `*Error`
|
||||
implements methods to add context to the error (they mirror the functions and do
|
||||
the same thing). They allow for a chainable syntax for adding context.
|
||||
|
||||
Example:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/ansel1/merry"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var InvalidInputs = errors.New("Input is invalid")
|
||||
|
||||
func main() {
|
||||
// create a new error, with a stacktrace attached
|
||||
err := merry.New("bad stuff happened")
|
||||
|
||||
// create a new error with format string, like fmt.Errorf
|
||||
err = merry.Errorf("bad input: %v", os.Args)
|
||||
|
||||
// capture a fresh stacktrace from this callsite
|
||||
err = merry.Here(InvalidInputs)
|
||||
|
||||
// Make err merry if it wasn't already. The stacktrace will be captured here if the
|
||||
// error didn't already have one. Also useful to cast to *Error
|
||||
err = merry.Wrap(err, 0)
|
||||
|
||||
// override the original error's message
|
||||
err.WithMessagef("Input is invalid: %v", os.Args)
|
||||
|
||||
// Use Is to compare errors against values, which is a common golang idiom
|
||||
merry.Is(err, InvalidInputs) // will be true
|
||||
|
||||
// associated an http code
|
||||
err.WithHTTPCode(400)
|
||||
|
||||
perr := parser.Parse("blah")
|
||||
err = Wrap(perr, 0)
|
||||
// Get the original error back
|
||||
merry.Unwrap(err) == perr // will be true
|
||||
|
||||
// Print the error to a string, with the stacktrace, if it has one
|
||||
s := merry.Details(err)
|
||||
|
||||
// Just print the stacktrace (empty string if err is not a RichError)
|
||||
s := merry.Stacktrace(err)
|
||||
|
||||
// Get the location of the error (the first line in the stacktrace)
|
||||
file, line := merry.Location(err)
|
||||
|
||||
// Get an HTTP status code for an error. Defaults to 500 for non-nil errors, and 200 if err is nil.
|
||||
code := merry.HTTPCode(err)
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
See inline docs for more details.
|
||||
|
||||
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.
|
152
vendor/github.com/ansel1/merry/chainable_api.go
generated
vendored
Normal file
152
vendor/github.com/ansel1/merry/chainable_api.go
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
package merry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
v2 "github.com/ansel1/merry/v2"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Error extends the standard golang `error` interface with functions
|
||||
// for attachment additional data to the error
|
||||
type Error interface {
|
||||
error
|
||||
Appendf(format string, args ...interface{}) Error
|
||||
Append(msg string) Error
|
||||
Prepend(msg string) Error
|
||||
Prependf(format string, args ...interface{}) Error
|
||||
WithMessage(msg string) Error
|
||||
WithMessagef(format string, args ...interface{}) Error
|
||||
WithUserMessage(msg string) Error
|
||||
WithUserMessagef(format string, args ...interface{}) Error
|
||||
WithValue(key, value interface{}) Error
|
||||
Here() Error
|
||||
WithStackSkipping(skip int) Error
|
||||
WithHTTPCode(code int) Error
|
||||
WithCause(err error) Error
|
||||
Cause() error
|
||||
fmt.Formatter
|
||||
}
|
||||
|
||||
// make sure errImpl implements Error
|
||||
var _ Error = (*errImpl)(nil)
|
||||
|
||||
// WithValue is equivalent to WithValue(e, key, value).
|
||||
func (e *errImpl) WithValue(key, value interface{}) Error {
|
||||
return WrapSkipping(e, 1, v2.WithValue(key, value))
|
||||
}
|
||||
|
||||
// Here is equivalent to Here(e).
|
||||
func (e *errImpl) Here() Error {
|
||||
return HereSkipping(e, 1)
|
||||
}
|
||||
|
||||
// WithStackSkipping is equivalent to HereSkipping(e, i).
|
||||
func (e *errImpl) WithStackSkipping(skip int) Error {
|
||||
return HereSkipping(e, skip+1)
|
||||
}
|
||||
|
||||
// WithHTTPCode is equivalent to WithHTTPCode(e, code).
|
||||
func (e *errImpl) WithHTTPCode(code int) Error {
|
||||
return WrapSkipping(e, 1, v2.WithHTTPCode(code))
|
||||
}
|
||||
|
||||
// WithMessage is equivalent to WithMessage(e, msg).
|
||||
func (e *errImpl) WithMessage(msg string) Error {
|
||||
return WrapSkipping(e, 1, v2.WithMessage(msg))
|
||||
}
|
||||
|
||||
// WithMessagef is equivalent to WithMessagef(e, format, args...).
|
||||
func (e *errImpl) WithMessagef(format string, args ...interface{}) Error {
|
||||
return WrapSkipping(e, 1, v2.WithMessagef(format, args...))
|
||||
}
|
||||
|
||||
// WithUserMessage is equivalent to WithUserMessage(e, msg).
|
||||
func (e *errImpl) WithUserMessage(msg string) Error {
|
||||
return WrapSkipping(e, 1, v2.WithUserMessage(msg))
|
||||
}
|
||||
|
||||
// WithUserMessagef is equivalent to WithUserMessagef(e, format, args...).
|
||||
func (e *errImpl) WithUserMessagef(format string, args ...interface{}) Error {
|
||||
return WrapSkipping(e, 1, v2.WithUserMessagef(format, args...))
|
||||
}
|
||||
|
||||
// Append is equivalent to Append(err, msg).
|
||||
func (e *errImpl) Append(msg string) Error {
|
||||
return WrapSkipping(e, 1, v2.AppendMessage(msg))
|
||||
}
|
||||
|
||||
// Appendf is equivalent to Appendf(err, format, msg).
|
||||
func (e *errImpl) Appendf(format string, args ...interface{}) Error {
|
||||
return WrapSkipping(e, 1, v2.AppendMessagef(format, args...))
|
||||
}
|
||||
|
||||
// Prepend is equivalent to Prepend(err, msg).
|
||||
func (e *errImpl) Prepend(msg string) Error {
|
||||
return WrapSkipping(e, 1, v2.PrependMessage(msg))
|
||||
}
|
||||
|
||||
// Prependf is equivalent to Prependf(err, format, args...).
|
||||
func (e *errImpl) Prependf(format string, args ...interface{}) Error {
|
||||
return WrapSkipping(e, 1, v2.PrependMessagef(format, args...))
|
||||
}
|
||||
|
||||
// WithCause is equivalent to WithCause(e, err).
|
||||
func (e *errImpl) WithCause(err error) Error {
|
||||
return WrapSkipping(e, 1, v2.WithCause(err))
|
||||
}
|
||||
|
||||
// errImpl coerces an error to an Error
|
||||
type errImpl struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func coerce(err error) Error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if e, ok := err.(Error); ok {
|
||||
return e
|
||||
}
|
||||
|
||||
return &errImpl{err}
|
||||
}
|
||||
|
||||
// Format implements fmt.Formatter.
|
||||
func (e *errImpl) Format(s fmt.State, verb rune) {
|
||||
// the inner err should always be an err produced
|
||||
// by v2
|
||||
if f, ok := e.err.(fmt.Formatter); ok {
|
||||
f.Format(s, verb)
|
||||
return
|
||||
}
|
||||
|
||||
// should never happen, but fall back on something
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
_, _ = io.WriteString(s, Details(e))
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
_, _ = io.WriteString(s, e.Error())
|
||||
case 'q':
|
||||
_, _ = fmt.Fprintf(s, "%q", e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e *errImpl) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
// Unwrap returns the next wrapped error.
|
||||
func (e *errImpl) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
// Cause implements Error.
|
||||
func (e *errImpl) Cause() error {
|
||||
return Cause(e.err)
|
||||
}
|
90
vendor/github.com/ansel1/merry/doc.go
generated
vendored
Normal file
90
vendor/github.com/ansel1/merry/doc.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
// Package merry provides enriched golang errors, with stacktraces
|
||||
//
|
||||
// merry creates errors with stacktraces, and can augment those errors with additional
|
||||
// information.
|
||||
//
|
||||
// When you create a new merry error, or wrap an existing error in a merry error, merry attaches
|
||||
// a stacktrace to the error:
|
||||
//
|
||||
// err := merry.New("an error occurred")
|
||||
//
|
||||
// err has a stacktrace attached. Alternately, you can wrap existing errors. merry will
|
||||
// attach a stacktrace at the point of wrapping:
|
||||
//
|
||||
// _, err := ioutil.ReadAll(r)
|
||||
// if err != nil {
|
||||
// return merry.Wrap(err)
|
||||
// }
|
||||
//
|
||||
// Capturing the stack can be globally disabled with `SetStackCaptureEnabled(false)`. Wrapping
|
||||
// is idempotent: Wrap will only attach a stacktrace if the error doesn't already have one.
|
||||
//
|
||||
// Wrap() is the simplest way to attach a stacktrace to an error, but other functions can be
|
||||
// used instead, with both add a stacktrace, and augment or modify the error. For example,
|
||||
// Prepend() modifies the error's message (and also attaches a stacktrace):
|
||||
//
|
||||
// _, err := ioutil.ReadAll(r)
|
||||
// if err != nil {
|
||||
// return merry.Prepend(err, "reading from conn failed")
|
||||
// // err.Error() would read something like "reading from conn failed: timeout"
|
||||
// }
|
||||
//
|
||||
// See the other package functions for other ways to augment or modify errors, such as Append,
|
||||
// WithUserMessage, WithHTTPCode, WithValue, etc. These functions all return a merry.Error interface, which
|
||||
// has methods which mirror the package level functions, to allow simple chaining:
|
||||
//
|
||||
// return merry.New("object not found").WithHTTPCode(404)
|
||||
//
|
||||
// Here
|
||||
//
|
||||
// Wrap will not take a new stacktrace if an error already has one attached. Here will create
|
||||
// a new error which replaces the stacktrace with a new one:
|
||||
//
|
||||
// var ErrOverflow = merry.New("overflowed")
|
||||
//
|
||||
// func Read() error {
|
||||
// // ...
|
||||
// return merry.Here(ErrOverflow)
|
||||
// }
|
||||
//
|
||||
// Is
|
||||
//
|
||||
// The go idiom of exporting package-level error variables for comparison to errors returned
|
||||
// by the package is broken by merry. For example:
|
||||
//
|
||||
// _, err := io.ReadAll(r)
|
||||
// if err == io.EOF {
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// If the error returned was a merry error, the equality comparison would always fail, because merry
|
||||
// augments errors by wrapping them in layers. To compensate for this, merry has the Is() function.
|
||||
//
|
||||
// if merry.Is(err, io.EOF) {
|
||||
//
|
||||
// Is() will unwrap the err and compare each layer to the second argument.
|
||||
//
|
||||
// Cause
|
||||
//
|
||||
// You can add a cause to an error:
|
||||
//
|
||||
// if err == io.EOF {
|
||||
// err = merry.New("reading failed"), err)
|
||||
// fmt.Println(err.Error()) // reading failed: EOF
|
||||
// }
|
||||
//
|
||||
// Cause(error) will return the cause of the argument. RootCause(error) returns the innermost cause.
|
||||
// Is(err1, err2) is cause aware, and will return true if err2 is a cause (anywhere in the causal change)
|
||||
// of err1.
|
||||
//
|
||||
// Formatting and printing
|
||||
//
|
||||
// To obtain an error's stacktrace, call Stack(). To get other information about the site
|
||||
// of the error, or print the error's stacktrace, see Location(), SourceLine(), Stacktrace(), and Details().
|
||||
//
|
||||
// merry errors also implement the fmt.Formatter interface. errors support the following fmt flags:
|
||||
//
|
||||
// %+v print the equivalent of Details(err), which includes the user message, full stacktrace,
|
||||
// and recursively prints the details of the cause chain.
|
||||
//
|
||||
package merry
|
304
vendor/github.com/ansel1/merry/errors.go
generated
vendored
Normal file
304
vendor/github.com/ansel1/merry/errors.go
generated
vendored
Normal file
@ -0,0 +1,304 @@
|
||||
package merry
|
||||
|
||||
// The merry package augments standard golang errors with stacktraces
|
||||
// and other context information.
|
||||
//
|
||||
// You can add any context information to an error with `e = merry.WithValue(e, "code", 12345)`
|
||||
// You can retrieve that value with `v, _ := merry.Value(e, "code").(int)`
|
||||
//
|
||||
// Any error augmented like this will automatically get a stacktrace attached, if it doesn't have one
|
||||
// already. If you just want to add the stacktrace, use `Wrap(e)`
|
||||
//
|
||||
// It also providers a way to override an error's message:
|
||||
//
|
||||
// var InvalidInputs = errors.New("Bad inputs")
|
||||
//
|
||||
// `Here()` captures a new stacktrace, and WithMessagef() sets a new error message:
|
||||
//
|
||||
// return merry.Here(InvalidInputs).WithMessagef("Bad inputs: %v", inputs)
|
||||
//
|
||||
// Errors are immutable. All functions and methods which add context return new errors.
|
||||
// But errors can still be compared to the originals with `Is()`
|
||||
//
|
||||
// if merry.Is(err, InvalidInputs) {
|
||||
//
|
||||
// Functions which add context to errors have equivalent methods on *Error, to allow
|
||||
// convenient chaining:
|
||||
//
|
||||
// return merry.New("Invalid body").WithHTTPCode(400)
|
||||
//
|
||||
// merry.Errors also implement fmt.Formatter, similar to github.com/pkg/errors.
|
||||
//
|
||||
// fmt.Sprintf("%+v", e) == merry.Details(e)
|
||||
//
|
||||
// pkg/errors Cause() interface is not implemented (yet).
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
v2 "github.com/ansel1/merry/v2"
|
||||
)
|
||||
|
||||
// MaxStackDepth is no longer used. It remains here for backward compatibility.
|
||||
// deprecated: See Set/GetMaxStackDepth.
|
||||
var MaxStackDepth = 50
|
||||
|
||||
// StackCaptureEnabled returns whether stack capturing is enabled
|
||||
func StackCaptureEnabled() bool {
|
||||
return v2.StackCaptureEnabled()
|
||||
}
|
||||
|
||||
// SetStackCaptureEnabled sets stack capturing globally. Disabling stack capture can increase performance
|
||||
func SetStackCaptureEnabled(enabled bool) {
|
||||
v2.SetStackCaptureEnabled(enabled)
|
||||
}
|
||||
|
||||
// VerboseDefault no longer has any effect.
|
||||
// deprecated: see SetVerboseDefault
|
||||
func VerboseDefault() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetVerboseDefault used to control the behavior of the Error() function on errors
|
||||
// processed by this package. Error() now always just returns the error's message.
|
||||
// This setting no longer has any effect.
|
||||
// deprecated: To print the details of an error, use Details(err), or format the
|
||||
// error with the verbose flag: fmt.Sprintf("%+v", err)
|
||||
func SetVerboseDefault(bool) {
|
||||
}
|
||||
|
||||
// GetMaxStackDepth returns the number of frames captured in stacks.
|
||||
func GetMaxStackDepth() int {
|
||||
return v2.MaxStackDepth()
|
||||
}
|
||||
|
||||
// SetMaxStackDepth sets the MaxStackDepth.
|
||||
func SetMaxStackDepth(depth int) {
|
||||
v2.SetMaxStackDepth(depth)
|
||||
}
|
||||
|
||||
// New creates a new error, with a stack attached. The equivalent of golang's errors.New().
|
||||
// Accepts v2 wrappers to apply to the error.
|
||||
func New(msg string, wrappers ...v2.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 can be format args, or v2 wrappers which will be applied to the error.
|
||||
func Errorf(format string, args ...interface{}) Error {
|
||||
var wrappers []v2.Wrapper
|
||||
|
||||
// pull out the args which are wrappers
|
||||
n := 0
|
||||
for _, arg := range args {
|
||||
if w, ok := arg.(v2.Wrapper); ok {
|
||||
wrappers = append(wrappers, w)
|
||||
} else {
|
||||
args[n] = arg
|
||||
n++
|
||||
}
|
||||
}
|
||||
args = args[:n]
|
||||
|
||||
return WrapSkipping(fmt.Errorf(format, args...), 1, wrappers...)
|
||||
}
|
||||
|
||||
// UserError creates a new error with a message intended for display to an
|
||||
// end user.
|
||||
func UserError(msg string) Error {
|
||||
return WrapSkipping(errors.New(msg), 1, v2.WithUserMessage(msg))
|
||||
}
|
||||
|
||||
// UserErrorf is like UserError, but uses fmt.Sprintf()
|
||||
func UserErrorf(format string, args ...interface{}) Error {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
return WrapSkipping(errors.New(msg), 1, v2.WithUserMessagef(msg))
|
||||
}
|
||||
|
||||
// Wrap turns the argument into a merry.Error. If the argument already is a
|
||||
// merry.Error, this is a no-op.
|
||||
// If e == nil, return nil
|
||||
func Wrap(err error, wrappers ...v2.Wrapper) Error {
|
||||
return coerce(v2.WrapSkipping(err, 1, wrappers...))
|
||||
}
|
||||
|
||||
// WrapSkipping turns the error arg into a merry.Error if the arg is not
|
||||
// already a merry.Error.
|
||||
// If e is nil, return nil.
|
||||
// If a merry.Error is created by this call, the stack captured will skip
|
||||
// `skip` frames (0 is the call site of `WrapSkipping()`)
|
||||
func WrapSkipping(err error, skip int, wrappers ...v2.Wrapper) Error {
|
||||
return coerce(v2.WrapSkipping(err, skip+1, wrappers...))
|
||||
}
|
||||
|
||||
// WithValue adds a context an error. If the key was already set on e,
|
||||
// the new value will take precedence.
|
||||
// If e is nil, returns nil.
|
||||
func WithValue(err error, key, value interface{}) Error {
|
||||
return WrapSkipping(err, 1, v2.WithValue(key, value))
|
||||
}
|
||||
|
||||
// Value returns the value for key, or nil if not set.
|
||||
// If e is nil, returns nil.
|
||||
func Value(err error, key interface{}) interface{} {
|
||||
return v2.Value(err, key)
|
||||
}
|
||||
|
||||
// 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{} {
|
||||
return v2.Values(err)
|
||||
}
|
||||
|
||||
// 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{} {
|
||||
return v2.RegisteredDetails(err)
|
||||
}
|
||||
|
||||
// Here returns an error with a new stacktrace, at the call site of Here().
|
||||
// Useful when returning copies of exported package errors.
|
||||
// If e is nil, returns nil.
|
||||
func Here(err error) Error {
|
||||
return WrapSkipping(err, 1, v2.CaptureStack(false))
|
||||
}
|
||||
|
||||
// HereSkipping returns an error with a new stacktrace, at the call site
|
||||
// of HereSkipping() - skip frames.
|
||||
func HereSkipping(err error, skip int) Error {
|
||||
return WrapSkipping(err, skip+1, v2.CaptureStack(false))
|
||||
}
|
||||
|
||||
// Message returns just returns err.Error(). It is here for
|
||||
// historical reasons.
|
||||
func Message(err error) string {
|
||||
if err == nil {
|
||||
return ""
|
||||
}
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return v2.Stack(err)
|
||||
}
|
||||
|
||||
// WithHTTPCode returns an error with an http code attached.
|
||||
// If e is nil, returns nil.
|
||||
func WithHTTPCode(e error, code int) Error {
|
||||
return WrapSkipping(e, 1, v2.WithHTTPCode(code))
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return v2.HTTPCode(err)
|
||||
}
|
||||
|
||||
// UserMessage returns the end-user safe message. Returns empty if not set.
|
||||
// If e is nil, returns "".
|
||||
func UserMessage(err error) string {
|
||||
return v2.UserMessage(err)
|
||||
}
|
||||
|
||||
// Cause returns the cause of the argument. If e is nil, or has no cause,
|
||||
// nil is returned.
|
||||
func Cause(err error) error {
|
||||
return v2.Cause(err)
|
||||
}
|
||||
|
||||
// RootCause returns the innermost cause of the argument (i.e. the last
|
||||
// error in the cause chain)
|
||||
func RootCause(err error) error {
|
||||
for {
|
||||
cause := Cause(err)
|
||||
if cause == nil {
|
||||
return err
|
||||
}
|
||||
err = cause
|
||||
}
|
||||
}
|
||||
|
||||
// WithCause returns an error based on the first argument, with the cause
|
||||
// set to the second argument. If e is nil, returns nil.
|
||||
func WithCause(err error, cause error) Error {
|
||||
return WrapSkipping(err, 1, v2.WithCause(cause))
|
||||
}
|
||||
|
||||
// WithMessage returns an error with a new message.
|
||||
// The resulting error's Error() method will return
|
||||
// the new message.
|
||||
// If e is nil, returns nil.
|
||||
func WithMessage(err error, msg string) Error {
|
||||
return WrapSkipping(err, 1, v2.WithMessage(msg))
|
||||
}
|
||||
|
||||
// WithMessagef is the same as WithMessage(), using fmt.Sprintf().
|
||||
func WithMessagef(err error, format string, args ...interface{}) Error {
|
||||
return WrapSkipping(err, 1, v2.WithMessagef(format, args...))
|
||||
}
|
||||
|
||||
// WithUserMessage adds a message which is suitable for end users to see.
|
||||
// If e is nil, returns nil.
|
||||
func WithUserMessage(err error, msg string) Error {
|
||||
return WrapSkipping(err, 1, v2.WithUserMessage(msg))
|
||||
}
|
||||
|
||||
// WithUserMessagef is the same as WithMessage(), using fmt.Sprintf()
|
||||
func WithUserMessagef(err error, format string, args ...interface{}) Error {
|
||||
return WrapSkipping(err, 1, v2.WithUserMessagef(format, args...))
|
||||
}
|
||||
|
||||
// Append a message after the current error message, in the format "original: new".
|
||||
// If e == nil, return nil.
|
||||
func Append(err error, msg string) Error {
|
||||
return WrapSkipping(err, 1, v2.AppendMessage(msg))
|
||||
}
|
||||
|
||||
// Appendf is the same as Append, but uses fmt.Sprintf().
|
||||
func Appendf(err error, format string, args ...interface{}) Error {
|
||||
return WrapSkipping(err, 1, v2.AppendMessagef(format, args...))
|
||||
}
|
||||
|
||||
// Prepend a message before the current error message, in the format "new: original".
|
||||
// If e == nil, return nil.
|
||||
func Prepend(err error, msg string) Error {
|
||||
return WrapSkipping(err, 1, v2.PrependMessage(msg))
|
||||
}
|
||||
|
||||
// Prependf is the same as Prepend, but uses fmt.Sprintf()
|
||||
func Prependf(err error, format string, args ...interface{}) Error {
|
||||
return WrapSkipping(err, 1, v2.PrependMessagef(format, args...))
|
||||
}
|
||||
|
||||
// Is is equivalent to errors.Is, but tests against multiple targets.
|
||||
//
|
||||
// merry.Is(err1, err2, err3) == errors.Is(err1, err2) || errors.Is(err1, err3)
|
||||
func Is(e error, originals ...error) bool {
|
||||
for _, o := range originals {
|
||||
if errors.Is(e, o) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Unwrap returns the innermost underlying error.
|
||||
// This just calls errors.Unwrap() until if finds the deepest error.
|
||||
// It isn't very useful, and only remains for historical purposes
|
||||
//
|
||||
// deprecated: use errors.Is() or errors.As() instead.
|
||||
func Unwrap(e error) error {
|
||||
for {
|
||||
next := errors.Unwrap(e)
|
||||
if next == nil {
|
||||
return e
|
||||
}
|
||||
e = next
|
||||
}
|
||||
}
|
65
vendor/github.com/ansel1/merry/print.go
generated
vendored
Normal file
65
vendor/github.com/ansel1/merry/print.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
package merry
|
||||
|
||||
import (
|
||||
v2 "github.com/ansel1/merry/v2"
|
||||
)
|
||||
|
||||
// RegisterDetail registers an error property key in a global registry, with a label.
|
||||
// The registry is used by the Details() function. Registered error properties will
|
||||
// be included in Details() output, if the value of that error property is not nil.
|
||||
// For example:
|
||||
//
|
||||
// err := New("boom")
|
||||
// err = err.WithValue(colorKey, "red")
|
||||
// fmt.Println(Details(err))
|
||||
//
|
||||
// // Output:
|
||||
// // boom
|
||||
// //
|
||||
// // <stacktrace>
|
||||
//
|
||||
// RegisterDetail("Color", colorKey)
|
||||
// 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 RegisterDetail(label string, key interface{}) {
|
||||
v2.RegisterDetail(label, key)
|
||||
}
|
||||
|
||||
// Location returns zero values if e has no stacktrace
|
||||
func Location(err error) (file string, line int) {
|
||||
return v2.Location(err)
|
||||
}
|
||||
|
||||
// SourceLine returns the string representation of
|
||||
// Location's result or an empty string if there's
|
||||
// no stracktrace.
|
||||
func SourceLine(err error) string {
|
||||
return v2.SourceLine(err)
|
||||
}
|
||||
|
||||
// Stacktrace returns the error's stacktrace as a string formatted
|
||||
// the same way as golangs runtime package.
|
||||
// If e has no stacktrace, returns an empty string.
|
||||
func Stacktrace(err error) string {
|
||||
return v2.Stacktrace(err)
|
||||
}
|
||||
|
||||
// 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(err error) string {
|
||||
return v2.Details(err)
|
||||
}
|
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