CockroachDB errors library for Go error stack information


1. Go standard library errors are too simple

The most common "simple" error object in Go constructed by fmt.Errorf() is similar to the string contained in the structure with an error interface: its Error() method returns the string set when the error was constructed.

// Go 标准库 errors
// 使用 fmt.Errorf() 构造 Go 中最常见的“简单”错误对象类似于带有错误接口的包含在结构中的字符串:打印错误对象只会显示该字符串。
// 使用 Go 的错误包 errors 的构造函数构建错误 errors.New() 结果一样。

func testSimpleCustomError() {
    
    
	err := fmt.Errorf("fmt.Errorf")
	fmt.Println(err) // "hello"

	err = errors.New("errors.New")
	fmt.Println(err) // "errors.New"
}

Nothing, nothing more. Print error objects will also display this string. By the way, using the constructor of Go's error package errors to construct errors.New() has the same result.



2. CockroachDB error handling library

Using Dave Cheney's error library [1], or even better CockroachDB error library [2] (via github.com/cockroachdb/errors), simple errors will also automatically capture stack traces when constructing errors. The stack trace is displayed only when the error is printed in detail. This makes it easier to rule out the source of the error:


2.1 CockroachDB new stack error

Using Dave Cheney's error library [1], or even better CockroachDB error library [2] (by importing ithub.com/cockroachdb/errors), simple errors will also automatically capture stack traces when constructing errors.

It is recommended to use the following methods of the CockroachDB library instead of GO's standard error handling library:

errors.New(): directly replace the errors.New() of the Go standard library, but it will have a stack trace;
errors.Errorf() or errors.Newf(): replace the fmt of the Go standard library with a stack trace. Errorf();

func testCockroachdbError() {
    
    

	err := cockroachdb_errors.New("cockroachdb_errors.New")
	fmt.Println("只会显示错误字符串:", err)

	fmt.Println("显示错误堆栈信息:", err)
	fmt.Printf("%+v \n", err) // 推荐
}

Insert picture description here

2.2 CockroachDB adds error context prefix

When the same logic is called from multiple locations and may fail due to errors, you want to add the message prefix to any returned error objects.

This helps to provide more context about "where the error occurred" so that when an error occurs at runtime (when the error occurs), it is clear which code path caused the error.

It is especially useful for errors in channel scenarios.

func foo() error {
    
     return errors.New("boo") }

func bar() error {
    
    
	if err := foo(); err != nil {
    
    
		return cockroachdb_errors.Wrap(err, "bar")
	}
	return nil
}

func baz() error {
    
    
	// 当提供 nil 错误作为输入时,errors.Wrap() 返回nil。这使我们可以消除 if err != nil 条件。
	return cockroachdb_errors.Wrap(foo(), "baz")
}

func testCockroachdbErrorWrap() {
    
    
	err1 := bar()
	fmt.Printf("%+v \n", err1)
	err2 := baz()
	fmt.Printf("%+v \n", err2)
}

Insert picture description here

1.3. CockroachDB minor errors

What should I do if I encounter an error while handling the error?

We hope to return detailed information about these two errors in some way to help with troubleshooting.
At the same time, for the purpose of cause analysis, we should be careful to keep the first error encountered as the "main" error.

The minor error comments do not affect the text returned on the major error, and the code behaves as if only the major error has occurred. However, the second error message will be displayed during the detailed printing process;

func testCockroachdbSecondaryError() {
    
    
	err := errors.New("主要错误")
	err = cockroachdb_errors.Wrap(err, "主要信息前缀")
	err = cockroachdb_errors.WithSecondaryError(err, cockroachdb_errors.New("次要错误"))

	fmt.Println(err) // 只打印 "主要错误"

	fmt.Printf("%+v \n", err) // 打印只要错误和次要错误的堆栈信息
}

Insert picture description here



to sum up

The Go library provides a simplified implementation of the error interface through fmt.Errorf() and errors.New() in Go's own error package.

Use the CockroachDB error library instead of Go's error package and Dave Cheney's pkg/errors to get a better experience.

Its error constructor errors.New()/errors.Newf() (alias errors.Errorf()) automatically includes the stack trace in the error object, you can use fmt.Printf("%+v" ,err) to print the stack track.

It also provides a glossary of error wrappers. The most common is the message prefix annotation with errors.Wrap()/errors.Wrapf(), which is used to annotate the call path of functions called from multiple locations. This also includes the stack trace behind the scenes.

Another common wrapper solves the confusing problem of how to execute in Go when an error is encountered while handling another error: use auxiliary cause annotations, and use errors.WithSecondaryCause() or errors.CombineErrors() to attach, Go code can retain both errors, so programmers can see both at the same time during troubleshooting.

The errors in the CockroachDB error library also provide consistent behavior and a useful display structure when formatting errors in detail, thus avoiding the huge Go error printing disaster.

Note source code: https://github.com/qiuyunzhao/go_basis/blob/master/12_%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86/02_%E8%87 %AA%E5%AE%9A%E4%B9%89%E9%94%99%E8%AF%AF%26%E9%94%99%E8%AF%AF%E5%A0%86%E6%A0 %88/main.go

Guess you like

Origin blog.csdn.net/QiuHaoqian/article/details/112005271