dongying3830 2014-12-14 09:07
浏览 36

如果将所有错误更改为包括文件名,函数名和行号的样式,是否有潜在的问题?

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"))
}
  • 写回答

1条回答 默认 最新

  • dou426098 2014-12-14 09:23
    关注

    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)
            }
        }
    }
    
    评论

报告相同问题?