【Go】エラーライブラリによるスタックトレースの違い
作成日
目次
この記事では、Go言語でのエラーハンドリングに関して、pkg/errorsとcockroachdb/errors ライブラリを使用した際のスタックトレースの出力方法を比較します。
cockroachdb/errorsはそのREADMEに
This library aims to be used as a drop-in replacement to github.com/pkg/errors and Go’s standard errors package.
とあるようにpkg/errorsの代替となりますが、使ってみるとスタックトレースの出力のされ方は全く同じではありませんでした。
だからといって別に困らないのですが、実験した結果を以下にメモします。なお、スタックトレースはpkg/errorsもcockroachdb/errorsもfmt.Printf("%+v\n", err)
のようにして出力しました。
pkg/errorsの場合
エラー発生元でのみWrapした場合
「エラー発生元でのみWrap」とは次のようなイメージです。
func funcD1() error {
err := funcD2()
return err
}
func funcD2() error {
_, err := os.Open("text.txt")
return errors.Wrap(err, "funcD2")
}
funcD2
関数がエラーの発生元でここではWrapしていますが、funcD1
ではそのままreturnしています。
この場合、スタックトレースは次のようになります。
open text.txt: no such file or directory
funcD2
main.funcD2
/home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:78
main.funcD1
/home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:71
main.main
/home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:28
runtime.main
/home/newvm/go/pkg/mod/golang.org/[email protected]/src/runtime/proc.go:267
runtime.goexit
/home/newvm/go/pkg/mod/golang.org/[email protected]/src/runtime/asm_amd64.s:1650
エラー発生元でのみWrapした場合
「毎回Wrap」とは下記のようなイメージです。
func funcE1() error {
err := funcE2()
return errors.Wrap(err, "funcE1")
}
func funcE2() error {
_, err := os.Open("text.txt")
return errors.Wrap(err, "funcE2")
}
エラーが発生するfuncE2
だけでなく、funcE1
でもWrapしています。
この場合スタックトレースは次のようになります。
open text.txt: no such file or directory
funcE2
main.funcE2
/home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:89
main.funcE1
/home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:82
main.main
/home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:33
runtime.main
/home/newvm/go/pkg/mod/golang.org/[email protected]/src/runtime/proc.go:267
runtime.goexit
/home/newvm/go/pkg/mod/golang.org/[email protected]/src/runtime/asm_amd64.s:1650
funcE1
main.funcE1
/home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:83
main.main
/home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:33
runtime.main
/home/newvm/go/pkg/mod/golang.org/[email protected]/src/runtime/proc.go:267
runtime.goexit
/home/newvm/go/pkg/mod/golang.org/[email protected]/src/runtime/asm_amd64.s:1650
スタックトレースが重複し、かなり読みづらくなりました。
cockroachdb/errorsの場合
エラー発生元でのみWrapした場合
pkg/errorsと同じように「エラー発生元でのみWrap」とは次のようなイメージです。
func funcB1() error {
err := funcB2()
return err
}
func funcB2() error {
_, err := os.Open("text.txt")
return errors.Wrap(err, "funcB2")
}
funcB2
関数がエラーの発生元でここではWrapしていますが、funcB1
ではそのままreturnしています。
この場合、スタックトレースは次のようになります。
funcB2: open text.txt: no such file or directory
(1) attached stack trace
-- stack trace:
| main.funcB2
| /home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:56
| main.funcB1
| /home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:49
| main.main
| /home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:18
| runtime.main
| /home/newvm/go/pkg/mod/golang.org/[email protected]/src/runtime/proc.go:267
| runtime.goexit
| /home/newvm/go/pkg/mod/golang.org/[email protected]/src/runtime/asm_amd64.s:1650
Wraps: (2) funcB2
Wraps: (3) open text.txt
Wraps: (4) no such file or directory
Error types: (1) *withstack.withStack (2) *errutil.withPrefix (3) *fs.PathError (4) syscall.Errno
エラー発生元でのみWrapした場合
「毎回Wrap」とは下記のようなイメージです。
func funcC1() error {
err := funcC2()
return errors.Wrap(err, "funcC1")
}
func funcC2() error {
_, err := os.Open("text.txt")
return errors.Wrap(err, "funcC2")
}
エラーが発生するfuncC2
だけでなく、funcC1
でもWrapしています。
この場合スタックトレースは次のようになります。
funcC1: funcC2: open text.txt: no such file or directory
(1) attached stack trace
-- stack trace:
| main.funcC1
| /home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:61
| [...repeated from below...]
Wraps: (2) funcC1
Wraps: (3) attached stack trace
-- stack trace:
| main.funcC2
| /home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:67
| main.funcC1
| /home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:60
| main.main
| /home/newvm/ghq/gitlab.com/my-study-etc-group/go-error-study/main.go:23
| runtime.main
| /home/newvm/go/pkg/mod/golang.org/[email protected]/src/runtime/proc.go:267
| runtime.goexit
| /home/newvm/go/pkg/mod/golang.org/[email protected]/src/runtime/asm_amd64.s:1650
Wraps: (4) funcC2
Wraps: (5) open text.txt
Wraps: (6) no such file or directory
Error types: (1) *withstack.withStack (2) *errutil.withPrefix (3) *withstack.withStack (4) *errutil.withPrefix (5) *fs.PathError (6) syscall.Errno
pkg/errorsのときと異なり、[...repeated from below...]
などとなり、毎回Wrapしてもそこまで冗長な出力にならなくなりました。
補足
今回実験に使ったリポジトリはこちらです。