Documentation
¶
Overview ¶
Package serrors provides enhanced errors. Errors created with serrors can have additional log context in form of key value pairs. The package provides wrapping methods. The returned errors support new Is and As error functionality. For any returned error err, errors.Is(err, err) is always true, for any err which wraps err2 or has err2 as msg, errors.Is(err, err2) is always true, for any other combination of errors errors.Is(x,y) can be assumed to return false.
Index ¶
- func IsTemporary(err error) bool
- func IsTimeout(err error) bool
- func Join(err, cause error, errCtx ...interface{}) error
- func JoinNoStack(err, cause error, errCtx ...interface{}) error
- func New(msg string, errCtx ...interface{}) error
- func Wrap(msg string, cause error, errCtx ...interface{}) error
- func WrapNoStack(msg string, cause error, errCtx ...interface{}) error
- type Frame
- type List
- type StackTrace
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsTemporary ¶
IsTemporary returns whether err is or is caused by a temporary error.
func Join ¶ added in v0.9.0
Join returns an error that associates the given error, with the given cause (an underlying error) unless nil, and the given context.
A stack dump is added unless cause is a basicError or joinedError (in which case it is assumed to contain a stack dump).
The returned error supports Is. If cause isn't nil, Is(cause) returns true. Is(error) returns true.
This is best used as an alternative to Wrap when deriving an error from a sentinel error. If there is an underlying error it may be used as the cause (with the same effect as Wrap. When creating a new error (not due to an underlying error) nil may be passed as the cause. In that case the result is a sentinel error enriched with context. For such a purpose this is better than Wrap, since Wrap would retain any irrelevant context possibly attached to the sentinel error and store a redundant message string.
Example ¶
package main import ( "errors" "fmt" "io" "github.com/scionproto/scion/pkg/private/serrors" ) func main() { // ErrNoProgress is a sentinel error defined at package scope. cause is an error from a lower // layer, based on ErrNoSpace, with an more specific message. var cause = fmt.Errorf("sd0 unresponsive: %w", io.ErrNoProgress) // ErrDB is a sentinel error defined at package scope in the upper layer. var ErrDB = errors.New("db") wrapped := serrors.Join(ErrDB, cause, "ctx", 1) // Now we can identify specific errors: fmt.Println(errors.Is(wrapped, io.ErrNoProgress)) fmt.Println(errors.Is(wrapped, cause)) // But we can also identify the broader error class ErrDB: fmt.Println(errors.Is(wrapped, ErrDB)) fmt.Printf("\n%v", wrapped) }
Output: true true true db {ctx=1}: sd0 unresponsive: multiple Read calls return no data or error
func JoinNoStack ¶ added in v0.12.0
JoinNoStack behaves like Join except that no stack dump is added regardless of cause's underlying type.
Example ¶
package main import ( "fmt" "github.com/scionproto/scion/pkg/private/serrors" ) func main() { // BrokenPacket is a sentinel error defined at package scope. var brokenPacket = serrors.New("invalid packet") // ErrBadL4 is a sentinel error defined at package scope. var ErrBadL4 = serrors.New("Unsupported L4 protocol") addedCtx := serrors.JoinNoStack(brokenPacket, ErrBadL4, "type", "SCTP") fmt.Println(addedCtx) }
Output: invalid packet {type=SCTP}: Unsupported L4 protocol
func New ¶
New creates a new basicError with the given message and context, plus a stack dump. It returns a pointer as the underlying type of the error interface object. Avoid using this in performance-critical code: it is the most expensive variant. If used to construct other errors, such as with Join, the embedded stack trace and context serve no purpose. Therefore, to make sentinel errors, errors.New() should be preferred.
Example ¶
package main import ( "errors" "fmt" "github.com/scionproto/scion/pkg/private/serrors" ) func main() { err1 := serrors.New("errtxt") err2 := serrors.New("errtxt") // Self equality always works: fmt.Println(errors.Is(err1, err1)) fmt.Println(errors.Is(err2, err2)) // On the other hand different errors with same text should not be "equal". // That is to prevent that errors with same message in different packages // with same text are seen as the same thing: fmt.Println(errors.Is(err1, err2)) }
Output: true true false
func Wrap ¶
Wrap returns an error that associates the given error, with the given cause (an underlying error) unless nil, and the given context.
A stack dump is added unless cause is a basicError or joinedError (in which case it is assumed to contain a stack dump).
The returned error supports Is. Is(cause) returns true.
This is best used when adding context to an error that already has some. The existing error is used as the cause; all of its existing context and stack trace are preserved for printing and logging. The new context is attached to the new error.
Passing nil as the cause is legal but of little use. In that case, prefer New. The only difference is the underlying type of the returned interface.
To enrich a sentinel error with context only, do not use
Wrap("dummy message", sentinel, ...)
instead use Join
Join(sentinel, nil, ...)
Wrap may be useful to enrich sentinel errors if the main message needs to be different than that supplied by the sentinel error.
Example ¶
package main import ( "errors" "fmt" "github.com/scionproto/scion/pkg/private/serrors" ) func main() { // ErrNoSpace is an error defined at package scope. It should be is an error from lower layers, // with some context already attached. var ErrNoSpace = serrors.New("no space", "dev", "sd0") wrappedErr := serrors.Wrap("wrap with more context", ErrNoSpace, "ctx", 1) fmt.Println(errors.Is(wrappedErr, ErrNoSpace)) fmt.Printf("\n%v", wrappedErr) }
Output: true wrap with more context {ctx=1}: no space {dev=sd0}
func WrapNoStack ¶ added in v0.12.0
WrapNoStack behaves like Wrap, except that no stack dump is added, regardless of cause's underlying type.
Example ¶
package main import ( "errors" "fmt" "github.com/scionproto/scion/pkg/private/serrors" ) func main() { // ErrBadL4 is a sentinel defined at package scope. var ErrBadL4 = errors.New("Unsupported L4 protocol") addedCtx := serrors.WrapNoStack("parsing packet", ErrBadL4, "type", "SCTP") fmt.Println(addedCtx) }
Output: parsing packet {type=SCTP}: Unsupported L4 protocol
Types ¶
type Frame ¶
type Frame uintptr
Frame represents a program counter inside a stack frame. For historical reasons if Frame is interpreted as a uintptr its value represents the program counter + 1.
func (Frame) Format ¶
Format formats the frame according to the fmt.Formatter interface.
%s source file %d source line %n function name %v equivalent to %s:%d
Format accepts flags that alter the printing of some verbs, as follows:
%+s function name and path of source file relative to the compile time GOPATH separated by \n\t (<funcname>\n\t<path>) %+v equivalent to %+s:%d
func (Frame) MarshalText ¶
MarshalText formats a stacktrace Frame as a text string. The output is the same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
type List ¶
type List []error
List is a slice of errors.
func (List) MarshalLogArray ¶
func (e List) MarshalLogArray(ae zapcore.ArrayEncoder) error
MarshalLogArray implements zapcore.ArrayMarshaller for nicer logging format of error lists.
type StackTrace ¶
type StackTrace []Frame
StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
func (StackTrace) Format ¶
func (st StackTrace) Format(s fmt.State, verb rune)
Format formats the stack of Frames according to the fmt.Formatter interface.
%s lists source files for each Frame in the stack %v lists the source file and line number for each Frame in the stack
Format accepts flags that alter the printing of some verbs, as follows:
%+v Prints filename, function, and line number for each Frame in the stack.