🤖
Goでエラートレースを表示するにはどれがいい?
はじめに
Goでエラートレースを実装するにあたってどんなライブラリがあるのかを調べてみた。
Goのエラーパッケージは様々なライブラリがあったが個人的に興味をもった3つを紹介していく。
ライブラリ
-
pkg/errors
Goの標準ライブラリの最も古く、おそらく最も使われてきたライブラリ。しかし、Go 1.13でネイティブなエラーハンドリングが導入されて以降、このライブラリの必要性は減少してきたみたい(?)。現在は新しい機能の追加は行われていないが、既存のプロジェクトでは依然として使われている。 -
go-errors/errors
pkg/errorsと比較してエラーメッセージの構造やスタックトレースの管理に特化している。スタックトレースの自動取得やメッセージフォーマットのカスタマイズなど、豊富なエラーメッセージ機能を備えている。また、現在も積極的にメンテナンスが行われてる。これから新規のプロジェクトで採用するならこれが最適そう。 -
ztrue/tracerr
エラーが発生した場所と、そのエラーに至るまでの呼び出し履歴(スタックトレース)を取得し、エラーメッセージに含めることが可能。スタックトレースの概念をさらに一歩進めて、そのトレース内の実際のソースコードの行を出力し、エラーが発生した方法を行ごとに色付きで表示したい人向け。
実装例
今回は先ほど紹介したztrue/tracerr
とgo-errors/errors
について実際に実装してみる。
今回は存在しないファイルを開いてエラーが発生したときにエラートレースをコンソールに表示させる。
ztrue/tracerr
- tracerr.Wrap
tracerr.Wrap
メソッドは、通常のGoエラーにスタックトレースを追加するために使用する。これは、エラーが発生した箇所の情報(どの関数・ファイル・行で発生したか)を記録する。このメソッド自体にはコンソールにログを出力する機能がないため注意が必要。 - tracerr.PrintSourceColor
tracerr.PrintSourceColor
メソッドは、エラーとそのスタックトレースをカラフルにコンソールに出力するために使用される。これは、デバッグの際にエラー箇所をより視覚的に分かりやすくするため。
main.go
package main
import (
"hello/openfile"
"github.com/ztrue/tracerr"
)
func main() {
err := openfile.Openfile("nonexistent_file.txt")
if err != nil {
tracerr.PrintSourceColor(err) // エラーとスタックトレースをカラフルに表示
}
}
openfile.go
package openfile
import (
"fmt"
"os"
"github.com/ztrue/tracerr"
)
func Openfile(filename string) error {
file, err := os.Open(filename)
fmt.Println("asas")
if err != nil {
// 元のエラーにスタックトレースを付けて返す
return tracerr.Wrap(err)
}
defer file.Close()
// ファイルを正常に開いた時の処理
fmt.Println("ファイルが正常に開かれました")
return nil
}
コンソール
go-errors/errors
- err.(*errors.Error)
err
は通常のGoのエラー型だが、go-errors/errors
ライブラリを使うと、エラーを*errors.Error
型として扱えるようになる。 - ErrorStack
ErrorStack
メソッドは、エラーメッセージと共に、そのエラーが発生したときのスタックトレースを含むエラーメッセージを返す。
main.go
package main
import (
"hello/openfile"
"fmt"
"github.com/go-errors/errors"
)
func main() {
err := openfile.Openfile("nonexistent_file.txt") // 存在しないファイル
if err != nil {
fmt.Println(err.(*errors.Error).ErrorStack()) // スタックトレースを表示
}
}
openfile.go
package openfile
import (
"fmt"
"os"
"github.com/go-errors/errors"
)
func Openfile(filename string) error {
file, err := os.Open(filename)
if err != nil {
// エラーメッセージ生成(errors.Wrap(err)でスタックトレースを含めるやり方も可)
return errors.New(err)
}
defer file.Close()
// ファイルが正常に開かれた場合
fmt.Println("ファイルが正常に開かれました")
return nil
}
コンソール
最後に
わかりやすさで言えば、ztrue/tracerr
の方が色付きでコードも表示されるのでわかりやすいが、ログの書き込みが多くなりすぎると膨大になりすぎてわかりにくかったり、パフォーマンスに影響が出てきそう。そのため、自分が扱うならgo-errors/errors
で良いかと思う。
Discussion