// Package errors provides errors that have stack-traces. package errors import ( "bytes" "fmt" "reflect" "runtime" ) // The maximum number of stackframes on any error. var MaxStackDepth = 50 // Error is an error with an attached stacktrace. It can be used // wherever the builtin error interface is expected. type Error struct { Err error stack []uintptr frames []StackFrame } // New makes an Error from the given value. If that value is already an // error then it will be used directly, if not, it will be passed to // fmt.Errorf("%v"). The skip parameter indicates how far up the stack // to start the stacktrace. 0 is from the current call, 1 from its caller, etc. func New(e interface{}, skip int) *Error { var err error switch e := e.(type) { case *Error: return e case error: err = e default: err = fmt.Errorf("%v", e) } stack := make([]uintptr, MaxStackDepth) length := runtime.Callers(2+skip, stack[:]) return &Error{ Err: err, stack: stack[:length], } } // Errorf creates a new error with the given message. You can use it // as a drop-in replacement for fmt.Errorf() to provide descriptive // errors in return values. func Errorf(format string, a ...interface{}) *Error { return New(fmt.Errorf(format, a...), 1) } // Error returns the underlying error's message. func (err *Error) Error() string { return err.Err.Error() } // Stack returns the callstack formatted the same way that go does // in runtime/debug.Stack() func (err *Error) Stack() []byte { buf := bytes.Buffer{} for _, frame := range err.StackFrames() { buf.WriteString(frame.String()) } return buf.Bytes() } // StackFrames returns an array of frames containing information about the // stack. func (err *Error) StackFrames() []StackFrame { if err.frames == nil { err.frames = make([]StackFrame, len(err.stack)) for i, pc := range err.stack { err.frames[i] = NewStackFrame(pc) } } return err.frames } // TypeName returns the type this error. e.g. *errors.stringError. func (err *Error) TypeName() string { if _, ok := err.Err.(uncaughtPanic); ok { return "panic" } return reflect.TypeOf(err.Err).String() }