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

时间:2014-12-14 09:07:43

标签: error-handling go

主要目的是设置调试并使错误日志更有用,但这是一个很大的变化,所以我想知道:任何流行问题?

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 个答案:

答案 0 :(得分:2)

您可以在项目youtube/vitess/go/tb/error.go中看到类似的方法,但它会检查提供新错误的参数之一是否已包含堆栈:

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

this gist中说明了另一种更简单的方法:获取现有错误(而不是定义新类型),并向其添加/打印堆栈信息。

// 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\n", filename, callingFuncName, line, msg, err)
            os.Exit(1)
        }
    }
}