errorsパッケージの代わりにgithub.com/pkg/errorsを使うと良いです。
自分でerrors.New()しているところ
今から修正するとして、自分でerrors.New()しているところについて、やることはこれだけ。
- errorsの代わりにgithub.com/pkg/errorsをimportする
- 従来通りerrors.New()でエラーを生成する
- github.com/pkg/errorsを使用しているが、errors.New()の記述は一緒なので修正する必要なし
- エラーハンドラなどスタックトレースを表示したいところで、フォーマット文字列に%+vを使う
サンプルコード
package main
import (
"fmt"
"github.com/pkg/errors"
)
func main() {
err := level1()
fmt.Printf("error %+v\n", err)
}
func level1() error {
return level2()
}
func level2() error {
return level3()
}
func level3() error {
return errors.New("level3で発生したエラーです")
}
実行結果
error level3で発生したエラーです
main.level3
/xxx/error.go:22 <-- errors.New()した行
main.level2
/xxx/error.go:18
main.level1
/xxx/error.go:14
main.main
/xxx/error.go:9
runtime.main
/xxx/proc.go:185
runtime.goexit
/xxx/asm_amd64.s:2197
fmt.Printfを使って出力していますが、fmt.SprintfでもloggerのPrintfなどでも%+vを使えます!
自分でerrors.New()していないところ
ライブラリの戻り値など自分でerrors.New()していないところは、errors.WithStack()を使ってerrorをスタックトレース付きのものにラッピングして返すと良いです。
package main
import (
"fmt"
"github.com/pkg/errors"
"strconv"
)
func main() {
err := level1()
fmt.Printf("error %+v\n", err)
}
func level1() error {
return level2()
}
func level2() error {
return level3()
}
func level3() error {
// 失敗するParse
_, err := strconv.ParseBool("XXX")
return errors.WithStack(err)
}
実行結果。errors.WithStack()したところまでたどれる。
error strconv.ParseBool: parsing "XXX": invalid syntax
main.level3
/xxx/error.go:25 <-- errors.WithStack()した行
main.level2
/xxx/error.go:19
main.level1
/xxx/error.go:15
main.main
/xxx/error.go:10
runtime.main
/usr/local/Cellar/go/1.8.3/libexec/src/runtime/proc.go:185
runtime.goexit
/usr/local/Cellar/go/1.8.3/libexec/src/runtime/asm_amd64.s:2197
まとめ
- 標準のerrorsではなく、github.com/pkg/errorsをimportする
- errors.New()は、今まで通り
- 他のライブラリが返すerrorはerrors.WithStack(error)でラップして返す
- エラーハンドラで"%+v"を使って、スタックトレースを含めたエラー表示なり、ログ出力ナリする
これでエラーを追いやすくなりますね!