コンテンツにスキップ

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 なら次のような名前が望ましい。

GET /users/{id}
POST /orders

HTTP client なら、外部サービス名と正規化された endpoint を使う。

GET payment-api /v1/customers/{id}
POST search-api /v1/query

DB なら、SQL 全文ではなく、操作と対象、用途が分かる範囲に抑える。

SELECT users by id
UPDATE orders status

このような名前にするには、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 を設計する必要がある。
  • 取得本文が限定的だったため、詳細な実装例や議論は未確認。

タグ

opentelemetry #tracing #span-name #observability #python #go