163 lines
3.9 KiB
Go
163 lines
3.9 KiB
Go
// Package errors provides a unified error handling strategy for the application.
|
|
// It extends the standard Go errors package with additional functionality for
|
|
// error wrapping, error types, and error logging.
|
|
package errors
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"git.influ.su/artmares/digglestool/internal/pkg/logger"
|
|
)
|
|
|
|
// Standard errors that can be used throughout the application.
|
|
var (
|
|
ErrNotFound = errors.New("not found")
|
|
ErrInvalidInput = errors.New("invalid input")
|
|
ErrInternal = errors.New("internal error")
|
|
ErrNotImplemented = errors.New("not implemented")
|
|
)
|
|
|
|
// Error represents an error with additional context.
|
|
type Error struct {
|
|
// Original is the original error.
|
|
Original error
|
|
// Message is an additional message to provide context.
|
|
Message string
|
|
// File is the file where the error occurred.
|
|
File string
|
|
// Line is the line where the error occurred.
|
|
Line int
|
|
}
|
|
|
|
// Error returns the error message.
|
|
func (e *Error) Error() string {
|
|
if e.Original == nil {
|
|
return e.Message
|
|
}
|
|
if e.Message == "" {
|
|
return e.Original.Error()
|
|
}
|
|
return fmt.Sprintf("%s: %s", e.Message, e.Original.Error())
|
|
}
|
|
|
|
// Unwrap returns the original error.
|
|
func (e *Error) Unwrap() error {
|
|
return e.Original
|
|
}
|
|
|
|
// New creates a new error with the given message.
|
|
func New(message string) error {
|
|
return &Error{
|
|
Message: message,
|
|
}
|
|
}
|
|
|
|
// Wrap wraps an error with additional context.
|
|
// If err is nil, Wrap returns nil.
|
|
func Wrap(err error, message string) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
_, file, line, _ := runtime.Caller(1)
|
|
file = trimFilePath(file)
|
|
return &Error{
|
|
Original: err,
|
|
Message: message,
|
|
File: file,
|
|
Line: line,
|
|
}
|
|
}
|
|
|
|
// Wrapf wraps an error with a formatted message.
|
|
// If err is nil, Wrapf returns nil.
|
|
func Wrapf(err error, format string, args ...interface{}) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
_, file, line, _ := runtime.Caller(1)
|
|
file = trimFilePath(file)
|
|
return &Error{
|
|
Original: err,
|
|
Message: fmt.Sprintf(format, args...),
|
|
File: file,
|
|
Line: line,
|
|
}
|
|
}
|
|
|
|
// Is reports whether any error in err's chain matches target.
|
|
func Is(err, target error) bool {
|
|
return errors.Is(err, target)
|
|
}
|
|
|
|
// As finds the first error in err's chain that matches target, and if so, sets
|
|
// target to that error value and returns true. Otherwise, it returns false.
|
|
func As(err error, target interface{}) bool {
|
|
return errors.As(err, target)
|
|
}
|
|
|
|
// LogError logs an error with the appropriate log level and returns it.
|
|
// This is useful for logging an error while still returning it up the call stack.
|
|
func LogError(err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
var e *Error
|
|
if errors.As(err, &e) {
|
|
logger.Errorf("[%s:%d] %s", e.File, e.Line, err.Error())
|
|
} else {
|
|
_, file, line, _ := runtime.Caller(1)
|
|
file = trimFilePath(file)
|
|
logger.Errorf("[%s:%d] %s", file, line, err.Error())
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// LogWarn logs an error as a warning and returns it.
|
|
func LogWarn(err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
var e *Error
|
|
if errors.As(err, &e) {
|
|
logger.Warnf("[%s:%d] %s", e.File, e.Line, err.Error())
|
|
} else {
|
|
_, file, line, _ := runtime.Caller(1)
|
|
file = trimFilePath(file)
|
|
logger.Warnf("[%s:%d] %s", file, line, err.Error())
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// LogFatal logs an error as fatal and exits the program.
|
|
func LogFatal(err error) {
|
|
if err == nil {
|
|
return
|
|
}
|
|
|
|
var e *Error
|
|
if errors.As(err, &e) {
|
|
logger.Fatalf("[%s:%d] %s", e.File, e.Line, err.Error())
|
|
} else {
|
|
_, file, line, _ := runtime.Caller(1)
|
|
file = trimFilePath(file)
|
|
logger.Fatalf("[%s:%d] %s", file, line, err.Error())
|
|
}
|
|
}
|
|
|
|
// trimFilePath trims the file path to make it more readable.
|
|
func trimFilePath(file string) string {
|
|
// Find the last occurrence of "git.influ.su/artmares/digglestool"
|
|
idx := strings.LastIndex(file, "git.influ.su\\artmares\\digglestool")
|
|
if idx >= 0 {
|
|
return file[idx+len("git.influ.su\\artmares\\digglestool"):]
|
|
}
|
|
return file
|
|
}
|