Redmage/pkg/errs/errs.go

188 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 if lv, ok := er.origin.(slog.LogValuer); ok {
values = append(values, slog.Attr{Key: "error", Value: lv.LogValue()})
2024-04-06 21:11:22 +07:00
} else {
values = append(values, slog.Attr{Key: "error", Value: slog.GroupValue(
slog.String("type", reflect.TypeOf(er.origin).String()),
slog.String("message", er.origin.Error()),
slog.Any("data", er.origin),
)})
2024-04-06 21:11:22 +07:00
}
2024-04-06 01:22:00 +07:00
return slog.GroupValue(values...)
}
2024-05-14 12:07:07 +07:00
func (e *Err) Error() string {
2024-04-26 10:51:09 +07:00
s := strings.Builder{}
2024-05-14 12:07:07 +07:00
if e.message != "" {
s.WriteString(e.message)
if e.origin != nil {
s.WriteString(": ")
}
2024-04-06 01:33:03 +07:00
}
2024-05-14 12:07:07 +07:00
unwrap := errors.Unwrap(e)
for unwrap != nil {
var current string
2024-04-26 10:51:09 +07:00
if e, ok := unwrap.(Error); ok && e.GetMessage() != "" {
2024-05-14 12:07:07 +07:00
current = e.GetMessage()
} else {
current = unwrap.Error()
2024-04-06 01:33:03 +07:00
}
2024-04-26 10:51:09 +07:00
next := errors.Unwrap(unwrap)
if next != nil {
2024-05-14 12:07:07 +07:00
current, _ = strings.CutSuffix(current, next.Error())
current, _ = strings.CutSuffix(current, ": ")
2024-04-06 01:22:00 +07:00
}
2024-05-14 12:07:07 +07:00
if current != "" {
s.WriteString(current)
if next != nil {
s.WriteString(": ")
}
}
2024-04-26 10:51:09 +07:00
unwrap = next
2024-04-06 01:22:00 +07:00
}
return s.String()
}
2024-04-10 17:13:07 +07:00
func (er *Err) Unwrap() error {
return er.origin
}
2024-04-06 01:22:00 +07:00
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-08 15:48:45 +07:00
log.New(ctx).Caller(er.caller).Err(er).Error(er.message)
2024-04-06 21:11:22 +07:00
return er
}
2024-04-07 16:06:33 +07:00
func Wrap(err error) Error {
return &Err{
origin: err,
caller: caller.New(3),
}
}
func Wrapw(err error, message string, details ...any) Error {
2024-04-06 21:11:22 +07:00
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
}