Skip to content

Instantly share code, notes, and snippets.

@tkm-kj
Last active October 13, 2020 09:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tkm-kj/6d31ab29e2dee57fd2bf5bb20953bf6c to your computer and use it in GitHub Desktop.
Save tkm-kj/6d31ab29e2dee57fd2bf5bb20953bf6c to your computer and use it in GitHub Desktop.
errors.Wrap のstacktraceの出方とエラー判定の方法
package main
import (
"fmt"
"log"
"github.com/pkg/errors"
)
var (
Err1 = errors.New("err1")
Err2 = errors.New("err2")
Err3 = errors.New("err3")
Err4 = errors.New("err4")
)
func func1() error {
return Err1
}
func func2() error {
return errors.Wrap(Err2, "error happened on func2")
}
func func3() error {
err := func4()
if err != nil {
return errors.Wrap(err, "func3 catch error")
}
return nil
}
func func4() error {
return Err3
}
func func5() error {
err := func6()
if err != nil {
return errors.Wrap(err, "func5 catch error")
}
return nil
}
func func6() error {
return errors.Wrap(Err4, "error happened on func6")
}
func func7() error {
err := func6()
if err != nil {
return err
}
return nil
}
func main() {
err := func1()
if err != nil {
// Wrap せずに返す
// エラーが定義されている行数だけ出てくる
// 直接的にエラーが return されたところがわからない
// なので、あまり役に立たない
log.Printf("%+v", err)
fmt.Println()
// スタンダードなエラーはそのまま err を switch 文に渡せる
switch err {
case Err1:
log.Println("Err1発生したよ")
}
}
fmt.Println()
fmt.Println()
fmt.Println()
err = func2()
if err != nil {
// 大元でWrap
// エラーが返された行数まではっきりわかる
log.Printf("%+v", err)
fmt.Println()
// Wrapした時点で通常の err だけ渡して switch しても期待通りに動かない
switch err {
case Err2:
log.Println("Err2発生したよ")
}
fmt.Println()
// Wrap したやつは Cause を使うと取り出せるので、それで分岐させる
switch errors.Cause(err) {
case Err2:
log.Println("Err2発生したよその2")
}
}
fmt.Println()
fmt.Println()
fmt.Println()
err = func3()
if err != nil {
// func3だけWrap
// Wrapされたところからstacktraceが生まれる
// func4で大元のエラーが発生しているが、その情報がエラーに入っていない
// errorの途中からWrapしてもあまりありがたみがないことがわかった
log.Printf("%+v", err)
}
fmt.Println()
fmt.Println()
fmt.Println()
err = func5()
if err != nil {
// 2重にWrap
// エラーの大元(func6)の情報からstacktraceに入ってくる。また、func5の発生場所もはっきりわかる。ぶっちゃけ全部Wrapしちゃう方式でも問題ない気がする
log.Printf("%+v", err)
fmt.Println()
// 2重にWrapしていても、大元だけチェックすれば良い
switch errors.Cause(err) {
case Err4:
log.Println("Err4発生したよ")
}
}
fmt.Println()
fmt.Println()
fmt.Println()
err = func7()
if err != nil {
// エラーの大元だけWrapして子供は return で流す。
// func5の時と同じ。大元だけWrapして後は全部 return で流すのが一番丁度よい。
log.Printf("%+v", err)
fmt.Println()
switch errors.Cause(err) {
case Err4:
log.Println("Err4発生したよその2")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment