Files
QSfera/vendor/github.com/gookit/goutil/errorx/errorx.go
T
dependabot[bot]andRalf Haferkamp 0df009eae0 Bump github.com/gookit/config/v2 from 2.2.3 to 2.2.4
Bumps [github.com/gookit/config/v2](https://github.com/gookit/config) from 2.2.3 to 2.2.4.
- [Release notes](https://github.com/gookit/config/releases)
- [Commits](https://github.com/gookit/config/compare/v2.2.3...v2.2.4)

---
updated-dependencies:
- dependency-name: github.com/gookit/config/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-03 10:26:28 +01:00

340 lines
7.3 KiB
Go

// Package errorx provide an enhanced error implements for go,
// allow with stacktraces and wrap another error.
package errorx
import (
"bytes"
"errors"
"fmt"
"io"
)
// Causer interface for get first cause error
type Causer interface {
// Cause returns the first cause error by call err.Cause().
// Otherwise, will returns current error.
Cause() error
}
// Unwrapper interface for get previous error
type Unwrapper interface {
// Unwrap returns previous error by call err.Unwrap().
// Otherwise, will returns nil.
Unwrap() error
}
// XErrorFace interface
type XErrorFace interface {
error
Causer
Unwrapper
}
// Exception interface
// type Exception interface {
// XErrorFace
// Code() string
// Message() string
// StackString() string
// }
/*************************************************************
* implements XErrorFace interface
*************************************************************/
// ErrorX struct
//
// TIPS:
//
// fmt pkg call order: Format > GoString > Error > String
type ErrorX struct {
// trace stack
*stack
prev error
msg string
}
// Cause implements Causer.
func (e *ErrorX) Cause() error {
if e.prev == nil {
return e
}
if ex, ok := e.prev.(*ErrorX); ok {
return ex.Cause()
}
return e.prev
}
// Unwrap implements Unwrapper.
func (e *ErrorX) Unwrap() error {
return e.prev
}
// Format error, will output stack information.
func (e *ErrorX) Format(s fmt.State, verb rune) {
// format current error: only output on have msg
if len(e.msg) > 0 {
_, _ = io.WriteString(s, e.msg)
if e.stack != nil {
e.stack.Format(s, verb)
}
}
// format prev error
if e.prev == nil {
return
}
_, _ = s.Write([]byte("\nPrevious: "))
if ex, ok := e.prev.(*ErrorX); ok {
ex.Format(s, verb)
} else {
_, _ = s.Write([]byte(e.prev.Error()))
}
}
// GoString to GO string, contains stack information.
// printing an error with %#v will produce useful information.
func (e *ErrorX) GoString() string {
// var sb strings.Builder
var buf bytes.Buffer
_, _ = e.WriteTo(&buf)
return buf.String()
}
// Error msg string, not contains stack information.
func (e *ErrorX) Error() string {
var buf bytes.Buffer
e.writeMsgTo(&buf)
return buf.String()
}
// String error to string, contains stack information.
func (e *ErrorX) String() string {
return e.GoString()
}
// WriteTo write the error to a writer, contains stack information.
func (e *ErrorX) WriteTo(w io.Writer) (n int64, err error) {
// current error: only output on have msg
if len(e.msg) > 0 {
_, _ = w.Write([]byte(e.msg))
// with stack
if e.stack != nil {
_, _ = e.stack.WriteTo(w)
}
}
// with prev error
if e.prev != nil {
_, _ = io.WriteString(w, "\nPrevious: ")
if ex, ok := e.prev.(*ErrorX); ok {
_, _ = ex.WriteTo(w)
} else {
_, _ = io.WriteString(w, e.prev.Error())
}
}
return
}
// Message error message of current
func (e *ErrorX) Message() string {
return e.msg
}
// StackString returns error stack string of current.
func (e *ErrorX) StackString() string {
if e.stack != nil {
return e.stack.String()
}
return ""
}
// writeMsgTo write the error msg to a writer
func (e *ErrorX) writeMsgTo(w io.Writer) {
// current error
if len(e.msg) > 0 {
_, _ = w.Write([]byte(e.msg))
}
// with prev error
if e.prev != nil {
_, _ = w.Write([]byte("; "))
if ex, ok := e.prev.(*ErrorX); ok {
ex.writeMsgTo(w)
} else {
_, _ = io.WriteString(w, e.prev.Error())
}
}
}
// CallerFunc returns the error caller func. if stack is nil, will return nil
func (e *ErrorX) CallerFunc() *Func {
if e.stack == nil {
return nil
}
return FuncForPC(e.stack.CallerPC())
}
// Location information for the caller func. more please see CallerFunc
//
// Returns eg:
//
// github.com/gookit/goutil/errorx_test.TestWithPrev(), errorx_test.go:34
func (e *ErrorX) Location() string {
if e.stack == nil {
return "unknown"
}
return e.CallerFunc().Location()
}
/*************************************************************
* new error with call stacks
*************************************************************/
// New error message and with caller stacks
func New(msg string) error {
return &ErrorX{
msg: msg,
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
}
}
// Newf error with format message, and with caller stacks.
// alias of Errorf()
func Newf(tpl string, vars ...any) error {
return &ErrorX{
msg: fmt.Sprintf(tpl, vars...),
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
}
}
// Errorf error with format message, and with caller stacks
func Errorf(tpl string, vars ...any) error {
return &ErrorX{
msg: fmt.Sprintf(tpl, vars...),
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
}
}
// With prev error and error message, and with caller stacks
func With(err error, msg string) error {
return &ErrorX{
msg: msg,
prev: err,
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
}
}
// Withf error and with format message, and with caller stacks
func Withf(err error, tpl string, vars ...any) error {
return &ErrorX{
msg: fmt.Sprintf(tpl, vars...),
prev: err,
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
}
}
// WithPrev error and message, and with caller stacks. alias of With()
func WithPrev(err error, msg string) error {
return &ErrorX{
msg: msg,
prev: err,
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
}
}
// WithPrevf error and with format message, and with caller stacks. alias of Withf()
func WithPrevf(err error, tpl string, vars ...any) error {
return &ErrorX{
msg: fmt.Sprintf(tpl, vars...),
prev: err,
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
}
}
/*************************************************************
* wrap go error with call stacks
*************************************************************/
// WithStack wrap a go error with a stacked trace. If err is nil, will return nil.
func WithStack(err error) error {
if err == nil {
return nil
}
return &ErrorX{
msg: err.Error(),
// prev: err,
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
}
}
// Traced warp a go error and with caller stacks. alias of WithStack()
func Traced(err error) error {
if err == nil {
return nil
}
return &ErrorX{
msg: err.Error(),
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
}
}
// Stacked warp a go error and with caller stacks. alias of WithStack()
func Stacked(err error) error {
if err == nil {
return nil
}
return &ErrorX{
msg: err.Error(),
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
}
}
// WithOptions new error with some option func
func WithOptions(msg string, fns ...func(opt *ErrStackOpt)) error {
opt := newErrOpt()
for _, fn := range fns {
fn(opt)
}
return &ErrorX{
msg: msg,
stack: callersStack(opt.SkipDepth, opt.TraceDepth),
}
}
/*************************************************************
* helper func for wrap error without stacks
*************************************************************/
// Wrap error and with message, but not with stack
func Wrap(err error, msg string) error {
if err == nil {
return errors.New(msg)
}
return &ErrorX{
msg: msg,
prev: err,
}
}
// Wrapf error with format message, but not with stack
func Wrapf(err error, tpl string, vars ...any) error {
if err == nil {
return fmt.Errorf(tpl, vars...)
}
return &ErrorX{
msg: fmt.Sprintf(tpl, vars...),
prev: err,
}
}