error.go 1.9 KB
Newer Older
O
ob-robot 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
package errors

import (
	"fmt"
	"path"
	"runtime"
	"strconv"
	"strings"
)

type Error struct {
	code   Code
	values []interface{}
	cause  error
	stack  string
}

type FormatFunc func(err *Error) string

var defaultFormatFunc = func(err *Error) string {
	code := err.code
	return fmt.Sprintf("Module=%s, kind=%s, code=%s; ",
		code.Module, code.Kind.Name, code.Name) + code.Format(err.values...)
}

var GlobalFormatFunc = defaultFormatFunc

func (err *Error) Error() string {
	ret := defaultFormatFunc(err)
	if err.stack != "" {
		ret += "\n" + string(err.stack)
	}
	if err.cause != nil {
		ret += "\ncause:\n"
		if causeErr, ok := err.cause.(*Error); ok {
			ret += causeErr.Error()
		} else {
			ret += err.cause.Error()
		}
	}
	return ret
}

func (err *Error) Kind() Kind {
	return err.code.Kind
}

func (err *Error) CodeName() string {
	return err.code.Name
}

func (err *Error) Module() string {
	return err.code.Module
}

func (err *Error) Code() Code {
	return err.code
}

func (err *Error) HttpCode() int {
	return err.code.Kind.HttpCode
}

func (err *Error) Message() string {
	return GlobalFormatFunc(err)
}

func (err *Error) WithCause(cause error) *Error {
	err.cause = cause
	return err
}

func (err *Error) WithStack() *Error {
	lines := make([]string, 0, 8)
	lines = append(lines, "stack:\n")
	i := 1
	for {
		pc, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}
		fn := runtime.FuncForPC(pc)
		fnName := ""
		if fn != nil {
			fnName = fn.Name()
		}

		lines = append(lines, fnName+" ("+path.Base(file)+":"+strconv.Itoa(line)+")\n")
		i++
	}
	err.stack = strings.Join(lines, "")
	return err
}

func (err *Error) Values() []interface{} {
	return err.values
}

func (err *Error) Cause() error {
	return err.cause
}

func (err *Error) Stack() string {
	return err.stack
}

func HttpCode(err error, def int) int {
	if e, ok := err.(*Error); ok {
		return e.HttpCode()
	}
	return def
}