The primary purpose is to facility debugging and make error log more useful,but It is a big change,so I want to know:any poptential problem?
package main
import(
"errors"
//"fmt"
"runtime"
"github.com/fatih/structs"
"github.com/Sirupsen/logrus"
)
type Error interface {
Mapify() map[string]interface{}
Error() string
}
func New(err error) Error {
//get error runtime info
pc, file, line, _ := runtime.Caller(1)
funcName := runtime.FuncForPC(pc).Name()
return &ErrorString{err.Error(), file, funcName, line}
}
type ErrorString struct {
Err string
File string//file name
Func string//function name
Line int
}
func (s *ErrorString) Mapify() map[string]interface{} {
return structs.Map(s)
}
func (s *ErrorString) Error() string {
return s.Err
}
func main(){
logrus.WithFields(logrus.Fields(throw().Mapify())).Error(errors.New("test"))
}
func throw() Error{
return New(errors.New("any error"))
}
You can see a similar approach in the project youtube/vitess/go/tb/error.go
, but it checks if one of the arguments provided with an new Error already includes a stack:
func Errorf(msg string, args ...interface{}) error {
stack := ""
// See if any arg is already embedding a stack - no need to
// recompute something expensive and make the message unreadable.
for _, arg := range args {
if stackErr, ok := arg.(stackError); ok {
stack = stackErr.stackTrace
break
}
}
// compute own stack if empty
Another simpler approach is illustrated in this gist: take an existing error (instead of defining a new type), and add/print the stack information to it.
// Handle an error for any function at <depth> from the top of the call stack
func HandleDepth(msg string, err error, depth int) {
// If the error is non-nil
if err != nil {
// Find out who called it and where from, skip the top <depth> calls
pc, file, line, ok := runtime.Caller(depth)
// Parse out the filename and calling function
filename := filepath.Base(file)
callingFunc := runtime.FuncForPC(pc)
callingFuncName := callingFunc.Name()
// If we could retrieve the information then print a message and exit with an error
if ok {
fmt.Printf("%s:%s:%d: %s %s
", filename, callingFuncName, line, msg, err)
os.Exit(1)
}
}
}