🤖

Goでエラートレースを表示するにはどれがいい?

2024/10/16に公開

はじめに

Goでエラートレースを実装するにあたってどんなライブラリがあるのかを調べてみた。
Goのエラーパッケージは様々なライブラリがあったが個人的に興味をもった3つを紹介していく。

ライブラリ

  • pkg/errors
    Goの標準ライブラリの最も古く、おそらく最も使われてきたライブラリ。しかし、Go 1.13でネイティブなエラーハンドリングが導入されて以降、このライブラリの必要性は減少してきたみたい(?)。現在は新しい機能の追加は行われていないが、既存のプロジェクトでは依然として使われている。
  • go-errors/errors
    pkg/errorsと比較してエラーメッセージの構造やスタックトレースの管理に特化している。スタックトレースの自動取得やメッセージフォーマットのカスタマイズなど、豊富なエラーメッセージ機能を備えている。また、現在も積極的にメンテナンスが行われてる。これから新規のプロジェクトで採用するならこれが最適そう。
  • ztrue/tracerr
    エラーが発生した場所と、そのエラーに至るまでの呼び出し履歴(スタックトレース)を取得し、エラーメッセージに含めることが可能。スタックトレースの概念をさらに一歩進めて、そのトレース内の実際のソースコードの行を出力し、エラーが発生した方法を行ごとに色付きで表示したい人向け。

実装例

今回は先ほど紹介したztrue/tracerrgo-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