英文:
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(
"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
得分: 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 := ""
// 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\n", filename, callingFuncName, line, msg, err)
os.Exit(1)
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论