otel-migration について
otel-migrationは、計装のない既存アプリケーションや、既存のログ・メトリクス方式を維持する必要があるアプリケーションにOpenTelemetryを導入するガイドです。SDK設定からコンテキスト伝播、ブリッジ、検証までを6段階で説明します。
主な機能
- 016段階の移行手順
- 02SDKの初期化と終了処理
- 03HTTPミドルウェアとコンテキスト伝播
- 04カスタムスパンの指針
- 05ログとメトリクスのブリッジ
- 06各段階での検証
活用シーン
- 01既存サービスへのOpenTelemetry導入
- 02アプリケーションコード全体へのトレース伝播
- 03移行中のPrometheusメトリクス維持
- 04既存ログとトレースの関連付け
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ honeycombio/ agent-skill --skill otel-migrationインストール後、Claude Code で/otel-migrationを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/bridge-libraries.mdcontext-propagation-patterns.mdframework-middleware.mdmigration-pitfalls.mdverification-checklist.md詳細
既存アプリケーションの OpenTelemetry 移行
既存の、計装されていないアプリケーションに OpenTelemetry を後付けするためのガイドです。ここでは
段階的な移行アプローチ、コンテキスト伝播のリファクタリング、ログとメトリクスのブリッジ、および
検証について扱います。これは新規構築の OTel セットアップ(otel-instrumentation スキルを参照)や
Beeline 固有の移行(beeline-migration スキルを参照)とは異なります。
このスキルを使うべき場面
ユーザーが次のような既存アプリケーションを持っている場合に、このスキルを使用してください。
- OpenTelemetry の計装がなく、追加する必要がある
- OTel と共存させる必要がある既存のログ、メトリクス、コンテキストのパターンがある
- コールスタックを通じてトレースコンテキストを引き回すために、関数シグネチャをリファクタリングする必要がある
- OTel ミドルウェアの落とし穴があるフレームワークを使用している(例: Fiber、Gin、Express)
新規構築の OTel セットアップには、代わりに otel-instrumentation スキルを使用してください。
Beeline から OTel への移行には、代わりに beeline-migration スキルを使用してください。
なぜ計装するのかを理解するには、observability-fundamentals スキルを参照してください。
移行フェーズ
移行は 6 つのフェーズを順に進みます。各フェーズは個別にデプロイ可能で、検証可能です。 コンテキスト伝播(フェーズ 3)は通常、作業量の約 60% を占めます。
フェーズ 1: SDK の初期化とシャットダウン
OTLP エクスポーターを使用して TracerProvider、MeterProvider、LoggerProvider をセットアップします。初期化は アプリケーションのエントリポイントの早い段階で組み込み、シャットダウンはシグナルハンドラーに組み込みます。
重要なガイダンス:
- SDK の初期化は、スパンを作成する可能性のあるアプリケーションコードより前に行う必要があります。エントリポイントの 最初の方で、設定の読み込みやストレージの初期化よりも前に実行してください
- シャットダウンの順序は重要です。トレース、次にメトリクス、次にログをフラッシュします。タイムアウト(10〜30 秒)を使用してください
- 初期化が失敗しても、アプリケーションは動作し続けるべきです。エラーをログに記録し、テレメトリーなしで続行します
- 言語固有の SDK セットアップについては、
${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/sdk-setup-by-language.mdを参照してください
フェーズ 2: HTTP ミドルウェア(自動計装)
HTTP フレームワークに OTel ミドルウェアを追加します。これにより、ハンドラーへのコード変更を一切行わずに、 受信リクエストごとに自動的にスパンを取得できます。これは投資対効果が最も高いステップです。
重要: フレームワークごとに、OTel で強化されたコンテキストの公開方法が異なります。これがサイレントな
トレース断絶の最大の原因です。フレームワーク固有の詳細については
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/framework-middleware.md を参照してください。
| フレームワーク | OTel コンテキストの取得方法 | よくある間違い |
|---|---|---|
| Go net/http | r.Context() | 該当なし(標準) |
| Go Fiber v2 | c.UserContext() | c.Context() の使用(OTel スパンのない fasthttp コンテキストを返す) |
| Go Gin | c.Request.Context() | c を直接使用 |
| Go Echo | c.Request().Context() | 該当なし |
| Python Flask | 自動(スレッドローカル) | 計装ライブラリでは該当なし |
| Python Django | 自動(スレッドローカル) | 計装ライブラリでは該当なし |
| Node.js Express | 自動(AsyncLocalStorage) | 計装ライブラリでは該当なし |
| Java Spring | 自動(スレッドローカル) | スレッドプールでのコンテキスト消失 |
| .NET ASP.NET Core | 自動(AsyncLocal) | 該当なし |
| Ruby Rails | 自動(スレッドローカル) | 計装ライブラリでは該当なし |
フェーズ 3: コンテキスト伝播のリファクタリング
HTTP ハンドラー(またはエントリーポイント)から I/O 操作に至るまでの呼び出しチェーンを通じて、トレースコンテキストをスレッドしてください。これが最も難しいフェーズです — 通常、移行作業の約 60% を占めます。
このフェーズの難易度は言語によって大きく異なります:
- Go: 最も難しい。呼び出しチェーン内のすべての関数に
context.Contextパラメータを追加する必要があります。 - Java: 中程度。スレッドローカルコンテキストはスレッド内で自動的に伝播しますが、スレッドプール、CompletableFuture、リアクティブストリームをまたぐと壊れます。
- Python: 比較的容易。
contextvarsはスレッド内で自動的に伝播します。課題となるのはスレッドプールとマルチプロセッシングです。 - Node.js: 比較的容易。
AsyncLocalStorageは async/await を通じて自動的に伝播します。課題となるのは古いコールバックベースのコードです。 - .NET: 最も容易。
ActivityはAsyncLocal<T>を介して async/await を通じて自動的に伝播します。 - Ruby: 比較的容易。スレッドローカルコンテキストは自動的に伝播します。手動でのスレッド作成が課題です。
言語固有のパターンとコード例については、
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/context-propagation-patterns.md を参照してください。
フェーズ 4: カスタムスパン
自動計装ではカバーされないビジネスロジック操作にスパンを追加します。スパン作成の仕組みについては、
otel-instrumentation スキルに委ねてください。移行固有のガイダンス:
- I/O 境界から始める — データベース呼び出し、外部 HTTP 呼び出し、キャッシュ操作
- 次にビジネスロジックを追加する — なぜ 時間が費やされているかを説明する操作
- 属性を惜しみなく追加する — あらゆるコンテキストが調査時の BubbleUp を有用にします
- スパンに結果を記録する — 結果ステータス、エラー数、所要時間を属性として
属性の命名とスパン作成のパターンについては、
${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/custom-instrumentation.md を参照してください。
フェーズ 5: ログの移行
既存のログライブラリを OTel に置き換えるかブリッジして、ログがトレースと相関するようにします。
重要なガイダンス:
- ほぼ確実に、ログは stderr(ローカルデバッグ)と OTel(トレース相関)の両方に出力したいはずです。 これにはマルチハンドラー/ファンアウトパターンが必要です。
- OTel ログブリッジは構造化ログ(キーと値のペア)で動作します。既存のログが printf スタイルのフォーマット文字列を使用している場合は、まず構造化フォーマットに変換してください。
- printf スタイルから構造化ログへの変換は面倒ですが機械的です — 自動リファクタリングの良い候補です。
言語固有のログブリッジとマルチハンドラーパターンについては、
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/bridge-libraries.md を参照してください。
フェーズ 6: メトリクスブリッジ
すでに Prometheus メトリクス(または別のメトリクスライブラリ)がある場合は、書き直すのではなく OTel にブリッジしてください。
重要なガイダンス:
- Prometheus ブリッジは既存のレジストリから読み取り、OTel メトリクスを生成します — 既存の
prometheus.NewCounterVec(...)呼び出しは変更なしで継続します - 既存のスクレイパーがある場合は、Prometheus の
/metricsエンドポイントを維持してください。ブリッジは スクレイピングに 加えて OTLP エクスポートを追加します。 - 最終的に Prometheus 依存関係を削除したい場合は、後で別の移行を計画してください。 ブリッジは時間を稼いでくれます。
言語固有のメトリクスブリッジについては、
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/bridge-libraries.md を参照してください。
検証
各フェーズの後、計装が正確かつ完全であることを検証してください。
完全なチェックリストとクエリパターンについては、
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/verification-checklist.md を参照してください。
Honeycomb アカウントなしでローカルで検証するには、バンドルされたコレクタースクリプトを使用して
スパンをデバッグ出力と NDJSON としてキャプチャします。使用方法については
${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/local-collector-debug-test.md を、完全なスクリプトについては
${CLAUDE_PLUGIN_ROOT}/scripts/start-collector.sh を参照してください。
Honeycomb 固有の検証クエリについては、query-patterns スキルも参照してください。
よくある落とし穴
よくある間違いとその回避方法のカタログについては、
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/migration-pitfalls.md を参照してください。
実世界でのキャリブレーション
参考として、Gatus(約30k LOC の Go、Fiber v2、SQLite/Postgres、Prometheus)の実際の移行では次のようになりました:
- 変更したファイル: 約45、行数: +840/-645
- 工数の内訳: コンテキスト伝播 約60%、カスタムスパン 約15%、ログ移行 約15%、その他すべて 約10%
- 遭遇したバグ: Fiber の
c.Context()とc.UserContext()、printf 形式の slog フォーマット文字列、span.End()呼び出しの欠落、goroutine のコンテキスト再利用