OTLPのspan nameが情報量少なすぎる件¶
チェック¶
- [ ] 本文を確認した
- [ ] 概要を確認した
- [ ] タグを確認した
- [ ]
inbox/直下へ移行した
概要¶
OpenTelemetry の公式 instrumentation が付ける span name が粗すぎて、Grafana などの trace UI で見たときに実用上の情報量が足りない、という問題提起の記事。
HTTP クライアントの span name が GET だけだったり、mysqlclient の span name が SELECT だけだったりすると、同じ名前の span が大量に並び、どの処理かを毎回属性で開く必要がある。
取得できた本文が限定的だったため partial として保存するが、問題意識と読み替えを残す。
本文¶
記事の問題意識は、OpenTelemetry で trace を取っても、span name が粗いと trace UI が使いにくいというもの。
OpenTelemetry では span に attributes があり、詳細情報は http.method、http.route、db.statement などへ入る。
しかし、trace 一覧やウォーターフォール表示でまず目に入るのは span name。
span name が情報量の少ない文字列だと、調査時の認知負荷が高くなる。
HTTP client span が GET だけになる問題¶
例として、Requests の instrumentation で span name が GET のような HTTP メソッドだけになるケースが挙げられている。
HTTP メソッドだけでは、どの API へのアクセスか分からない。
trace 画面で GET が複数並ぶと、ユーザーはそれぞれの span を開き、attributes の URL や route を確認しなければならない。
障害調査では、どの外部 API、どの内部サービス、どの endpoint が遅いのかをすぐ見たい。
span name が GET だけでは、その入口で詰まる。
理想的には、クライアント呼び出しでも、少なくとも host や route 相当の情報が名前に入っている方が調査しやすい。 ただし、URL 全体を入れると ID やクエリパラメータで cardinality が爆発するため、正規化が必要になる。
DB span が SELECT だけになる問題¶
mysqlclient の instrumentation では、span name が SELECT のような SQL 操作種別だけになるケースが問題として挙げられている。
これも同じで、SELECT が大量に並んでも、どのテーブル、どのクエリ、どの処理か分からない。
詳細な SQL は db.statement attribute に入ることがある。
しかし、Grafana の trace view で毎回 span をクリックして db.statement を見るのは手間。
ウォーターフォール上で「この SELECT が遅い」と見えても、名前だけでは何の SELECT か判別できない。
一方で、SQL 文をそのまま span name に入れると別の問題が起きる。 値入り SQL は cardinality が高くなり、個人情報や機密値が入る危険もある。 したがって、span name には操作種別だけでなく、正規化されたテーブル名やクエリ種別のような、安全で安定した識別子を入れる設計が必要になる。
Flask の route span はまだ使いやすい¶
記事では、Flask の span name が GET /user/<id:int> のように route template を含む場合があり、これは比較的使いやすい例として読める。
実際の user ID を入れるのではなく、route pattern を入れることで、cardinality を抑えつつ、どの endpoint かが分かる。
HTTP server span では、OpenTelemetry semantic conventions でも route template を使う方向が一般的。
GET /users/{id} のような名前なら、trace UI で見た瞬間に対象の処理が分かる。
この考え方を、HTTP client や DB span にも応用したい。 生の URL や SQL ではなく、正規化された意味のある名前を span name に置く。
span name と attributes の役割¶
OpenTelemetry では、詳細情報は attributes に持たせる設計が多い。 これは検索や集計、仕様上の整理としては正しい。 しかし、UI 上の可読性では、span name が強い。
span name は、trace を開いた瞬間に見える見出し。
attributes は、必要に応じて掘る詳細。
見出しが GET や SELECT だけでは、詳細を見る前に比較判断ができない。
したがって、span name には「人間が一覧で見て区別できる程度の情報量」が必要になる。 ただし、cardinality を増やしすぎない、機密情報を入れない、仕様と互換性を保つという制約もある。
読み替え¶
この記事は、OpenTelemetry の自動計装をそのまま使えば十分、とは限らないことを示している。 自動計装は導入を簡単にするが、運用で本当に使いやすい trace にするには、span name、attributes、resource、service name、route、DB 情報の設計が必要。
バックエンドで実務的に使うなら、次の観点を確認したい。
- HTTP server span name は route template になっているか。
- HTTP client span name は呼び出し先を区別できるか。
- DB span name は操作種別だけでなく、どの処理かを推測できるか。
- 生の ID、URL query、SQL literal、個人情報を span name に入れていないか。
- Grafana や Tempo など実際に使う UI で、クリックなしに主要な遅延箇所が分かるか。
実装時の方向性¶
アプリケーション側で span name を補正できる場合は、低 cardinality で意味のある名前にする。
HTTP server なら次のような名前が望ましい。
HTTP client なら、外部サービス名と正規化された endpoint を使う。
DB なら、SQL 全文ではなく、操作と対象、用途が分かる範囲に抑える。
このような名前にするには、instrumentation hook、middleware、wrapper、DB access layer で span をリネームする必要がある。 公式 instrumentation のデフォルトが調査しにくい場合は、アプリケーションの観測設計として補う。
要点¶
- span name が
GETやSELECTだけだと、trace UI でどの処理か分からない。 - 詳細が attributes にあっても、一覧で見える span name の情報量が足りないと調査が遅い。
- route template のような正規化された名前は、cardinality を抑えつつ人間に分かりやすい。
- SQL 全文や URL 全体を span name に入れると cardinality や機密情報の問題がある。
- 自動計装のデフォルトに任せず、実際の UI で使いやすい span naming を設計する必要がある。
- 取得本文が限定的だったため、詳細な実装例や議論は未確認。