package WrappedError import ( // Standard "errors" "fmt" "path" "runtime" ) type Error struct { Wrapped error File string Line int Data interface{} } 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 { return fmt.Sprintf( "[%s:%d] %s", wrapped.File, wrapped.Line, wrapped.Wrapped.Error(), ) } func create(err error, data interface{}) error { _, file, line, _ := runtime.Caller(2) file = file[baseDirLength+1:] wrapped := Error{ Wrapped: err, File: file, Line: line, Data: data, } callback(wrapped) return wrapped } // Wrap wraps an existing error with file and line. func Wrap(err error) error { return create(err, "") } func WrapData(err error, data interface{}) error { return create(err, data) } // New creates a new wrapped error with file and line. func New(msg string) error { wrapped := create(errors.New(msg), "") return wrapped } func NewData(msg string, data interface{}) error { wrapped := create(errors.New(msg), data) return wrapped }