Redmage/pkg/errs/errs.go

178 lines
3.5 KiB
Go
Raw Normal View History

2024-04-06 01:22:00 +07:00
package errs
import (
"context"
"errors"
2024-04-06 01:33:03 +07:00
"fmt"
2024-04-06 01:22:00 +07:00
"log/slog"
"reflect"
"strings"
2024-04-06 21:11:22 +07:00
2024-04-06 22:09:17 +07:00
"github.com/tigorlazuardi/redmage/pkg/caller"
"github.com/tigorlazuardi/redmage/pkg/log"
2024-04-06 01:22:00 +07:00
)
type Error interface {
error
Message(msg string, args ...any) Error
GetMessage() string
Code(status int) Error
GetCode() int
2024-04-06 21:11:22 +07:00
Caller(pc caller.Caller) Error
GetCaller() caller.Caller
2024-04-06 01:22:00 +07:00
Details(...any) Error
GetDetails() []any
Log(ctx context.Context) Error
}
var _ Error = (*Err)(nil)
type Err struct {
2024-04-06 21:11:22 +07:00
message string
2024-04-06 01:22:00 +07:00
code int
2024-04-06 21:11:22 +07:00
caller caller.Caller
2024-04-06 01:22:00 +07:00
details []any
origin error
}
func (er *Err) LogValue() slog.Value {
values := make([]slog.Attr, 0, 5)
2024-04-06 21:11:22 +07:00
if er.message != "" {
values = append(values, slog.String("message", er.message))
2024-04-06 01:22:00 +07:00
}
if er.code != 0 {
values = append(values, slog.Int("code", er.code))
}
2024-04-06 21:11:22 +07:00
if er.caller.PC != 0 {
values = append(values, slog.Any("origin", er.caller))
2024-04-06 01:22:00 +07:00
}
if len(er.details) > 0 {
values = append(values, slog.Group("details", er.details...))
}
2024-04-06 21:11:22 +07:00
if er.origin == nil {
values = append(values, slog.Any("error", er.origin))
} else {
errGroupValues := make([]slog.Attr, 0, 3)
errGroupValues = append(errGroupValues, slog.String("type", reflect.TypeOf(er.origin).String()))
if lv, ok := er.origin.(slog.LogValuer); ok {
errGroupValues = append(errGroupValues, slog.Attr{Key: "data", Value: lv.LogValue()})
} else {
errGroupValues = append(errGroupValues, slog.String("message", er.origin.Error()), slog.Any("data", er.origin))
}
values = append(values, slog.Attr{Key: "error", Value: slog.GroupValue(errGroupValues...)})
}
2024-04-06 01:22:00 +07:00
return slog.GroupValue(values...)
}
func (er *Err) Error() string {
var (
s = strings.Builder{}
source = er.origin
2024-04-06 01:33:03 +07:00
msg = source.Error()
unwrap = errors.Unwrap(source)
2024-04-06 01:22:00 +07:00
)
2024-04-06 01:33:03 +07:00
if unwrap == nil {
2024-04-06 21:11:22 +07:00
if er.message != "" {
s.WriteString(er.message)
2024-04-06 01:33:03 +07:00
s.WriteString(": ")
}
s.WriteString(msg)
return s.String()
}
2024-04-06 01:22:00 +07:00
for unwrap := errors.Unwrap(source); unwrap != nil; source = unwrap {
originMsg := unwrap.Error()
2024-04-06 01:33:03 +07:00
var write string
2024-04-06 01:22:00 +07:00
if cut, found := strings.CutSuffix(msg, originMsg); found {
2024-04-06 01:33:03 +07:00
write = cut
2024-04-06 01:22:00 +07:00
} else {
2024-04-06 01:33:03 +07:00
write = msg
}
msg = originMsg
if write != "" {
s.WriteString(write)
s.WriteString(": ")
2024-04-06 01:22:00 +07:00
}
}
return s.String()
}
func (er *Err) Message(msg string, args ...any) Error {
2024-04-06 21:11:22 +07:00
er.message = fmt.Sprintf(msg, args...)
2024-04-06 01:33:03 +07:00
return er
2024-04-06 01:22:00 +07:00
}
func (er *Err) GetMessage() string {
2024-04-06 21:11:22 +07:00
return er.message
2024-04-06 01:22:00 +07:00
}
func (er *Err) Code(status int) Error {
2024-04-06 21:11:22 +07:00
er.code = status
return er
2024-04-06 01:22:00 +07:00
}
func (er *Err) GetCode() int {
2024-04-06 21:11:22 +07:00
return er.code
2024-04-06 01:22:00 +07:00
}
2024-04-06 21:11:22 +07:00
func (er *Err) Caller(pc caller.Caller) Error {
er.caller = pc
return er
2024-04-06 01:22:00 +07:00
}
2024-04-06 21:11:22 +07:00
func (er *Err) GetCaller() caller.Caller {
return er.caller
2024-04-06 01:22:00 +07:00
}
2024-04-06 21:11:22 +07:00
func (er *Err) Details(ctx ...any) Error {
er.details = ctx
return er
2024-04-06 01:22:00 +07:00
}
func (er *Err) GetDetails() []any {
2024-04-06 21:11:22 +07:00
return er.details
2024-04-06 01:22:00 +07:00
}
func (er *Err) Log(ctx context.Context) Error {
2024-04-06 21:11:22 +07:00
log.Log(ctx).Caller(er.caller).Error(er.message, "error", er)
return er
}
func Wrap(err error, message string, details ...any) Error {
return &Err{
origin: err,
details: details,
message: message,
caller: caller.New(3),
}
}
func Wrapf(err error, message string, args ...any) Error {
message = fmt.Sprintf(message, args...)
return &Err{
origin: err,
message: message,
caller: caller.New(3),
}
}
func Fail(message string, details ...any) Error {
return &Err{
origin: errors.New(message),
details: details,
caller: caller.New(3),
}
}
func Failf(message string, args ...any) Error {
return &Err{
origin: fmt.Errorf(message, args...),
caller: caller.New(3),
}
2024-04-06 01:22:00 +07:00
}