aws-xray-sdk-goというAWS X-Rayでトレースを記録する便利グッズがある。
これはoutgoing HTTP requestも記録できるのだけれども、ある時を機会にトレースの記録に失敗するようになって試行錯誤したけど今日、IQ200になってすべてを理解した。
結論はタイトルの通りで、以下は詳細。
具体的にはこういうエラー・警告が出ていた:
[00] 2019-05-16T15:50:34+09:00 [Error] Suppressing AWS X-Ray context missing panic: failed to begin subsegment named 'example.com': segment cannot be found.
[00] 2019-05-16T15:50:35+09:00 [Warn] failed to record HTTP transaction: segment cannot be found.
つまり親のsegmentが取れていないということ。
HTTP APIなので xray.Handler
を使ってsegmentを作っているはずだけど……。
コードはREADMEにある以下のようなかんじ:
func main() {
http.Handle("/", xray.Handler(xray.NewFixedSegmentNamer("myApp"), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello!"))
})))
http.ListenAndServe(":8000", nil)
}
aws-xray-sdk-goはcontextを使ってrecorderというオブジェクトを持ち回しおり、このrecorderというオブジェクトがsegmentを保持している。
トレースできなかったコードはこういうかんじ:
resp, err := c.httpClient.Get(endpointURL.String())
このメソッドにcontextは渡しているけれど、HTTPリクエストを送る時に渡していないのが原因。
どうしたらいいかというとhttp.Requestオブジェクトを作ってWithContext()を呼ぶとうまくいった。
req, err := http.NewRequest(http.MethodGet, endpointURL.String(), nil)
if err != nil {
return nil, fmt.Errorf("[BUG] failed to build request: %s", err)
}
resp, err := c.httpClient.Do(req.WithContext(ctx))
いや〜〜〜〜〜〜〜大変。
気付くのに時間がかかったポイントとしては、以前のリビジョンではうまくいっていたのでHTTPリクエストを送るコードより設定やライブラリのバージョンに関心が寄っていたこと、他にトレースを発行するコードがなかったので全体に問題があるのかHTTPリクエスト送信に問題があるのか切り分けがむずかしかったこと、があげられそう。
手でsubsegmentを作ってうまくいくか見れば、トレースが取れてxray.Clientの使い方がおかしいと気付けたかもしれない。
ちなみになぜ以前はうまくいっていたかというと、その当時呼んでいたメソッドはWithContextを呼んでおり、最新のアプリではhttp.Client.Getを呼ぶ実装になっていたため……。