wrappederror/pkg.go

126 lines
2.4 KiB
Go

package WrappedError
import (
// Standard
"fmt"
"path"
"regexp"
"runtime"
)
type Error struct {
Wrapped error
ErrStr string // wrapped error isn't necessarily json encodable
Code string
File string
Line int
Data any
}
type CodableError interface {
error
WithCode(string) CodableError
WithData(any) CodableError
Log() CodableError
}
type LogCallback func(Error)
var (
logCallback LogCallback
baseDirLength int
)
// Init only works if called from the main package and sets the length of code base path
// to later be removed in file paths to receive relative paths.
func Init() {
_, file, _, _ := runtime.Caller(1)
dirBase := path.Dir(file)
baseDirLength = len(dirBase)
}
// SetLogCallback gives a possibility to automatically run code to handle any errors.
func SetLogCallback(cbk LogCallback) {
logCallback = cbk
}
func callback(wrapped Error) {
if logCallback != nil {
logCallback(wrapped)
}
}
// Error implements the error inteface and adds filename and line to the error.
func (wrapped Error) Error() string {
var code string
if wrapped.Code != "" {
code = wrapped.Code + ":"
}
return fmt.Sprintf(
"[%s%s:%d] %s",
code,
wrapped.File,
wrapped.Line,
wrapped.Wrapped.Error(),
)
}
func create(err error, data interface{}) *Error {
if err == nil {
return nil
}
_, file, line, _ := runtime.Caller(2)
file = file[baseDirLength+1:]
wrapped := Error{
Wrapped: err,
ErrStr: err.Error(),
File: file,
Line: line,
Data: data,
}
return &wrapped
}
// Wrap wraps an existing error with file and line.
func Wrap(err error) *Error {
return create(err, nil)
}
// New creates a new wrapped error with file and line.
func New(msg string, params ...any) *Error {
err := fmt.Errorf(msg, params...)
wrapped := create(err, nil)
return wrapped
}
// WithCode associates a string code with the error.
func (e *Error) WithCode(code string) CodableError {
e.Code = code
return e
}
// WithData associates any data with the error to make troubleshooting easier.
func (e *Error) WithData(data any) CodableError {
e.Data = data
return e
}
// Log calls the log callback.
func (e *Error) Log() CodableError {
callback(*e)
return e
}
// NoTrace returns the Error() string without the trace.
func (e *Error) NoTrace() string {
rxp := regexp.MustCompile(`^(\[[^\]]+\.go:\d+\]\s*)*`)
return string(
rxp.ReplaceAll(
[]byte(e.Error()),
[]byte(""),
),
)
}