analyze-traces
実行中のautotelsサービスから OpenTelemetry トレースと構造化ログを分析し、エラーのデバッグ、レイテンシーの調査、サービス間のリクエスト追跡、カーディナリティ/属性衛生上の問題の検出を行えます。Honeycomb、Grafana Tempo、Datadog、Jaeger、Sentry、Axiom、HyperDX などの任意の OTLP バックエンドからのトレースに対応しており、ローカルの `.autotel/spans/` ダンプやテスト内の `InMemorySpanExporter` でも動作します。
description の原文を見る
Analyze OpenTelemetry traces and structured logs from a running autotel service to debug errors, investigate latency, follow requests across services, and surface cardinality / attribute hygiene problems. Works with traces from any OTLP backend (Honeycomb, Grafana Tempo, Datadog, Jaeger, Sentry, Axiom, HyperDX, …) plus the local `.autotel/spans/` dump and `InMemorySpanExporter` in tests.
SKILL.md 本文
トレースの分析
このスキルは、autotel によって生成された OpenTelemetry トレースを読み取り、推論する方法を AI アシスタントに教えます。トレースはバックエンドに保存されていても、ローカル JSON ダンプにエクスポートされていても、テスト内でキャプチャされていても対応できます。
使用時期
- デプロイ後のエンドポイント障害をデバッグする
- レイテンシー低下を調査する(p50 / p95 / p99 スパイク)
- ブラウザ → サーバー → キュー → ワーカー全体で単一リクエストを追跡する
- 属性の衛生状態を監査する(カーディナリティ、PII 漏洩リスク、ノイズ)
- 新しいインストルメンテーションが実際に期待したスパンを生成していることを確認する
入力フォーマット
| ソース | アクセス方法 |
|---|---|
| ローカルデバッグダンプ | .autotel/spans/*.ndjson — 1 行に 1 スパン、OTLP JSON 形式 |
InMemorySpanExporter(テスト) | exporter.getFinishedSpans() |
| バックエンド(インタラクティブ) | Jaeger / Tempo / Honeycomb UI、Datadog Trace Search など |
| バックエンド(プログラマティック) | Honeycomb Query API、Tempo /api/search、Datadog Logs / Trace API |
autotel スパンの形状
{
"name": "POST /api/checkout",
"context": { "traceId": "…", "spanId": "…" },
"parentSpanId": "…",
"kind": "SERVER",
"startTimeUnixNano": "…",
"endTimeUnixNano": "…",
"status": { "code": "OK" },
"attributes": {
"service.name": "checkout",
"http.request.method": "POST",
"url.full": "https://api.example.com/api/checkout",
"http.response.status_code": 200,
"user.id": "usr_123",
"user.plan": "enterprise",
"cart.items": 3,
"cart.total": 14999,
"_correlationId": "01J…"
},
"events": [
{
"name": "log.emit.manual",
"attributes": { "level": "info", "stage": "validated" }
}
],
"links": [],
"resource": {
"service.name": "checkout",
"deploy.id": "v2025.05.04-1"
}
}
認識すべき主なコンベンション:
service.nameは複数サービス トレース内のサービスを区別します。_correlationId(autotel 固有)は、フォークされた子スパン間であっても論理的な作業単位内で安定しています(_parentCorrelationIdがそれらを結びつけます)。gen_ai.*属性は LLM コール用の OpenTelemetry gen-ai セマンティック コンベンションに従います。exception.*属性(createStructuredErrorで自動設定)はtype、message、stacktraceを含みます。
一般的な調査
「エンドポイント X が失敗するのはなぜか?」
- トレースを検索:
service.name = "<svc>" AND http.route = "<route>" AND status = errorでここ 1 時間をフィルタします。 - 最も遅い/最新のマッチングトレースを開きます。
- ルート スパンの
exception.messageとexception.stacktraceを検査します。 - 子スパンを下に辿ります。
status.code = ERRORが付いた最も深いスパンが通常、原因です。 createStructuredErrorを使用している場合は、code、why、internal.*属性を探します。これらは通常、コードを読まずに「なぜ」に答えます。
「エンドポイント X が遅いのはなぜか?」
- 遅いトレースを検索:
service.name = "<svc>" AND http.route = "<route>" AND duration > p99(duration)。 - ウォーターフォール ビューを表示し、セルフタイム(ウォールタイムではなく)で最長の子スパンを特定します。
- よくある原因:
- 並列化すべき連続 await — 兄弟スパンが重ならずに端から端まで実行されます。
- N+1 クエリ — 同じ名前の多くの短いスパン(
SELECT * FROM …)が 1 つの親の下にあります。 - コールドスタート — Workers または Lambda で
faas.coldstart=true。 - ツールの再試行 —
gen_ai.response.finish_reason = errorの後に別の呼び出しが続く gen-ai スパン。
「このユーザーをサービス全体で追跡する」
_correlationId(またはある場合は user.id)を使用します:
service.name in (web, api, worker) AND _correlationId = "01J…"
ORDER BY startTime
各サービスは同じ traceId を持つスパンに貢献します(W3C トレース コンテキスト伝播は autotel のグローバル fetch インストルメンテーションで自動的に処理されます)。
「新しいインストルメンテーションは実際に起動したか?」
テスト内では、メモリ内エクスポーターをダンプします:
import { InMemorySpanExporter } from 'autotel/exporters';
const exporter = new InMemorySpanExporter();
// … テスト対象のコードを実行
const spans = exporter.getFinishedSpans();
console.log(spans.map((s) => ({ name: s.name, attrs: s.attributes })));
または、SDK をローカル ファイル ダンプにポイントします:
init({ service: 'my-app', debug: 'pretty', spanDumpPath: '.autotel/spans' });
…その後、機能を実行しながら tail -f .autotel/spans/*.ndjson | jq で追跡します。
カーディナリティ / 衛生監査
| チェック項目 | クエリ / ヒューリスティック |
|---|---|
| スパン名のカーディナリティ | サービスごとの上位 K 個の異なる name。数百を超えるものはすべて注意信号 — URL が正規化されていない可能性が高い。 |
| 属性ごとのカーディナリティ | 属性キーごとの unique(attribute_value)。属性内の UUID / メール / Date.now() id はストレージを圧迫します。 |
service.name が欠落 | リソース属性が空または "app" のスパン — SDK init で修正してください。 |
| PII の兆候 | 生の @、長さ 16 の先頭の数字の連続、または eyJ プレフィックスを探します — リダクターがオフです。 |
| ヘルスチェック ノイズ | http.route in (/healthz, /ready) のスパン。FilteringSpanProcessor でドロップします。 |
gen-ai トレースの読み取り
LLM 呼び出しは、親スパン(種類 CLIENT)と各ツール呼び出しの子を生成します:
| 属性 | 意味 |
|---|---|
gen_ai.system | プロバイダー(openai、anthropic など) |
gen_ai.request.model | モデル id |
gen_ai.usage.input_tokens / output_tokens | トークン数 |
gen_ai.usage.cache_read_tokens / cache_creation_tokens | キャッシュ ヒット |
gen_ai.response.finish_reason | stop、tool_calls、length、error |
gen_ai.tool.name | 呼び出されたツール(ツール呼び出し子スパン上) |
gen_ai.cost.usd | 推定コスト(価格マップが提供されている場合) |
一般的な結果:
- 高い
gen_ai.usage.input_tokensで低いcache_read_tokens→ プロンプト キャッシングを有効にします。 - 多くの連続するツール呼び出しスパン → モデルがサポートしている場合は並列ツール呼び出しを検討します。
gen_ai.response.finish_reason = length→max_tokensを増やします。
トレースが見つからない場合
スパンが予期されているのに存在しない場合:
- サンプリング。 ヘッド サンプリングがそれをドロップしましたか? 任意のサブスクライバーで
sampling.ratesとrecordedSpansを確認します。 waitUntilなしの Workers。 エクスポーターがフラッシュされる前にリクエストは返されましたか?defineWorkerFetch/wrapModuleに移動します。instrumentation.disabled = true— 環境条件付きコンフィグを確認します。- エクスポーターが拒否。 サービス ログで
OTLP exporter4xx / 5xx を確認 — 無効なトークン、間違ったデータセット。
出力フォーマット
調査をまとめるときは、決定を変える事実 で始め、その後に裏付けるエビデンスを続けます:
障害原因: payment.declined(Stripe コード: insufficient_funds)
- トレース: 9d3a…b21
- ここ 1 時間のチェックアウト リクエスト 412 件中 38 件が status=402 で失敗。
- すべて eu-west-1、すべて plan=free。
- exception.cause.stripeChargeId は ch_3M… で始まります。
- 提案: 構造化された `fix` フィールドをクライアントに表示します。現在の 402 本文は汎用メッセージを返します。
生のスパン ダンプはサマリーから除外します。代わりにトレース ID にリンクします。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- jagreehal
- リポジトリ
- jagreehal/autotel
- ライセンス
- MIT
- 最終更新
- 2026/5/10
Source: https://github.com/jagreehal/autotel / ライセンス: MIT