package fw import ( "fmt" "runtime" "strings" ) type Error interface { Add(string) Error Tap() Error Message() string Trace() []string Error() string } type LogError struct { err error messages []string trace []string stack []byte } func Err(err error) *LogError { return &LogError{ err: err, trace: []string{trace()}, } } func ErrStr(msg string) *LogError { return &LogError{ messages: []string{msg}, trace: []string{trace()}, } } func (it *LogError) Add(msg string) Error { it.trace = append(it.trace, trace()) it.messages = append(it.messages, msg) return it } func (it *LogError) Tap() Error { it.trace = append(it.trace, trace()) return it } func (it *LogError) Message() string { result := "" for i := len(it.messages) - 1; i >= 0; i-- { if result == "" { result += fmt.Sprintf("%v", it.messages[i]) } else { result += fmt.Sprintf(": %v", it.messages[i]) } } if it.err != nil { if result == "" { result += fmt.Sprintf("%v", it.err) } else { result += fmt.Sprintf(": %v", it.err) } } return result } func (it *LogError) Error() string { result := "" if len(it.trace) > 0 { result = "\n\t" + strings.Join(it.trace, "\n\t") } return it.Message() + result } func (it *LogError) Trace() []string { return it.trace } type PanicError struct { *LogError } func ErrPanic(err error, stack []byte) *PanicError { e := PanicError{ LogError: Err(err), } e.trace = strings.Split(string(stack), "\n") return &e } var ( basePath = "packages/fw/error.go" ) func init() { _, file, _, ok := runtime.Caller(0) if !ok { return } basePath = file[:len(file)-len(basePath)] } func trace() string { _, file, line, ok := runtime.Caller(2) if !ok { return "it was not possible to recover the information" } if strings.HasPrefix(file, basePath) { return fmt.Sprintf("%s:%d", file[len(basePath):], line) } else { return fmt.Sprintf("%s:%d", file, line) } }