/error.go
Go | 105 lines | 70 code | 15 blank | 20 comment | 13 complexity | a39086902d15b7358d5a47864342863b MD5 | raw file
- package easy
- import (
- "runtime"
- "fmt"
- "errors"
- )
- //HelpfulError includes a base error and some context from the call stack.
- type HelpfulError struct {
- //base error
- Err error
- //ErrChainf will produce/add to the comentary here.
- Commentary string
- //A few lines of the call stack so you can figure out where
- //the hell your error came from
- Context string
- }
- func (he HelpfulError) Error() string {
- if len(he.Commentary) == 0 {
- return he.Err.Error() + "\n<callstack:\n" + he.Context + "\n>"
- }
- return fmt.Sprintf("%s\n<commentary:\n%s\ncallstack:\n%s\n>",
- he.Err.Error(), he.Commentary, he.Context)
- }
- //Error makes a HelpfulError out of err. If err is nil, it returns nil.
- //So you can use on actual errors without checking. Also, this won't like
- //stack up a zillion call stacks if you call it on the same root error
- //multiple times.
- func Error(err error) error {
- if err == nil {
- return nil
- }
- //don't let these stack, that would be annoying.
- if _, ok := err.(HelpfulError); ok {
- return err
- }
- return HelpfulError{
- Err: err,
- Context: CallStackToString(3),
- }
- }
- //Errorf returns a new error with the given formatted message, plus a call
- //stack for context.
- func Errorf(format string, vargs ...interface{}) error {
- return HelpfulError{
- Err: errors.New(fmt.Sprintf(format, vargs...)),
- Context: CallStackToString(2),
- }
- }
- //ErrChainf returns an error with your commentary and a callstack.
- //If err is already a helpful error, it adds your commentary but
- //doesn't replace the base error or the callstack. If err is nil,
- //it returns nil and ignores your commentary.
- func ErrChainf(err error, format string, vargs ...interface{}) error {
- if err == nil {
- return nil
- }
- comments := fmt.Sprintf(format, vargs...)
- if he, ok := err.(HelpfulError); ok {
- he.Commentary += comments + "\n"
- return he
- }
- return HelpfulError{
- Err: err,
- Commentary: comments + "\n",
- Context: CallStackToString(3),
- }
- }
- //CallStackToString returns the callstack as a string. For nice error
- //or panic messages. Probably you want to skip one or two frames, at least.
- func CallStackToString(skipFrames int) (str string) {
- i := skipFrames
- for {
- pc, file, line, ok := runtime.Caller(i)
- if !ok {
- break
- }
- str += fmt.Sprintf("%16.16x: %s(%d)\r\n", pc, file, line)
- i++
- }
- return
- }
- // Is returns true if the two errors match, even if one or both are wrapped in
- // a HelpfulError.
- func Is(err1, err2 error) bool {
- found, ok := err1.(HelpfulError)
- if ok { err1 = found }
- found, ok = err2.(HelpfulError)
- if ok { err2 = found }
- return err1 == err2
- }