三行で
- pkg/errorsのスタックトレースが見にくい
- DatadogのError Trackingが見にくい
- まあまあなんとかするやつを作った
pkg/errors
Goのスタックトレース事情については、以下を参照のこと。
zenn.dev
現状では標準ライブラリにスタックトレースが実装されていないので、とりあえず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()")
}
gist.github.com
なのでもう少しきれいに表示するライブラリを作った。
github.com
pperr.Print(err)
以下のように表示される。
gist.github.com
若干重い処理をしているが、エラー発生時は仕方ないということにした。
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にはもう少し頑張って欲しい。
(フィードバックしたらなんとかなるだろうか)