| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 | package ierrorsimport (	"fmt"	"net/http"	"runtime"	"strings")type Option func(*Error)type Error struct {	err error	prefix        string	statusCode    int	publicMessage string	shouldReport  bool	stack []uintptr}func (e *Error) Error() string {	if len(e.prefix) > 0 {		return fmt.Sprintf("%s: %s", e.prefix, e.err.Error())	}	return e.err.Error()}func (e *Error) Unwrap() error {	return e.err}func (e *Error) Cause() error {	return e.err}func (e *Error) StatusCode() int {	if e.statusCode <= 0 {		return http.StatusInternalServerError	}	return e.statusCode}func (e *Error) PublicMessage() string {	if len(e.publicMessage) == 0 {		return "Internal error"	}	return e.publicMessage}func (e *Error) ShouldReport() bool {	return e.shouldReport}func (e *Error) StackTrace() []uintptr {	return e.stack}func (e *Error) Callers() []uintptr {	return e.stack}func (e *Error) FormatStackLines() []string {	lines := make([]string, len(e.stack))	for i, pc := range e.stack {		f := runtime.FuncForPC(pc)		file, line := f.FileLine(pc)		lines[i] = fmt.Sprintf("%s:%d %s", file, line, f.Name())	}	return lines}func (e *Error) FormatStack() string {	return strings.Join(e.FormatStackLines(), "\n")}func Wrap(err error, stackSkip int, opts ...Option) *Error {	if err == nil {		return nil	}	var e *Error	if ierr, ok := err.(*Error); ok {		// if we have some options, we need to copy the error to not modify the original one		if len(opts) > 0 {			ecopy := *ierr			e = &ecopy		} else {			return ierr		}	} else {		e = &Error{			err:          err,			shouldReport: true,		}	}	for _, opt := range opts {		opt(e)	}	if len(e.stack) == 0 {		e.stack = callers(stackSkip + 1)	}	return e}func WithStatusCode(code int) Option {	return func(e *Error) {		e.statusCode = code	}}func WithPublicMessage(msg string) Option {	return func(e *Error) {		e.publicMessage = msg	}}func WithPrefix(prefix string) Option {	return func(e *Error) {		if len(e.prefix) > 0 {			e.prefix = fmt.Sprintf("%s: %s", prefix, e.prefix)		} else {			e.prefix = prefix		}	}}func WithShouldReport(report bool) Option {	return func(e *Error) {		e.shouldReport = report	}}func callers(skip int) []uintptr {	stack := make([]uintptr, 10)	n := runtime.Callers(skip+2, stack)	return stack[:n]}
 |