mcpField
O
otel-instrumentation

otel-instrumentation

github.com/honeycombioクラウド・DevOps283.6k 回インストール3 週間前に更新
リポジトリ

otel-instrumentation について

OpenTelemetry と Honeycomb でサービスを計装する開発者向けのガイドです。SDK 設定、カスタムトレース、サンプリング、調査に役立つテレメトリーを扱います。

主な機能

  1. 01OTLP エンドポイントとプロトコルの設定
  2. 02既存 Span への属性追加
  3. 03カスタム Span とリンクの作成
  4. 04例外ログイベントの記録
  5. 05Span とサンプリング戦略の選択

活用シーン

  1. 01OpenTelemetry データの Honeycomb への送信
  2. 02重要な業務処理の計装
  3. 03属性による性能外れ値の調査
  4. 04例外ログとトレースの関連付け

MCP 対応

README には MCP を使った調査ワークフローへの言及がありますが、このスキルが MCP サービスや接続を提供するとは説明されていません。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/honeycombio/agent-skill --skill otel-instrumentation

インストール後、Claude Code で/otel-instrumentationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
architectural-patterns.md
collector-config.md
custom-instrumentation.md
lambda.md
local-collector-debug-test.md
python.md
sdk-setup-by-language.md
wide-event-attributes.md

詳細

Honeycomb 向け OpenTelemetry インストルメンテーション

SDK のセットアップ、カスタムスパン、属性、スパンイベント、サンプリング、およびレイヤードテレメトリー。 概念的な基礎(なぜワイドイベントが重要か、属性がどのように調査に結びつくか)については、observability-fundamentals スキルを参照してください。

OTLP の構成と SDK のセットアップ

すべての OTel SDK が Honeycomb にデータを送信するには、以下の環境変数が必要です。

必須の環境変数

基本構成:

OTEL_SERVICE_NAME=your-service-name
OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io
OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=YOUR_API_KEY"

任意ですが推奨:

# Protocol selection (default: http/protobuf)
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf  # or grpc

# Signal-specific endpoints (override base endpoint for specific signals)
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.honeycomb.io/v1/traces
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://api.honeycomb.io/v1/metrics

メトリクスの場合(推奨): モダンな OTLP メトリクスとネイティブデータポイントを使用してください。データセットヒントを使用して、送信先の種類(metrics または events)を確認します。認証には以下を使用します:

OTEL_EXPORTER_OTLP_METRICS_HEADERS="x-honeycomb-team=YOUR_API_KEY"
プロトコルの選択

OTEL_EXPORTER_OTLP_PROTOCOL はワイヤーフォーマットとトランスポートを決定します:

  • http/protobuf(デフォルト、推奨) — protobuf エンコーディングを使用する HTTP
  • grpc — protobuf エンコーディングを使用する gRPC
  • http/json — JSON エンコーディングを使用する HTTP(ペイロードが大きく、低速)

gRPC に対する特定のインフラストラクチャ要件がない限り、http/protobuf を使用してください。

シグナル固有のエンドポイント

デフォルトでは、OTel SDK は OTEL_EXPORTER_OTLP_ENDPOINT に /v1/traces と /v1/metrics を追加します。シグナル固有のエンドポイント変数を使用して上書きできます:

  • OTEL_EXPORTER_OTLP_TRACES_ENDPOINT — トレース用の完全な URL(/v1/traces を含む)
  • OTEL_EXPORTER_OTLP_METRICS_ENDPOINT — メトリクス用の完全な URL(/v1/metrics を含む)

シグナルを異なるバックエンドにルーティングする場合や、非標準のエンドポイントを使用する場合に便利です。

よくある落とし穴

サイレントな認証失敗: OTLP エクスポーターが認証を行うには x-honeycomb-team ヘッダーが必要です。これがないと、Honeycomb はリクエストをサイレントに拒否します — エラーもデータもありません。OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=YOUR_API_KEY" を設定するか、プログラムでヘッダーを渡してください。.env からキーを読み込む場合は、dotenv が SDK の初期化より前に実行されることを確認してください。

メトリクス: モダンな OTLP メトリクスとネイティブデータポイントを優先してください。データセットヒントは送信先の種類(metrics または events)を識別するため、デフォルトでは x-honeycomb-dataset を追加しないでください。このヘッダーは、ヒントまたは構成によって名前付きイベントデータセットへのレガシールーティングが必要な場合にのみ使用してください。トレースには不要です。トレースは service.name によってルーティングされます。

環境変数の値、言語固有の依存関係、およびセットアップコード(Go、Python、Node.js、Java、Ruby、.NET、Rust)については、${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/sdk-setup-by-language.md を参照してください。

カスタムインストルメンテーション

既存のスパンへの属性の追加(最も効果が高い)

自動インストルメンテーションされたスパンにビジネスコンテキストを追加します — 新しいスパンは不要です。コンテキストから現在のスパンを取得し、ユーザー、テナント、ビジネス、デプロイのコンテキストを指定して SetAttributes(Go)、set_attribute(Python)、または setAttribute(Node.js)を呼び出します。

カスタムスパンの作成

トレースウォーターフォールで可視化するために、重要なビジネスオペレーションをラップします。tracer.Start(ctx, "operation-name")(Go)、tracer.start_as_current_span("operation-name")(Python)、または tracer.startActiveSpan("operation-name", callback)(Node.js)を使用します。

すべての言語での完全なコード例については、${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/custom-instrumentation.md を参照してください。

スパンをいつ作成すべきか

すべての関数にスパンが必要なわけではありません。スパンを作成する価値があるかどうかは、2 つの質問で決まります。

  1. 興味深いか? — その処理はリクエスト全体のパフォーマンス (レイテンシーや障害) に意味のある影響を与えますか?
  2. 集計可能か? — このスパンを名前と属性でグループ化したとき、有用なトレンドや比較を生み出せますか?
操作興味深いか?集計可能か?スパンを作成するか?
HTTP リクエストハンドラーはい — レイテンシーが変動し、失敗しうるはい — ルート、メソッド、ステータスでグループ化はい
データベースクエリはい — I/O バウンドで、失敗しやすいはい — クエリ種別、テーブルでグループ化はい
外部 API 呼び出しはい — ネットワークレイテンシー、依存関係はい — エンドポイント、ステータスでグループ化はい
キャッシュルックアップはい — 高速パスと低速パスはい — キャッシュ名、ヒット/ミスでグループ化はい
メッセージキューのパブリッシュ/コンシュームはい — 非同期境界、遅延はい — キュー、メッセージ種別でグループ化はい
ビジネスロジックのトランザクションはい — 意味のある状態変化はい — 種別、結果でグループ化はい
プライベートなヘルパー関数いいえ — わずかな CPU、予測可能いいえ — 粒度が細かすぎるいいえ
ループのイテレーション場合による — 遅ければいいえ — カーディナリティが無制限いいえ
ゲッター/セッターいいえ — 意味のある duration がないいいえ — グループ化するものがないいいえ
入力バリデーション (純粋な CPU)いいえ — 高速で予測可能場合によるいいえ
ビジネスロジックのオーケストレーションいいえ — 計装済みコードを呼び出すだけいいえ — duration は子の合計いいえ

よくある間違い:

  • スパンが多すぎる: 数百万の 2ms スパンを含むトレースは詳細すぎて、ほとんど 実用的ではありません。まとめ上げましょう — 単一のスパンに統合するか、詳細を 親スパンの属性として記録します。
  • スパンが少なすぎる: 何時間もの処理を単一の不透明なハンドラーにまとめてしまうと、 どこに時間が費やされたかを推測することになります。
  • テスト用スパンが残っている: test-span、debug-span などの名前のスパンは、 データセットを汚染する成果物です。トレーシングが動作していることを確認するためだけに 作成したスパンは、作業を終える前に削除してください。

迷ったときは、新しい子スパンを作成するよりも、既存のスパンに属性を付けることを 優先してください。

タイミング属性 (子スパンなしでサブ操作を計測する)

重要なサブ操作の duration を親スパンの属性として記録します。これは子スパンよりも クエリが容易で、BubbleUp と直接連携します。

// Go: time auth and record on the existing span
span := trace.SpanFromContext(r.Context())
authStart := time.Now()
user, err := authenticate(r)
span.SetAttributes(attribute.Float64("auth.duration_ms", float64(time.Since(authStart).Milliseconds())))
# Python: time auth and record on the existing span
span = trace.get_current_span()
auth_start = time.monotonic()
user = authenticate(request)
span.set_attribute("auth.duration_ms", (time.monotonic() - auth_start) * 1000)
例外テレメトリー: イベントの詳細とスパンレベルのディメンション

新しい例外イベントには Logs API を使用します。該当するスパンがアクティブな間にレコードを出力し、標準の例外フィールド(exception.type、exception.message、exception.stacktrace、該当する場合は exception.escaped)、ERROR 重大度、および event.name="exception" を含めます。操作が失敗した場合は、別途スパンステータスを ERROR に設定します。

Honeycomb では、トレースと関連付けられた例外ログはトレース内で span_event アノテーションとしてレンダリングされ、trace.trace_id と trace.parent_id を持ちます。その完全な exception.* ペイロードはログ由来のイベント上に残り、包含するスパンにホイストされることはありません。例外イベントの行を検索し、そのトレース ID をたどって周囲のトレースを調査します。

集計とアラートには、カーディナリティの低いスパン属性を使用します:

  • error=true とスパンステータスは操作の失敗を示します。
  • exception.slug はエラー発生箇所を表す静的な、grep 可能な識別子です。
  • オプションのエラーカテゴリーは、完全な例外メッセージよりも GROUP BY に安全です。
Logs-API exception event: event.name=exception, body=exception, meta.signal_type=log
Legacy span-event exception: name=exception, meta.signal_type=trace
Both may have: meta.annotation_type=span_event

record_exception / RecordError は既存の SDK とコード向けの互換性 API として残りますが、Logs API のサポートが利用可能な場合は、新しいガイダンスとしてこれらだけを使用しないでください。これらはまた、Logs API のイベント単体では生成されない親スパンの例外フィールドを生成することがあります。

操作の失敗はスパンディメンションで検索します: WHERE error = true AND exception.slug does-not-exist。Logs API の例外イベントは event.name=exception AND exception.type exists で検索し、サンプリングされた trace.trace_id を show_events=true を付けて get_trace にたどります。

拡張例と MCP の調査レシピについては、${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/custom-instrumentation.md を参照してください。

オプションの互換性: LogRecordProcessor による例外フィールドのプロモート

既存のスパンレベルのダッシュボード、アラート、またはクエリが Honeycomb の従来の例外フィールドプロモートに依存している場合は、バッチ/エクスポートプロセッサーの前にカスタム LogRecordProcessor を追加します。例外ログを検出したら、ログレコードの解決済みコンテキストを使用してアクティブな記録中のスパンを見つけ、error=true、error.type、exception.type、exception.slug、またはエラーカテゴリーなど、設定された最小限のフィールドをプロモートする必要があります。

このために単体の SpanProcessor を推奨しないでください。スパンプロセッサーはログレコードではなくスパンのライフサイクルコールバックを受け取ります。デフォルトでは、完全な exception.message と exception.stacktrace は Logs API イベント上に保持します。レガシークエリの互換性が明示的に要求する場合にのみ、それらをスパンにコピーします。プロセッサーは、ログがバッチエクスポートに到達する前に、スパンコンテキストが有効な間に同期的に実行する必要があります。記録中のスパンが存在しない場合は何もしないようにし、アプリケーションがログレコードに設定していないフィールドを推測してはなりません。

これはオプションの移行レイヤーであり、Logs API イベントのクエリに代わるものではありません。エージェントは、スパンレベルでプロモートされたフィールドを計装に依存するものとして扱い、完全な診断のために引き続き event.name=exception のイベント行をクエリする必要があります。

計装すべき対象

高い価値(最初に計装する)
  • API エントリーポイント(HTTP ハンドラー、gRPC メソッド)
  • データベースクエリ(ほとんどの SDK で自動計装)
  • 外部 HTTP 呼び出し(ほとんどの SDK で自動計装)
  • メッセージキューのプロデューサー/コンシューマー

これらは通常 OTel SDK によって自動計装され、トレースの骨格を形成します。

中程度の価値(次に追加する)
  • ビジネスロジックの操作(チェックアウト、支払い、フルフィルメント)
  • キャッシュ操作(ヒット、ミス、エビクション)
  • 認証と認可のチェック
  • バックグラウンドジョブの実行

これらはビジネスロジックです。ここにカスタムスパンがないと、リクエストが遅いことはわかっても、なぜ 遅いのかはわかりません。トレースのウォーターフォールには、重要な処理が見えない形で行われている箇所に隙間ができてしまいます。

追加する属性

属性は、BubbleUp が調査中に使用するディメンションです。追加したすべての属性は、BubbleUp が外れ値リクエストの違いを見つけるために差分を取る新しい軸となります。根拠とクエリ例を含む、カテゴリ別に整理された完全なカタログについては、${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/wide-event-attributes.md を参照してください。

属性が概念的に重要な理由については、observability-fundamentals スキルを参照してください。

スパンイベント、Logs API イベント、スパンリンク

  • ポイントインタイムイベント: 新しいイベント、特に例外には Logs API を推奨します。スパンがアクティブな間に出力することで、レコードにトレースコンテキストが引き継がれます。Honeycomb では、相関付けられたログは meta.annotation_type=span_event アノテーションとしてレンダリングされますが、そのイベント名は name ではなく event.name(多くの場合 body も)にあります。
  • レガシースパンイベント: span.add_event / AddEvent は引き続き有効な互換パスです。そのイベント名は name にあり、シグナルタイプは trace です。
  • スパンリンク: 異なるトレース階層をまたいでスパンを接続します(非同期処理、ファンアウト/ファンイン、システム間の相関付け)。関連するスパンコンテキストへの Link を作成します。

人手による計装の例と、エージェントにとって安全な Honeycomb MCP のクエリ → サンプル → トレースというワークフローについては、${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/custom-instrumentation.md と production-investigation スキルを参照してください。

サンプリング

サンプリング戦略

サンプリングはトレードオフの問題です — 万能な解決策はありません:

  • ヘッドサンプリングはデバッグ性よりもコストを優先します。 リソースは節約できますが、1% のサンプリングにおける 0.1% のエラーは事実上見えなくなります。ヘッドサンプリングは下流で何が起こるかに無関心です。
  • テールサンプリングはシンプルさよりも忠実性を優先します。 興味深いトレースを保持できますが、完全なトレースをバッファリングして評価するためのインフラストラクチャ(Refinery または Collector)が必要です。

計算は重要です: エラーが 0.1% の確率で発生し、1% でヘッドサンプリングする場合、それらのエラーのおよそ 100,000 件に 1 件を捕捉することになります。中程度のトラフィックでは、そのエラーがデータに現れない可能性があります。

ヘッドサンプリング(SDK レベル)

トレースを作成する時点でサンプリングするかどうかを決定します。シンプルですが、興味深いトレースを見逃す可能性があります。

  • OTEL_TRACES_SAMPLER 環境変数で設定
  • always_on(デフォルト)、always_off、traceidratio(例: 10% をサンプリング)
  • parentbased_traceidratio は親のサンプリング決定を尊重します
  • 最適な用途: まれなイベントを見逃すことを許容できる、非常に高スループットなサービス
テールサンプリング(Collector/Refinery)

トレースが完了した後に決定します。興味深いトレース(エラー、遅いリクエスト)を保持します。

  • 本番のテールサンプリングには Honeycomb の Refinery を使用
  • または OTel Collector の tail_sampling プロセッサを設定
  • 次の基準でサンプリングできます: レイテンシ、エラーステータス、特定の属性、トレース期間
  • 最適な用途: デバッグ性が重要なサービス — 定常的なトラフィックをサンプリングしつつ、エラーと外れ値を保持します
サンプリングが Honeycomb に与える影響
  • サンプリングはデータ量とコストを削減します
  • SLO、BubbleUp、クエリ結果はサンプリングレートに合わせて自動的に調整されます
  • トレースの完全性が影響を受ける可能性があります — すべてのサービスが一貫してサンプリングしない場合、スパンが欠落します
  • サンプリングなしで開始し、コスト管理のために必要に応じて追加します

レイヤードテレメトリ

OpenTelemetry は「トレースファースト」です。コンテキスト伝播は、すべてのシグナルを相関させる接着剤のような役割を果たします。しかし、効果的なオブザーバビリティでは、目的に応じて複数のシグナルタイプを重ねて活用します。

適切なシグナルを選ぶための3つの問い:

  1. 因果関係とリクエスト全体のコンテキストが必要なのは何か? → トレース (スパン)
  2. 低コストな長期保存と高速なアラートが必要なのは何か? → メトリクス
  3. 希少なものと一般的なものは何か、また監査要件は何か? → ログ / イベント

スパンと並行してヒストグラムを出力するパターン: 高スループットの HTTP サービスでは、処理した各リクエストに対してスパンとヒストグラムメトリクスの両方を出力します。これにより、コストを抑えるためにトレースをヘッドサンプリングしつつ、ヒストグラムが最後の砦としてのアラートを提供できます。さらにエグザンプラーによって、外れ値のメトリクスデータポイントを特定のトレースに紐付け、より深い調査が可能になります。

この手法は各シグナルが異なる詳細レベルで異なるビューを提供するため、重ね合わせ (複製ではなく) です。

レイヤリングが不可欠となるアーキテクチャパターン (ストリーミング、非同期ジョブ、ETL) については、${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/architectural-patterns.md を参照してください。

AWS Lambda 固有のパターン — AWS マネージド OTel レイヤーと手動 SDK セットアップの選択、forceFlush、SDK 2.x のセットアップ、Lambda 間のトレース伝播、ヘッダーの正規化、TOKEN と REQUEST オーソライザー — については、${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/lambda.md を参照してください。

Honeycomb におけるログ

OTel はログも送信できます。既存のログ基盤がある場合、OTel Collector がログを取り込み、構造化イベントとして Honeycomb に転送できます:

  • OTel SDK ログブリッジ: 既存のログライブラリ (Go の slog、Python の logging、Node.js の winston/pino) からログをキャプチャし、OTel ログレコードとしてエクスポートします。
  • OTel Collector の filelog レシーバー: ログファイルを読み取り、解析し、OTLP としてエクスポートします。

OTel 経由で送信されたログは、スパンと同じクエリ機能を備えた構造化イベントとして Honeycomb に到着します。

命名規則

  • スパン名: 操作を説明する (HTTP GET /api/users、db.query SELECT、process-payment)
  • 属性名: ドット区切りの名前空間を使用する (user.id、order.total、cache.hit)
  • 該当する場合は OTel セマンティック規約に従う (http.method、db.system、rpc.service)
  • カスタム属性: 独自の名前空間を使用する (app.、checkout.、mycompany.)

その他のリソース

リファレンスファイル
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/sdk-setup-by-language.md — Go、Python、Node.js、Java、Ruby、.NET、Rust 向けの OTLP 設定と SDK セットアップ
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/local-collector-debug-test.md — Docker でローカルの OTel Collector を実行し、Honeycomb アカウントなしでスパン、ログ、メトリクスを検証する。NDJSON 出力を検査するための jq コマンドを含む
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/custom-instrumentation.md — 完全なコード例を伴うカスタムインストルメンテーションパターン (タイミング属性、例外スラッグ、非同期リクエストサマリー)
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/collector-config.md — フォーマット変換、処理、サンプリングのための OTel Collector 設定
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/wide-event-attributes.md — カテゴリ別に整理された正規の属性カタログとクエリ例
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/architectural-patterns.md — ストリーミング、非同期、ETL、サーバーレスアーキテクチャ向けのトレース設計パターン
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/lambda.md — AWS Lambda: OTel レイヤーと手動 SDK セットアップのトレードオフ、forceFlush とリクエストごとのレイテンシ、SDK 2.x のセットアップ、Lambda 間のトレース伝播、ヘッダーの正規化、TOKEN と REQUEST オーソライザーの移行
相互参照
  • なぜワイドイベントと属性が重要かという基礎的な背景については:observability-fundamentals スキル
  • 計装後は、query-patterns スキルを使用してデータが到着していることを確認してください

コメント