Go 言語用エラーハンドリング・パッケージ

no extension

本パッケージは Go 言語によるプログラミングに於いて標準の errors パッケージを補完しエラーハンドリングを行うことができる。

なお errs パッケージは Go 1.13 以上を要求する。 ご注意を。

Build Status GitHub license GitHub release

インポート

import "github.com/spiegel-im-spiegel/errs"

簡単な使い方

たとえば,以下のようなファイルをオープンするだけの関数を考えてみる。

func checkFileOpen(path string) error {
    file, err := os.Open(path)
    if err != nil {
        return err
    }
    defer file.Close()

    return nil
}

os.Open() 関数の実行時に吐き出されるエラー・インスタンス errerrs.Wrap() 関数でラッピングする。 こんな感じ。

func checkFileOpen(path string) error {
    file, err := os.Open(path)
    if err != nil {
        return errs.Wrap(
            err,
            "file open error",
            errs.WithParam("path", path),
        )
    }
    defer file.Close()

    return nil
}

errs.Wrap() 関数では元になる error インスタンスと追加のメッセージ,および errs.WithParam(name, value string) 関数で指定する任意のパラメータ(0個以上複数指定可能)を引数とする。

では実際に checkFileOpen() 関数を動かしてみよう。

func main() {
    if err := checkFileOpen("not-exist.txt"); err != nil {
        fmt.Printf("%v\n", err)
    }
}

この場合の実行結果は以下の通り。

$ go run sample.go 
file open error: open not-exist.txt: no such file or directory

まぁ Go 言語ではありふれた出力形式だ。

ここで fmt.Printf() の書式を %v から %#v に変えてみる。

func main() {
    if err := checkFileOpen("not-exist.txt"); err != nil {
        fmt.Printf("%#v\n", err)
    }
}

すると実行結果は

$ go run sample.go 
&errs.Error{Msg:"file open error", Params:map[string]string{"function":"main.checkFileOpen", "path":"not-exist.txt"}, Cause:&os.PathError{Op:"open", Path:"not-exist.txt", Err:0x2}}

という感じに構造体のダンプ表示ぽい出力になる。

ちなみに errs.Error.Params 要素は map[string]string 型の連想配列になっているが,既定でエラーが発生した関数名を格納している。 これでエラーを追いやすくなるだろう。

更に書式を %+v に変える。

func main() {
    if err := checkFileOpen("not-exist.txt"); err != nil {
        fmt.Printf("%+v\n", err)
    }
}

この場合の実行結果は

$ go run sample.go 
{"Type":"*errs.Error","Msg":"file open error: open not-exist.txt: no such file or directory","Params":{"function":"main.checkFileOpen","path":"not-exist.txt"},"Cause":{"Type":"*os.PathError","Msg":"open not-exist.txt: no such file or directory","Cause":{"Type":"syscall.Errno","Msg":"no such file or directory"}}}

と JSON フォーマットで出力される。 これなら

$ go run sample.go | jq .
{
  "Type": "*errs.Error",
  "Msg": "file open error: open not-exist.txt: no such file or directory",
  "Params": {
    "function": "main.checkFileOpen",
    "path": "not-exist.txt"
  },
  "Cause": {
    "Type": "*os.PathError",
    "Msg": "open not-exist.txt: no such file or directory",
    "Cause": {
      "Type": "syscall.Errno",
      "Msg": "no such file or directory"
    }
  }
}

といった感じに他ツールと組み合わせて errs.Error インスタンスの中身を検証することができる。

おまけの機能として errs.Cause() 関数も用意してみた。

func main() {
    if err := checkFileOpen("not-exist.txt"); err != nil {
        fmt.Printf("%v\n", errs.Cause(err))
    }
    // Output:
    // no such file or directory
}

このように errs.Cause() 関数では階層化 error を遡って大元の error インスタンスを抽出することができる。

errs パッケージと標準の errors パッケージを組み合わせることでエラーハンドリングの助けとなれば幸いである。

ブックマーク

参考図書

photo
プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
Alan A.A. Donovan, Brian W. Kernighan
柴田 芳樹 (翻訳)
丸善出版 2016-06-20
単行本(ソフトカバー)
4621300253 (ASIN), 9784621300251 (EAN)
評価     

著者のひとりは(あの「バイブル」とも呼ばれる)通称 “K&R” の K のほうである。この本は Go 言語の教科書と言ってもいいだろう。

reviewed by Spiegel on 2018-10-20 (powered by PA-API)