Any potential problems if changing all errors to the style that includes file name,function name and line number?

huangapple go评论77阅读模式
英文:

Any potential problems if changing all errors to the style that includes file name,function name and line number?

问题

主要目的是为了方便调试并使错误日志更有用,但这是一个重大的改变,所以我想知道是否存在潜在的问题?

package main

import (
	"errors"
	"runtime"
	"github.com/fatih/structs"
	"github.com/Sirupsen/logrus"
)

type Error interface {
	Mapify() map[string]interface{}
	Error() string
}

func New(err error) Error {
	//获取错误的运行时信息
	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 //文件名
	Func string //函数名
	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"))
}
英文:

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?

<!-- language: lang-go -->

package main

import(
	&quot;errors&quot;
	//&quot;fmt&quot;
	&quot;runtime&quot;
	&quot;github.com/fatih/structs&quot;
	&quot;github.com/Sirupsen/logrus&quot;
)

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 &amp;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(&quot;test&quot;))
}

func throw() Error{
	return New(errors.New(&quot;any error&quot;))
}

答案1

得分: 2

你可以在项目youtube/vitess/go/tb/error.go中看到类似的方法,但它检查是否有一个新的Error提供的参数已经包含了一个堆栈:

func Errorf(msg string, args ...interface{}) error {
    stack := ""
    // 查看是否有任何参数已经嵌入了堆栈 - 不需要重新计算昂贵的内容并使消息难以阅读。
    for _, arg := range args {
        if stackErr, ok := arg.(stackError); ok {
            stack = stackErr.stackTrace
            break
        }
    }
    // 如果为空则计算自己的堆栈
    // ...
}

另一种更简单的方法在这个gist中有示例:使用现有的错误(而不是定义一个新类型),并将堆栈信息添加/打印到其中。

// 处理来自调用栈顶部的第<depth>个函数的错误
func HandleDepth(msg string, err error, depth int) {
    // 如果错误不为空
    if err != nil {
        // 找出调用它的函数和位置,跳过前<depth>个调用
        pc, file, line, ok := runtime.Caller(depth)
        // 解析出文件名和调用函数
        filename := filepath.Base(file)
        callingFunc := runtime.FuncForPC(pc)
        callingFuncName := callingFunc.Name()
        // 如果能够获取到信息,则打印消息并以错误退出
        if ok {
            fmt.Printf("%s:%s:%d: %s %s\n", filename, callingFuncName, line, msg, err)
            os.Exit(1)
        }
    }
}
英文:

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 := &quot;&quot;
    // 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 &lt;depth&gt; 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 &lt;depth&gt; 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(&quot;%s:%s:%d: %s %s\n&quot;, filename, callingFuncName, line, msg, err)
			os.Exit(1)
		}
	}
}

huangapple
  • 本文由 发表于 2014年12月14日 17:07:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/27467846.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定