Datadog🐶のAPM・TraceでGo(echo)×SQL(gorm)のトレースをする
詰まったこと
DatadogのAPMをGoで実装されたAPIに導入する際に、echo単体・SQL単体のTraceは取れるようにすることはできたけど、echoのHTTPリクエストのTraceにSQLTraceが紐付かない
という状況に詰まっていました。
やりたいことのイメージ
この画像のように、HTTPリクエストのTraceの中にそのリクエストで実行SQLのTraceが紐付いた形で情報を取れるようにすること。
参考: https://docs.datadoghq.com/ja/tracing/trace_explorer/trace_view/?tab=spantags
試していたこと
- tracerをinitializeする実装をする
- echoのtracerを実装する
- gormtraceを実装する
1.と2.を実装した時点で、APMのTraceを見ると、echoのHTTPリクエストのデータしか取れておらず、 Traceの中にSQLのSpanがない状態でした。
この辺りの記事を参考にSQLのTraceをするにはgormtrace(sqltrce)を実装する必要があると思い、導入しましたが、SQL単体のTraceが取れるようになったものの先程の画像のように、HTTPリクエストのTraceの中にSQLのSpanが紐付くようにはなりませんでした。
解決方法
Datadogのサポートに協力いただいたりした結果、
クエリ実行時にWithContext(ctx)でechoのContextをgormに渡す
ことでやりたいことが実現できることがわかりました。
実装イメージは以下です。
func GetProjects(c echo.Context) error {
var people []Person
if err := gormtrace.WithContext(c.Request().Context(), db).Find(&people).Error; err != nil {
fmt.Println(err)
return c.JSON(400, people)
} else {
return c.JSON(200, people)
}
}
※ Railsなどではtracerをinitializeするだけで子SpanもTraceできるという先入観で諸々initializeすればイケるだろうという考えを持っていたので結構時間を溶かしてしまいました。
解決した後に気づいた参考になるブログ
- echo と olivere/elastic の統合
なので若干技術スタックは異なりますが、DatadogのAPMに関することがとてもわかりやすくまとまっていて参考になります。
まとめ
以上が、GoのAPI×SQLをDatadogのAPMでTraceする際にハマった点とその解決方法になります。
断片的に見ていてもなかなか解決できなかったりするという学びと、アウトプットをこのような簡単な形でもしていけるといいなあと感じたので継続していけたらと思います。
似たようなことにハマっている人の助けになれば幸いです。
Discussion
同じように親のSpanに子(GORM)のSpanが表示されずに困っているのですが、記事内で
gormtrace
と表示されている部分は https://pkg.go.dev/gopkg.in/DataDog/dd-trace-go.v1@v1.62.0/contrib/gorm.io/gorm.v1 ではなく、 https://pkg.go.dev/gopkg.in/DataDog/dd-trace-go.v1@v1.62.0/contrib/jinzhu/gorm を利用されてますか?gopkg.in/DataDog/dd-trace-go.v1/contrib/gorm.io/gorm.v1
なので前者になると思います🙏
こちらありがとうございます!
完全に自分がミスっておりまして、APIサーバからのContextを
c.Request().Context()
ではなくc
をそのまま渡してしまっていたのがミスでした🙏