三行で
- pkg/errorsのスタックトレースが見にくい
- DatadogのError Trackingが見にくい
- まあまあなんとかするやつを作った
pkg/errors
Goのスタックトレース事情については、以下を参照のこと。
現状では標準ライブラリにスタックトレースが実装されていないので、とりあえずpkg/errorsを使っている*1が、スタックトレースの表示がめちゃくちゃ見にくい。
package main import ( "fmt" "os" "github.com/pkg/errors" ) func main() { err := f1() fmt.Printf("%+v", err) } func f1() error { return errors.Wrap(f2(), "from f1()") } func f2() error { return errors.Wrap(f3(), "from f2()") } func f3() error { _, err := os.Open("not_found") return errors.Wrap(err, "from f3()") }
なのでもう少しきれいに表示するライブラリを作った。
pperr.Print(err)
以下のように表示される。
若干重い処理をしているが、エラー発生時は仕方ないということにした。
Datadogのエラートラッキング
DatadogはAPMに統合されたエラートラッキング機能を提供していて、Golangにも対応している。 APMの1リクエストに紐付いたエラーを表示できるが、スタックトレースの抽出が貧弱であんまりイケてない。
router.HandleFunc("/hello", func(rw http.ResponseWriter, r *http.Request) { span, _ := tracer.SpanFromContext(r.Context()) err := f1() if err != nil { rw.WriteHeader(http.StatusInternalServerError) span.SetTag(ext.Error, err) } else { fmt.Fprintln(rw, "hello") } })
上記のようにspan.SetTag(ext.Error, err)
するとこのような表示になる。
ext.ErrorDetails
にpkg/errorsのスタックトレースをセットしているが、コンソールに表示されるのはtakeStacktrace()
のほうらしい。
なので直接ext.ErrorStack
を設定する。
span.SetTag(ext.Error, err) span.SetTag(ext.ErrorStack, pperr.Sprint(err))
一応、スタックトレースが表示されるが、インデントが潰れてあんまり見やすくない。
なのでインデントを全角スペースするという微妙なことをする。
さらにErrorTypeとして*errors.withStack
が表示されてもうれしくないので、直近のcause error typeを表示するようにする。
span.SetTag(ext.Error, err)
span.SetTag(ext.ErrorStack, pperr.SprintFunc(err, pperr.NewPrinterWithIndent(" ")))
span.SetTag(ext.ErrorType, pperr.CauseType(err))
これでまあまあ見やすくなったと思う。
ちなみにext.ErrorType
にスタックトレースをセットするというさらによろしくなさそうなことをすると、全角スペースは不要になる。
span.SetTag(ext.ErrorType, pperr.Sprint(err))
エラー表示の機能的にはSentryと大きな違いはなさそうだけれど、UXがだいぶ劣っているのでDatadogにはもう少し頑張って欲しい。 (フィードバックしたらなんとかなるだろうか)