Go言語でのスタックトレースを簡素化する
2024-08-16 10:26:05 goGo言語のパッケージ: 冗長なスタックトレースを簡素化して出力します。
普通に出したスタックトレース冗長すぎ問題
github.com/pkg/errors
で作成したエラーについては fmt.Printf("%+v", err)
でスタックトレースを出力することができます。
ただ、その出力が errors.Wrap()
した単位でそれぞれ出力されるため、大分冗長です。
例
以下のように、C→B→A と経由したエラーがあったとします。
|
|
その場合、以下のようにして funcA から返ってきたエラーからスタックトレースを出力すると、以下のようになります。
|
|
error C
mypkg.funcC
path/to/mypkg/mysource.go:30
mypkg.funcB
path/to/mypkg/mysource.go:26
mypkg.funcA
path/to/mypkg/mysource.go:22
mypkg.Example
path/to/mypkg/mysource.go:12
testing.runExample
go/current/src/testing/run_example.go:63
testing.runExamples
go/current/src/testing/example.go:44
testing.(*M).Run
go/current/src/testing/testing.go:1721
main.main
_testmain.go:49
runtime.main
go/current/src/runtime/proc.go:250
runtime.goexit
go/current/src/runtime/asm_amd64.s:1571
error B
mypkg.funcB
path/to/mypkg/mysource.go:26
mypkg.funcA
path/to/mypkg/mysource.go:22
mypkg.Example
path/to/mypkg/mysource.go:12
testing.runExample
go/current/src/testing/run_example.go:63
testing.runExamples
go/current/src/testing/example.go:44
testing.(*M).Run
go/current/src/testing/testing.go:1721
main.main
_testmain.go:49
runtime.main
go/current/src/runtime/proc.go:250
runtime.goexit
go/current/src/runtime/asm_amd64.s:1571
error A
mypkg.funcA
path/to/mypkg/mysource.go:22
mypkg.Example
path/to/mypkg/mysource.go:12
testing.runExample
go/current/src/testing/run_example.go:63
testing.runExamples
go/current/src/testing/example.go:44
testing.(*M).Run
go/current/src/testing/testing.go:1721
main.main
_testmain.go:49
runtime.main
go/current/src/runtime/proc.go:250
runtime.goexit
go/current/src/runtime/asm_amd64.s:1571
起点となる “error C” についてのスタックトレースだけがあれば良いものを、その後 errors.Wrap()
した分エラーについてまでもスタックトレースを出力しています。
冗長ですね。
というわけで、パッケージ stacktrace
上記のような冗長な出力と比べて、エラー A, B, C それぞれのスタックトレースのフレームをマージしたようなスタックトレースを生成します。(フレームの再現はしません。あくまでも人間が読む出力を簡素化したいだけなので)
使い方
まずは go get
go get github.com/shu-go/stacktrace
ちなみに GitHub ☐↗
もともとの出力に近い方式
|
|
出力は以下のようになります。
error C
mypkg.funcC
path/to/mypkg/mysource.go:30
error B
mypkg.funcB
path/to/mypkg/mysource.go:26
error A
mypkg.funcA
path/to/mypkg/mysource.go:22
mypkg.Example
path/to/mypkg/mysource.go:12
testing.runExample
go/current/src/testing/run_example.go:63
testing.runExamples
go/current/src/testing/example.go:44
testing.(*M).Run
go/current/src/testing/testing.go:1721
main.main
_testmain.go:49
runtime.main
go/current/src/runtime/proc.go:250
runtime.goexit
go/current/src/runtime/asm_amd64.s:1571
もともとの出力を真似た上で冗長部分を削除、しかし、エラーメッセージ部分の出力は行うようにしています。
簡単に解説: スタックトレースの読み方
<最初に発生したエラーのメッセージ>
<最初にエラーが発生した関数の名前>
<エラーが発生したソースファイル上の位置>
<↑の関数を呼び出した関数の名前>
<エラー発生関数を呼び出していた部分のソースファイル上の位置>
:
基本的には上記のとおりなのですが、エラーメッセージは複数回出現することがあります。
これは、途中で errors.Wrap()
した場合など、エラーを伝播する中で「別のエラーがもともとのエラーを内部に隠し持つようになった」場合にそのようなスタックトレースの出力になります。
上の出力例では、“error C” や “error B” といった行が関数の名前が記載されるのと同じインデントで出力されていますね。
正直ちょっと見辛いと思いますが、まあ、もとから提供された振る舞いに合わせたということで、許してください。
さらにシンプルにした場合
%+v
にしていたところを、%v
に変えるだけです。
|
|
出力は以下のようになります。
error C
path/to/mypkg/stacktrace_test.go:30
error B
path/to/mypkg/stacktrace_test.go:26
error A
path/to/mypkg/stacktrace_test.go:22
path/to/mypkg/stacktrace_test.go:12
go/current/src/testing/run_example.go:63
go/current/src/testing/example.go:44
go/current/src/testing/testing.go:1721
_testmain.go:49
go/current/src/runtime/proc.go:250
go/current/src/runtime/asm_amd64.s:1571
%+v
から関数名の行を取り払っただけですが、大分見やすくなりました。(個人的には)
関数の呼び出し関係はわからなくなります。
細かく errors.Wrap()
するスタイルのコードではエラーメッセージでその分を補えると思うので、こちらの出力が見やすいかもしれません。
その他の使い方
stacktrace.New(err)
した結果はこのパッケージ独自のフレームの配列 ([]stacktrace.Frame) になります。
スタックトレースとして出力される情報だけを持った構造体なので加工するのに適しているかはわかりませんが、有用なようであればご利用ください。
- 📄 Hugo テーマ 6. Render Hook2024-08-16 12:36:24#5 の題材を、今度は Render Hook という機能を使って実装します。
- 📄 pomi2024-08-16 10:26:05ポメラSyncされたメモを操作するツール →後継のソフトウェアpmsyncを使ってください。
- 📄 Goでテーブル駆動のベンチマークをとる方法2024-08-16 10:26:05公式に記載ありますが、まとめてみます。
- 📄 slog-handler-guide2024-08-16 10:26:05slog-handler-guide の解説
- 📄 Popcorn2024-08-16 10:26:05自分がよく使うコマンドを登録して呼び出すための Vim script
- 📄 Ergodox EZ キーボードレイアウト2024-08-16 10:26:05JISレイアウトを参考にした、Ergodox EZ のキーボードレイアウト
- 📄 Go言語でのスタックトレースを簡素化する2024-08-16 10:26:05Go言語のパッケージ: 冗長なスタックトレースを簡素化して出力します。
- 📄 Keychron K15 Pro2024-08-15 21:30:59買ったので雑に感想でも書いてみます。
- 📄 Vim LSP メモ2024-08-15 21:30:59忘れそうな内容をメモ
- 📄 GOEXPERIMENT + Build Constraints2024-08-15 21:30:59例えば GOEXPERIMENT=rangefunc の場合にビルドしたい/したくない場合の書き方