Files
bj_power/bj_power_mes/common/errorx/errors.go
T

292 lines
6.0 KiB
Go
Raw Normal View History

package errorx
import (
"fmt"
"io"
"strings"
)
type ServiceError interface {
Code() code
Error() string
}
type ServiceFieldError interface {
ServiceError
Field() string
}
type ServiceFieldErrors interface {
Errors() []error
}
// New returns an error with the supplied message.
// New also records the stack trace at the point it was called.
func New(code code, message ...string) error {
msg := strings.Join(message, " ")
return &fundamental{
code: code,
msg: msg,
stack: callers(),
}
}
func NewDirectError(message ...string) error {
return New(DirectErrCode, message...)
}
// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
// Errorf also records the stack trace at the point it was called.
func Errorf(code code, format string, args ...interface{}) error {
return &fundamental{
code: code,
msg: fmt.Sprintf(format, args...),
stack: callers(),
}
}
// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
code code
msg string
*stack
}
func (f *fundamental) Code() code { return f.code }
func (f *fundamental) Error() string { return f.msg }
func (f *fundamental) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
_, _ = io.WriteString(s, fmt.Sprintf("%d", f.code))
_, _ = io.WriteString(s, f.msg)
f.stack.Format(s, verb)
return
}
fallthrough
case 's':
_, _ = io.WriteString(s, f.msg)
case 'q':
_, _ = fmt.Fprintf(s, "%q", f.msg)
}
}
func NewFieldError(field string, message string) error {
return &fieldError{
fundamental: fundamental{
code: RequestParamInvalidWithField,
msg: message,
},
field: field,
}
}
func NewFieldErrorf(field string, format string, args ...interface{}) error {
return &fieldError{
fundamental: fundamental{
code: RequestParamInvalidWithField,
msg: fmt.Sprintf(format, args...),
},
field: field,
}
}
type fieldError struct {
fundamental
field string
}
func (f *fieldError) Code() code { return f.code }
func (f *fieldError) Error() string { return f.msg }
func (f *fieldError) Field() string { return f.field }
func NewFieldErrors(fields map[string]string) error {
err := &fieldErrors{
fundamental: fundamental{
code: RequestParamInvalidWithField,
},
}
for field, msg := range fields {
err.errors = append(err.errors, NewFieldError(field, msg))
}
return err
}
type fieldErrors struct {
fundamental
errors []error
}
func (f *fieldErrors) Errors() []error { return f.errors }
// WithStack annotates err with a stack trace at the point WithStack was called.
// If err is nil, WithStack returns nil.
func WithStack(err error, code code) error {
if err == nil {
return nil
}
return &withStack{
err,
code,
callers(),
}
}
type withStack struct {
error
code
*stack
}
func (w *withStack) Code() code { return w.code }
func (w *withStack) Cause() error { return w.error }
// Unwrap provides compatibility for Go 1.13 error chains.
func (w *withStack) Unwrap() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
_, _ = fmt.Fprintf(s, "%+v", w.Cause())
_, _ = io.WriteString(s, fmt.Sprintf(" code: %d", w.code))
w.stack.Format(s, verb)
return
}
fallthrough
case 's':
_, _ = io.WriteString(s, w.Error())
case 'q':
_, _ = fmt.Fprintf(s, "%q", w.Error())
}
}
// Wrap returns an error annotating err with a stack trace
// at the point Wrap is called, and the supplied message.
// If err is nil, Wrap returns nil.
func Wrap(err error, code code, message string) error {
if err == nil {
return nil
}
err = &withMessage{
code: code,
cause: err,
msg: message,
}
return &withStack{
err,
code,
callers(),
}
}
// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is called, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, code code, format string, args ...interface{}) error {
if err == nil {
return nil
}
err = &withMessage{
code: code,
cause: err,
msg: fmt.Sprintf(format, args...),
}
return &withStack{
err,
code,
callers(),
}
}
// WithMessage annotates err with a new message.
// If err is nil, WithMessage returns nil.
func WithMessage(err error, code uint32, message string) error {
if err == nil {
return nil
}
return &withMessage{
code: code,
cause: err,
msg: message,
}
}
// WithMessagef annotates err with the format specifier.
// If err is nil, WithMessagef returns nil.
func WithMessagef(err error, code uint32, format string, args ...interface{}) error {
if err == nil {
return nil
}
return &withMessage{
code: code,
cause: err,
msg: fmt.Sprintf(format, args...),
}
}
type withMessage struct {
code code
cause error
msg string
}
func (w *withMessage) Code() code {
return w.code
}
func (w *withMessage) Error() string {
return fmt.Sprintf("%d", w.code) + ": " + w.msg + ": " + w.cause.Error()
}
func (w *withMessage) Cause() error { return w.cause }
// Unwrap provides compatibility for Go 1.13 error chains.
func (w *withMessage) Unwrap() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
_, _ = fmt.Fprintf(s, "%+v\n", w.Cause())
_, _ = io.WriteString(s, fmt.Sprintf("code: %d ", w.code))
_, _ = io.WriteString(s, fmt.Sprintf(", msg: %s\n", w.msg))
return
}
fallthrough
case 's', 'q':
_, _ = io.WriteString(s, w.Error())
}
}
// Cause returns the underlying cause of the error, if possible.
// An error value has a cause if it implements the following
// interface:
//
// type causer interface {
// Cause() error
// }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func Cause(err error) error {
type causer interface {
Cause() error
}
for err != nil {
cause, ok := err.(causer)
if !ok {
break
}
err = cause.Cause()
}
return err
}