errors

package module
v0.0.0-...-509c1e4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 22, 2023 License: Apache-2.0 Imports: 14 Imported by: 5

README

errors

like pkg/errors, but can wrap and retrieve anything

Requirements

Usage

  • error definition
var source = "your_package_path"
var NotFound = NewMetaError(source, "not_found(5)", "not found", status(http.StatusNotFound))
  • error override
import "github.com/ccmonky/errors"

errors.NotFound = errors.With(errors.NotFound, errors.StatusOption(400), ...)
  • error(meta) suggestion
err := errors.New("xxx")
err = errors.WithError(err, errors.NotFound)
  • error(meta) fallback
// NOTE: do notknow whether error has carried meta
err = errors.Adapt(err, errors.Unknown)
  • error enforce
// NOTE: attach errors.Unavailable on err whether err has carried meta or not
err = errors.WithError(err, errors.Unavailable)
  • error attr
// define attr
CountAttr := errors.NewAttr[int]("count", errors.WithAttrDescription("xxx count as an attr"))

// use attr
err = CountAttr.With(errors.New("xxx"), 100)
// or
err = errors.With(errors.New("xxx"), CountAttr.Option(100))
// get count
count := CountAttr.Get(err)
count == 100 // true
  • error wrap
err := errors.New("xxx")
err = errors.WithError(err, errors.NotFound)
err = errors.WithMessage(err, "wrapper")
err = errors.WithCaller(err, "caller...")
err = errors.WithSatus(err, 206)
//...
  • error unwrap
// unwrap error
originErr := errors.New("xxx")
err := Cause(errors.With(err, errors.ErrorOption(errors.NotFound), errors.StatusOption(409), errors.CallerOption("caller...")))
log.Print(originErr == err) // true

// unwrap attr
errors.StatusAttr.Get(err) == 409
errors.ErrorAttr.Get(err) == errors.NotFound
// NOTE: you can also get attr in attr's value(as long as it implement `interface{ Value(any)any}`, like this
errors.MetaAttr.Get(err).Code() == "not_found(5)" 
  • error assert
originErr := errors.New("xxx")
err := errors.WithError(originErr, errors.NotFound)
err = errors.WithMessage(err, "xxx")

errors.Is(err, originErr)                 // true
errors.Is(err, errors.NotFound)           // true
errors.Is(err, errors.AlreadyExists)      // false

errors.IsCauseOrLatestMetaError(err, originErr)            // true
errors.IsCauseOrLatestMetaError(err, errors.NotFound)      // true
errors.IsCauseOrLatestMetaError(err, errors.AlreadyExists) // false

err = errors.WithError(err, errors.AlreadyExists)
errors.Is(err, originErr)                 // true
errors.Is(err, errors.NotFound)           // true
errors.Is(err, errors.AlreadyExists)      // true

errors.IsCauseOrLatestMetaError(err, originErr)            // true
errors.IsCauseOrLatestMetaError(err, errors.NotFound)      // false
errors.IsCauseOrLatestMetaError(err, errors.AlreadyExists) // true

err = errors.Adapt(err, errors.Unknown)
errors.Is(err, originErr)                 // true
errors.Is(err, errors.NotFound)           // true
errors.Is(err, errors.AlreadyExists)      // true
errors.Is(err, errors.Unknown)            // false

errors.IsCauseOrLatestMetaError(err, originErr)            // true
errors.IsCauseOrLatestMetaError(err, errors.NotFound)      // false
errors.IsCauseOrLatestMetaError(err, errors.AlreadyExists) // true
errors.IsCauseOrLatestMetaError(err, errors.Unknown)       // false
  • error collection
err := errors.WithError(errors.New("e1"), errors.New("e2"))
err = errors.WithError(err, errors.New("e3"))
log.Println(errors.GetAllErrors(err))
// Output: [e1 e2 e3]
  • error attr extraction
err := errors.WithError(errors.New("xxx"), errors.NotFound)
err = errors.WithMessage(err, "wrapper1")
err = errors.WithCaller(err, "caller1")
err = errors.WithError(err, errors.AlreadyExists)
err = errors.WithMessage(err, "wrapper2")
err = errors.WithCaller(err, "caller2")
var ki int
err = errors.WithValue(err, &ki, "will not in map")
var ks = "ks"
err = errors.WithValue(err, &ks, "ks")

// errors.Map(err): get all values
// NOTE: error and *Meta will be flatten
m := errors.Map(err)
assert.Equalf(t, 10, len(m), "m length")
assert.Equalf(t, "myapp", m["meta.app"], "meta.app")
assert.Equalf(t, "github.com/ccmonky/errors", m["meta.source"], "meta.source")
assert.Equalf(t, "already_exists(6)", m["meta.code"], "meta.code")
assert.Equalf(t, "already exists", m["meta.message"], "meta.message")
assert.Equalf(t, "ks", m["ks"], "ks")
assert.Equalf(t, "wrapper2", m["msg"], "msg")
assert.Equalf(t, "caller2", m["caller"], "caller")
assert.Equalf(t, 409, m["status"], "status")
assert.Equalf(t, "meta={source=errors;code=already_exists(6)}:status={409}", fmt.Sprint(m["error"]), "error")
assert.Equalf(t, "source=errors;code=already_exists(6)", fmt.Sprint(m["meta"]), "meta")

// errors.Attrs: get values of specified attrs
// NOTE: error and *Meta will be flatten
m := errors.NewAttrs(errors.ErrorAttr, errors.MessageAttr).Map(err)
assert.Equalf(t, 8, len(m), "m length")
assert.Equalf(t, "myapp", m["meta.app"], "meta.app")
assert.Equalf(t, "github.com/ccmonky/errors", m["meta.source"], "meta.source")
assert.Equalf(t, "already_exists(6)", m["meta.code"], "meta.code")
assert.Equalf(t, "already exists", m["meta.message"], "meta.message")
assert.Equalf(t, "wrapper2", m["msg"], "msg")
assert.Equalf(t, 409, m["status"], "status")
assert.Equalf(t, "meta={source=errors;code=already_exists(6)}:status={409}", fmt.Sprint(m["error"]), "error")
assert.Equalf(t, "source=errors;code=already_exists(6)", fmt.Sprint(m["meta"]), "meta")
  • error admin
// list all registered meta errors(generated by `NewMetaError`)
mes, _ := errors.AllMetaErrors()
log.Println(string(data))

// list all registered error attrs(generated by `NewAttr`)
attrs, _ := errors.AllAttrs()
log.Println(string(data))

meta errors marshal result like this:

{
    ":github.com/ccmonky/errors:aborted(10)": {
        "error": {
            "key": "meta",
            "value": {
                "meta.app": "myapp",
                "meta.code": "aborted(10)",
                "meta.message": "operation was aborted",
                "meta.source": "github.com/ccmonky/errors"
            }
        },
        "key": "status",
        "value": 409
    },
    ":github.com/ccmonky/errors:already_exists(6)": {
        "error": {
            "key": "meta",
            "value": {
                "meta.app": "myapp",
                "meta.code": "already_exists(6)",
                "meta.message": "already exists",
                "meta.source": "github.com/ccmonky/errors"
            }
        },
        "key": "status",
        "value": 409
    }
    // ...
}

attrs json marshal result like this:

{
    "caller:0xc000110ed0": {
        "description": "caller as an attr",
        "has_default_value_func": false,
        "name": "caller",
        "type": "string"
    },
    "ctx:0xc000110dd0": {
        "description": "context.Context as an attr",
        "has_default_value_func": false,
        "name": "ctx",
        "type": "context.Context"
    },
    "error:0xc000110d70": {
        "description": "error as an attr",
        "has_default_value_func": false,
        "name": "error",
        "type": "error"
    },
    "meta:0xc000110e10": {
        "description": "meta as an attr",
        "has_default_value_func": false,
        "name": "meta",
        "type": "*errors.Meta"
    },
    "msg:0xc000110e50": {
        "description": "message as an attr",
        "has_default_value_func": false,
        "name": "msg",
        "type": "string"
    },
    "stack:0xc000110f10": {
        "description": "github.com/pkg/errors.stack as an attr",
        "has_default_value_func": false,
        "name": "stack",
        "type": "*errors.stack"
    },
    "status:0xc000110e90": {
        "description": "http status as an attr",
        "has_default_value_func": true,
        "name": "status",
        "type": "int"
    }
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrorAttr used to attach another error on input error, usually used to attach meta error
	ErrorAttr = NewAttr[error]("error", WithAttrDescription("error as an attr"))

	// CtxAttr used to attach context.Context on error
	CtxAttr = NewAttr[context.Context]("ctx", WithAttrDescription("context.Context as an attr"))

	// Meta used to attach meta to Error
	MetaAttr = NewAttr[*Meta]("meta", WithAttrDescription("meta as an attr"))

	// Message used to attach message to Error
	MessageAttr = NewAttr[string]("msg", WithAttrDescription("message as an attr"))

	// Status used as meta value stands for http status,
	// Status.Get returns http status if err is MetaError with status attached,
	// otherwise return 500 if err != nil else return 200
	StatusAttr = NewAttr[int]("status",
		WithAttrDefault(func(err error) any {
			if err != nil {
				return http.StatusInternalServerError
			}
			return http.StatusOK
		}),
		WithAttrDescription("http status as an attr"))

	// Caller used as meta value stands for runtime.Caller info
	CallerAttr = NewAttr[string]("caller", WithAttrDescription("caller as an attr"))

	// Stack attach `github.com/pkg/errors.stack` on error
	StackAttr = NewAttr[*stack]("stack", WithAttrDescription("github.com/pkg/errors.stack as an attr"))
)
View Source
var (
	OK                 = NewMetaError(source, "success(0)", "success", status(http.StatusOK))
	Canceled           = NewMetaError(source, "canceled(1)", "client cancelled request", status(499))
	Unknown            = NewMetaError(source, "unknown(2)", "server throws an exception", status(http.StatusInternalServerError))
	InvalidArgument    = NewMetaError(source, "invalid_argument(3)", "invalid argument", status(http.StatusBadRequest))
	DeadlineExceeded   = NewMetaError(source, "deadline_exceeded(4)", "timeout", status(http.StatusGatewayTimeout))
	NotFound           = NewMetaError(source, "not_found(5)", "not found", status(http.StatusNotFound))
	AlreadyExists      = NewMetaError(source, "already_exists(6)", "already exists", status(http.StatusConflict))
	PermissionDenied   = NewMetaError(source, "permission_denied(7)", "permission denied", status(http.StatusForbidden))
	ResourceExhausted  = NewMetaError(source, "resource_exhausted(8)", "resource exhauste", status(http.StatusTooManyRequests))
	FailedPrecondition = NewMetaError(source, "failed_precondition(9)", "failed precondition", status(http.StatusBadRequest))
	Aborted            = NewMetaError(source, "aborted(10)", "operation was aborted", status(http.StatusConflict))
	OutOfRange         = NewMetaError(source, "out_of_range(11)", "operation was attempted past the valid range", status(http.StatusBadRequest))
	Unimplemented      = NewMetaError(source, "unimplemented(12)", "unimplemented", status(http.StatusNotImplemented))
	Internal           = NewMetaError(source, "internal(13)", "internal error", status(http.StatusInternalServerError))
	Unavailable        = NewMetaError(source, "unavailable(14)", "service is unavailable", status(http.StatusServiceUnavailable))
	DataLoss           = NewMetaError(source, "data_loss(15)", "unrecoverable data loss or corruption", status(http.StatusInternalServerError))
	Unauthenticated    = NewMetaError(source, "unauthenticated(16)", "unauthenticated", status(http.StatusForbidden))
)

refer to `https://grpc.github.io/grpc/core/md_doc_statuscodes.html`

View Source
var (
	// New is `errors.New`
	New = errors.New

	// Errorf is `fmt.Errorf`
	Errorf = fmt.Errorf
)

standard

View Source
var (
	MetaAttrAppFieldName     string = "meta.app"
	MetaAttrSourceFieldName  string = "meta.source"
	MetaAttrCodeFieldName    string = "meta.code"
	MetaAttrMessageFieldName string = "meta.message"
)
View Source
var (
	WithError   = ErrorAttr.With
	ErrorOption = ErrorAttr.Option

	WithMeta   = MetaAttr.With
	MetaOption = MetaAttr.Option

	WithCtx   = CtxAttr.With
	CtxOption = CtxAttr.Option

	WithStatus   = StatusAttr.With
	StatusOption = StatusAttr.Option

	WithCaller   = CallerAttr.With
	CallerOption = CallerAttr.Option

	StackOption   = StackAttr.Option
	MessageOption = MessageAttr.Option
)

helper functions for attrs

View Source
var (
	// WithMessage imitate `github.com/pkg/errors.WithMessage` but implemented with `Message` attr
	WithMessage = MessageAttr.With
)

github.com/pkg/errros

Functions

func Adapt

func Adapt(err error, guard MetaError) error

Adapt defaultAdapter's Adapt

func AllAttrs

func AllAttrs() map[string]any

AllAttrs return all registered Attrs

func AllMetaErrors

func AllMetaErrors() map[metaID]MetaError

AllMetaErrors return all registered MetaErrors as a map with key is `app:source:code`

func AppName

func AppName() string

AppName return current app name, use `SetAppName` or `inithook.AppName` to set app name

func As

func As(err error, target interface{}) bool

As finds the first error in err's chain that matches target, and if so, sets target to that error value and returns true.

The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.

An error matches target if the error's concrete value is assignable to the value pointed to by target, or if the error has a method As(interface{}) bool such that As(target) returns true. In the latter case, the As method is responsible for setting target.

As will panic if target is not a non-nil pointer to either a type that implements error, or to any interface type. As returns false if err is nil.

func Cause

func Cause(err error) error

Cause returns the underlying cause of the error, if possible. An error value has a cause if it implements the following interface:

type unwrap interface {
       Unwrap() error
}

If the error does not implement unwrap, the original error will be returned. If the error is nil, nil will be returned without further investigation.

func Get

func Get(m error, key any) any

func GetAll

func GetAll(m error, key any) []any

GetAll get all values of key recursively

func GetAllErrors

func GetAllErrors(err error) []error

GetAllErrors get all errors contained in err, all errors attached by `WithError` + Cause

func GetApp

func GetApp(err error) string

GetApp get app name from error if err is ContextError, otherwise return empty string

func GetCode

func GetCode(err error) string

GetCode returns error code if err is ContextError, otherwise return Unknown.Code() if err != nil else return Ok.Code()

func GetMessage

func GetMessage(err error) string

GetMessage returns error message if err is ContextError, otherwise return Unknown.Message() if err != nil else return Ok.Message()

func GetSource

func GetSource(err error) string

GetSource returns error source if err is ContextError, otherwise return empty string

func Is

func Is(err, target error) bool

Is reports whether any error in err's chain matches target.

The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.

An error is considered to match a target if it is equal to that target or if it implements a method Is(error) bool such that Is(target) returns true.

func IsCauseOrLatestMetaError

func IsCauseOrLatestMetaError(err, target error) bool

IsCauseOrLatest used to test if err is a error, return true only if target == Cause(err) || target == GetLatestMetaError(err)

func Map

func Map(err error) map[string]any

Map unwrap all to get `name:value` map of all attrs

NOTE: 1. unlike Get or `GetAll`, Map do not traversal the value of `valueError` 2. result will not contain the value if key type is not *string 3. if meta exists, then app, source and message fields will be added into result 4. if key's name duplicates, the result will only contains the latest value

func MetaID

func MetaID(app, source, code string) string

MetaID returns a unique id of `Meta`

func NewAttrKey

func NewAttrKey(name string) any

NewAttrKey used to creates a new Attr's internal key https://github.com/golang/go/issues/33742

func RegisterMetaError

func RegisterMetaError(me MetaError) error

RegisterMetaError register MetaError into metaErrors registry, return error is exists

func SetAppName

func SetAppName(appNew string) error

SetAppName set app name and register Meta to new app namespace

func SetFormatMode

func SetFormatMode(mode FormatMode)

SetFormatMode set mode for formatting the `valueError`

func Unwrap

func Unwrap(err error) error

Unwrap returns the result of calling the Unwrap method on err, if err's type contains an Unwrap method returning error. Otherwise, Unwrap returns nil.

func With

func With(err error, opts ...Option) error

With used to attach multiple values on error with options

func WithErrorOptions

func WithErrorOptions(err, optsErr error) error

WithErrorOptions

func WithMessagef

func WithMessagef(err error, format string, args ...any) error

WithMessage imitate `github.com/pkg/errors.WithMessagef` but implemented with `Message` attr

func WithStack

func WithStack(err error) error

WithStack imitate `github.com/pkg/errors.WithStack` but implemented with `Stack` attr

func WithValue

func WithValue(err error, key, val any) error

WithValue returns a copy of parent in which the value associated with key is val.

The provided key must be comparable and should not be of type string or any other built-in type to avoid collisions between packages using meta. Users of WithValue should define their own types for keys. To avoid allocating when assigning to an interface{}, context keys often have concrete type struct{}. Alternatively, exported context key variables' static type should be a pointer or interface.

func Wrap

func Wrap(err error, message string) error

Wrap imitate `github.com/pkg/errors.Wrap` but implemented with `Message` & `Stack` attrs

func Wrapf

func Wrapf(err error, format string, args ...interface{}) error

Wrapf imitate `github.com/pkg/errors.Wrapf` but implemented with `Message` & `Stack` attrs

Types

type Adapter

type Adapter interface {
	Adapt(err error, guard MetaError) error
}

Adapter provides `Adapt` mainly to support suggestive error, error delivery path, error overrides ...

func NewAdapter

func NewAdapter(opts ...AdapterOption) Adapter

NewAdapter creates a new Adapter, usually no need to create a new one, just use the default `Adapt` function is enough

type AdapterOption

type AdapterOption func(*adapter)

AdapterOption default adapter implementation control option

func WithAddCaller

func WithAddCaller() AdapterOption

WithAddCaller add caller for default adapter implementation

func WithCallerFunc

func WithCallerFunc(fn func(int) string) AdapterOption

WithCallerFunc specify the caller func which returns the caller info for default adapter implementation

func WithCallerSkip

func WithCallerSkip(skip int) AdapterOption

WithCallerSkip specify caller skip depth for default adapter implementation

func WithDefaultOptions

func WithDefaultOptions(opts ...Option) AdapterOption

WithDefaultOptions specify the default meta options to append when `Adapt` for default adapter implementation

func WithMetaMappingFunc

func WithMetaMappingFunc(fn func(*Meta) MetaError) AdapterOption

WithMetaMappingFunc specify the default meta mappping function

type Attr

type Attr[T any] struct {
	// contains filtered or unexported fields
}

Attr defines an value extension for `Meta`, it can create an MetaOption by `With` method and get the value by `Get` method

Usage:

// define a new Attr
var Status = NewAttr[int](WithAttrDefault(func(err error){
	if err != nil {
		return http.StatusInternalServerError
	}
	return http.StatusOK
}))

// use `Attr.With`
var NotFound = NewMetaError("not_found(5)", "not found", source, Status.With(http.StatusNotFound))

// use `Attr.Get`
log.Println(Status.Get(err))

func GetAttrByKey

func GetAttrByKey[T any](key any) (*Attr[T], error)

GetAttrByKey get attr by type and key from attrs registry

func GetAttrByName

func GetAttrByName[T any](name string) (*Attr[T], error)

GetAttrByName get attr by type and name from attrs registry NOTE: the result may not be what you want, since the same name is allowed to be overwritten by default.

func MustGetAttrByKey

func MustGetAttrByKey[T any](key any) *Attr[T]

MustGetAttrByKey get attr by key, panic if not found

func MustGetAttrByName

func MustGetAttrByName[T any](name string) *Attr[T]

MustGetAttrByKey get attr by name, panic if not found

func NewAttr

func NewAttr[T any](name string, opts ...AttrOption) *Attr[T]

NewAttr creates a new `Attr`

func (*Attr[T]) Description

func (a *Attr[T]) Description() string

Description returns the description of Attr

func (*Attr[T]) Get

func (a *Attr[T]) Get(err error) T

Get get value specified by Attr's internal key from error if implement MetaError, otherwise return default value

func (*Attr[T]) GetAll

func (a *Attr[T]) GetAll(err error) []T

GetAll get all values specified by Attr's internal key from error

func (*Attr[T]) GetAny

func (a *Attr[T]) GetAny(err error) any

GetAny return attr value of err as any

func (*Attr[T]) Key

func (a *Attr[T]) Key() any

Key returns the internal key of Attr

func (*Attr[T]) MarshalJSON

func (a *Attr[T]) MarshalJSON() ([]byte, error)

func (*Attr[T]) Name

func (a *Attr[T]) Name() string

Key returns the internal key of Attr

func (*Attr[T]) Option

func (a *Attr[T]) Option(value T) Option

func (*Attr[T]) With

func (a *Attr[T]) With(err error, value T) error

type AttrInterface

type AttrInterface interface {
	Key() any
	Name() string
	Description() string
	GetAny(error) any
}

AttrInterface abstract Attr's minimal interface used for `Attrs`

type AttrOption

type AttrOption func(*AttrOptions)

AttrOption defines `Attr` constructor option

func WithAttrDefault

func WithAttrDefault(fn func(error) any) AttrOption

WithAttrDefault specify `Attr` default value function

func WithAttrDescription

func WithAttrDescription(desc string) AttrOption

WithAttrDefault specify `Attr` description

func WithAttrDoNotRegister

func WithAttrDoNotRegister(noReg bool) AttrOption

WithAttrDoNotRegister specify `Attr` DoNotRegister

func WithAttrPanicOnDuplicateNames

func WithAttrPanicOnDuplicateNames(noPanic bool) AttrOption

WithAttrPanicOnDuplicateNames specify `Attr` PanicOnDuplicateNames

type AttrOptions

type AttrOptions struct {
	// DefaultValueFunc Attr's default value function
	DefaultValueFunc func(error) any

	// Description Attr's description
	Description string

	// DoNotRegister do not register the new created attr into registry, default to false
	DoNotRegister bool

	// PanicOnDuplicateNames duplicate names are allowed by default
	PanicOnDuplicateNames bool
}

AttrOptions defines `Attr` constructor options

type Attrs

type Attrs []AttrInterface

Attrs is a group of AttrInterface, which usually used to extractor attrs's values

func NewAttrs

func NewAttrs(attrs ...AttrInterface) Attrs

NewAttrs create new Attrs

func (Attrs) Map

func (as Attrs) Map(err error) map[string]any

Map returns the name:value map of Attrs according to Attrs's order

type Error

type Error interface {
	error

	// Value get value specified by key in the Meta
	Value(key any) any
}

Error is a error with context values

func Empty

func Empty() Error

Empty returns a non-nil, empty Error. It has no values. It is typically used by the main function, initialization, and tests, and as the top-level Error when define a new Error.

type FormatMode

type FormatMode int

FormatMode used to format Meta value wrapper

const (
	// Default format value meta as `meta.String():key=value`
	Default FormatMode = iota

	// Simplified format value meta as `meta.String():*=*`
	Simplified

	// Default format value meta as `meta.String():key=*`
	NoValue
)

type Meta

type Meta struct {
	// contains filtered or unexported fields
}

func (*Meta) App

func (e *Meta) App() string

func (*Meta) Code

func (e *Meta) Code() string

func (*Meta) Format

func (e *Meta) Format(s fmt.State, verb rune)

Format implement fmt.Formatter

func (*Meta) ID

func (e *Meta) ID() string

func (*Meta) MarshalJSON

func (e *Meta) MarshalJSON() ([]byte, error)

func (*Meta) Message

func (e *Meta) Message() string

func (*Meta) Source

func (e *Meta) Source() string

func (*Meta) String

func (e *Meta) String() string

type MetaError

type MetaError interface {
	error
	App() string
	Source() string
	Code() string
	Message() string
}

func GetLatestMetaError

func GetLatestMetaError(err error) MetaError

GetLatestMetaError return the latest MetaError in err, returns nil if not found

func GetMetaError

func GetMetaError(id string) MetaError

GetMetaError get Meta according to app, source and code

func NewMetaError

func NewMetaError(source, code, msg string, opts ...Option) MetaError

NewMetaError define a new error with meta attached

type Option

type Option func(error) error

Option used to attach value on error

func Options

func Options(err error) []Option

Options used to get `[]Option` attached on err

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL