目录

项目中错误处理

项目中底层函数错误上报不能带上文件名和行号,后面查找很难,有些函数甚至同样的错误信息,比如

func AAA() error {
	if ...{
		return errors.New("file write err")
	}
	...
	if ...{
		return errors.New("file write err")
	}
		
}

pkg/errors

使用实例:


import (
	"errors"
	"fmt"
	pkgError "github.com/pkg/errors"
)

func main() {
	err := test3()
	fmt.Printf("%+v\n",err) // 打印原始err及调用栈信息
	fmt.Println(pkgError.Cause(err)) // 获取原始err
	fmt.Println(pkgError.Is(err,TestErr)) // 对比原始err
}

func test3() error {
	return pkgError.WithMessage(test2(),"this is test3")
}
func test2() error {
	return pkgError.WithMessage(test1(),"this is test2")
}

var TestErr =errors.New("test err")
func test1() error {
	return pkgError.Wrap(TestErr,"this is test1")
}

我们只需要在第一次出现err的地方wrap即可,不然会打印重复的调用栈信息,没有啥用。

go1.3error

1.3对参考pkg/errors引入As,Is,Wrap,Unwrap

func main() {
	err := test3()
	fmt.Printf("%+v\n",err) // 打印原始err及调用栈信息
	fmt.Println(errors.Unwrap(err)) // 和%w是反向操作,一次只能剥一层
	fmt.Println(errors.Is(err,TestErr)) // 对比原始err
}

func test3() error {
	return fmt.Errorf("%w,this is test3",test2())
}
func test2() error {
	return fmt.Errorf("%w,this is test2",test1())
}

var TestErr =errors.New("test err")
func test1() error {
	return fmt.Errorf("%w,this is test1",TestErr) // 通过%w来wrap error
}

打印:

test err,this is test1,this is test2,this is test3
test err,this is test1,this is test2
true

其实还是没有打印调用栈,并不能快速定位到文件和行

引发的打印思考

pkg/errors,要想打印出调用栈必须使用%+v,%v和%#v都不行,而且他这打印出非常规格式的属于定制,是怎么做到的? 看了代码发现他有函数:

func (f *fundamental) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			io.WriteString(s, f.msg)
			f.stack.Format(s, verb)
			return
		}
		fallthrough
	case 's':
		io.WriteString(s, f.msg)
	case 'q':
		fmt.Fprintf(s, "%q", f.msg)
	}
}

在这里判断了+v符号,所以只有这种情形才能打印,如果定义了一个结构体,想自定义打印样式,可以实现这个方法。