investigating-with-observability について
このスキルは、VictoriaMetrics、VictoriaLogs、VictoriaTraces、AlertManager を使うエージェント向けに、段階的な障害調査手順を示します。データとアラートの確認、仮説の検証、少なくとも 2 種類のシグナルによる結論の照合を重視します。
主な機能
- 014 段階で調査を構成
- 02指標・ログ・トレースを先に確認
- 03根拠に基づく仮説の検証
- 04複数シグナル種別の相関確認
- 05環境変数に応じたバックエンド選択
活用シーン
- 01サービスのエラーやクラッシュの調査
- 02レイテンシーやリソース異常の分析
- 03アラート確認と根本原因の検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ victoriametrics/ skills --skill investigating-with-observabilityインストール後、Claude Code で/investigating-with-observabilityを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/alertmanager-check.mdlogs-discovery.mdmetrics-discovery.mdtraces-discovery.md詳細
オブザーバビリティスキルを使ったトラブルシューティング
基本原則
無作為にクエリを実行すると時間を無駄にし、誤解を招く結果につながります。誤ったメトリクス名による空の結果は、「問題が存在しない」場合と見分けがつきません。仮説を立てずにシグナルを行き来すると、調査が迷走します。
クエリを実行する前に検出する。相関を調べる前に仮説を立てる。結論を出す前に確認する。
フェーズ 1 を完了していない場合、根本原因を提案することはできません。少なくとも 2 種類のシグナルを相関させていない場合、結論は推測にすぎません。
調査プロトコル
次のフェーズに進む前に、各フェーズを完了してください。
Phase 1: Gather Signals → What's already known? What's alerting?
Phase 2: Discover and Scope → What data exists? What are the real names?
Phase 3: Hypothesize and Test → Form one theory, query to confirm or refute
Phase 4: Correlate and Confirm → Cross-reference across signal types, find root cause
フェーズ 1:シグナルを収集する
クエリを書く前に、すでにわかっていることを確認します。
1. 環境変数が利用可能か確認する — Subagent Dispatch セクションのゲーティングチェックを実行します。
2. シグナル収集サブエージェントを並列にディスパッチする:
| サブエージェント | 条件 | 内容 |
|---|---|---|
| AlertManager の確認 | VM_ALERTMANAGER_URL が利用可能 | VM アラート、AlertManager アラート、およびサイレンスを確認します |
| メトリクスの検出(アラートのみ) | VM_METRICS_URL が利用可能で、かつ VM_ALERTMANAGER_URL が利用不可 | AlertManager エージェントをディスパッチできない場合の代替として、VM アラートを確認します |
VM_ALERTMANAGER_URL が利用可能な場合、AlertManager 確認エージェントが VM アラートと AlertManager クエリの両方を処理します。アラート用に別のメトリクスエージェントをディスパッチする必要はありません。
エージェントのプロンプトファイルを読み込み、1 回の Agent ツール呼び出しでディスパッチします。各サブエージェントのプロンプトには、次の内容を含めてください。
- エージェントファイルの内容
- 調査対象(判明している場合は、名前空間、サービス、またはコンポーネント名)
3. 結果を統合する — サブエージェントから結果が返ったら、次のことを行います。
- すべてのソースからのアラートに関する調査結果を統合する
- タイムラインを作成する:症状はいつ始まりましたか?何が変わりましたか?
- タイムラインが不明確な場合は、ユーザーに尋ねる
4. 最初に調べるシグナルの種類を特定する:
| 症状 | 最初に調べるもの | 次に相関させるもの |
|---|---|---|
| リソース/レートの問題 | メトリクス | ログ |
| エラー/クラッシュ | ログ | メトリクス |
| レイテンシ/リクエストの遅延 | トレース | ログ |
| アラートの発報 | メトリクス(アラートの詳細) | ログ + トレース |
フェーズ 2:検出して範囲を絞る
メトリクス名、ログフィールド名、サービス名を推測してはいけません。 検出は必須です。間違った名前による空の結果から結論を導き出すという、最もよくある調査上の失敗を防ぎます。
利用可能なすべてのバックエンドについて、検出サブエージェントを並列にディスパッチします。各エージェントのプロンプトファイルを読み込み、1 回の Agent ツール呼び出しでディスパッチします。各サブエージェントのプロンプトには、次の内容を含めてください。
- エージェントファイルの内容
- 対象の名前空間および/またはサービス名(フェーズ 1 の調査結果から)
- 調査対象の期間(RFC3339 形式)
- 検索する特定のキーワードまたはコンポーネント
| サブエージェント | 条件 |
|---|---|
| メトリクスの検出 | VM_METRICS_URL が利用可能 |
| ログの検出 | VM_LOGS_URL が利用可能 |
| トレースの検出 | VM_TRACES_URL が利用可能 |
検出結果を統合する:
- すべてのバックエンドで検出された名前を統合する
- 対象のデータがあるバックエンドと、ないバックエンドを記録する
- フェーズ 3 の仮説検証に最適なシグナルソースを特定する
複雑なクエリではスキルのリファレンスを参照してください。 トレーニングデータに含まれる LogsQL の構文をそのまま使えると考えてはいけません。LogsQL は Loki LogQL とは異なります。サブエージェントがすでに実行したものを超える複雑なクエリでは、対応する *-query スキルを呼び出すか、以下の LogsQL クイックリファレンスを使用してください。
フェーズ 3:仮説を立てて検証する
発見フェーズの後、さらにクエリを実行する前に具体的な仮説を立てます。
明確に述べます:「[フェーズ 1 の根拠 Y] から、[コンポーネント X] は[障害発生/遅延/OOM]していると考えます。」
必要最小限の検証を行います:
- 仮説を裏付ける、または否定するために、1 つだけクエリを実行します
- すべてを一度にクエリしないでください。データに埋もれてしまいます
- 範囲クエリより先に、まず即時クエリを使います(コストが低く、処理も速いため)
仮説が誤っていた場合:
- クエリを追加しないでください。新しい仮説を立てます
- フェーズ 1 とフェーズ 2 で明らかになったことを再検討します
- 発見した内容に予想外のことがなかったか確認します
仮説が 3 回続けて外れたら、停止します。 推測が 3 回外れたということは、根本的な何かを見落としています。次のいずれかを確認してください。
- 重要なデータソースがまだ見つかっていない
- 範囲が間違っている(別の名前空間、別のサービス、別の時間範囲)
- ユーザーにさらに詳しい情報を尋ねる必要がある
フェーズ 4:相関を調べて確認する
シグナルの種類が 1 つだけでは、証拠になりません。結論を出す前に、少なくとも 2 種類のシグナルを相関させます。
必要なシグナルの種類ごとに、相関調査を行うサブエージェントを並列で起動します。agents/ にある同じエージェントのプロンプトファイルを再利用しますが、発見タスクではなく具体的なクエリを指定してください。各サブエージェントのプロンプトには、次を含めます。
- エージェントファイルの内容
- 実行する具体的なクエリ(メトリクス式、ログフィルター、トレース検索パラメーター)
- 正確なクエリ対象時間範囲(フェーズ 3 の調査結果に基づいて絞り込んだもの)
- 確認する内容(フェーズ 3 で確認した仮説)
相関調査の並列起動例:
- メトリクスエージェント:「T1 から T2 まで、
rate(http_requests_total{code=~'5..', namespace='myapp'}[5m])をクエリする」 - ログエージェント:「T1 から T2 まで
{namespace='myapp'} errorを検索し、サンプルメッセージを返す」 - トレースエージェント:「T1 から T2 まで、サービス
myappのトレースをminDuration=1sで検索する」
相関分析の手法:
- 時間ベース: メトリクスで異常のタイムスタンプを特定し、その時刻のログやトレースをクエリします
- トレース ID: トレース内のトレース ID を見つけ、ログから
trace_id:"<id>"を検索します - Pod 名: メトリクスのラベルから Pod 名を取得し、ログストリームのフィルターに使用します
相関分析の後にのみ: 根本原因と修正策を提案します。
危険信号 — 停止してフェーズ 1 に戻る
次のようなことをしていると気付いたら、停止してください。
- シグナルの種類を 1 つだけクエリした後で根本原因を提案する
- 構文を確認せず、記憶だけで LogsQL クエリを書く
- 発見フェーズで存在を確認していないメトリクス名をクエリする
- 結果が空であることから「問題なし」と結論づける
- 「おそらく違うから」とアラートの確認を省略する
- 何か見つかることを期待して、異なるクエリを 5 つ実行する
- 仮説を立てずに「ちょっと試してみます……」と言う
これらはすべて、停止すべきサインです。調査ではなく、推測をしています。
よくある正当化
| 言い訳 | 実際のところ |
|---|---|
| 「メトリクス名は分かっています」 | そうかもしれません。発見には 2 秒しかかからず、空の結果を追いかけて 20 分を無駄にするのを防げます。 |
| 「ここではアラートは役に立ちません」 | アラートの確認は無料で、正確な答えが含まれていることもよくあります。見逃すと後悔するかもしれません。 |
| 「ログをさっと確認するだけです」 | 発見フェーズなしでログをさっと確認すると、フィールド名を間違えたり、誤解を招く結果になったりします。 |
| 「結果が空なら問題なし」 | 結果が空の場合、問題がないのではなく、クエリが間違っていることのほうがよくあります。まず名前を確認してください。 |
| 「相関分析は後で行います」 | シグナルが 1 つだけの結論は推測です。根本原因を断定する前に相関分析を行ってください。 |
| 「LogsQL は LogQL/Elasticsearch のようなものです」 | 違います。構文の違いによって、エラーが表示されずに失敗することがあります。リファレンスを確認してください。 |
環境
環境は環境変数で制御されています。現在の状態を確認します。
echo "VM_METRICS_URL: $VM_METRICS_URL"
echo "VM_LOGS_URL: $VM_LOGS_URL"
echo "VM_TRACES_URL: $VM_TRACES_URL"
echo "VM_ALERTMANAGER_URL: $VM_ALERTMANAGER_URL"
echo "VM_CURL_CONFIG: ${VM_CURL_CONFIG:-(unset - no auth)}"
アプリケーションがどの環境で実行されているか不明な場合は、ユーザーに尋ねてください。
サブエージェントの起動
このスキルは、調査を迅速化するため、フェーズの境界でサブエージェントを並列で起動します。各サブエージェントには API リファレンスが埋め込まれており、構造化された調査結果が返されます。
環境変数による制御
各ディスパッチの前に、利用可能なバックエンドを確認します。
echo "METRICS:${VM_METRICS_URL:+available}"
echo "LOGS:${VM_LOGS_URL:+available}"
echo "TRACES:${VM_TRACES_URL:+available}"
echo "ALERTMANAGER:${VM_ALERTMANAGER_URL:+available}"
available と報告されたバックエンドに対してのみ、サブエージェントをディスパッチしてください。 環境変数が空、または設定されていない場合は、サブエージェントをディスパッチしないでください。
ディスパッチ方法
agents/ディレクトリ(このスキルのディレクトリからの相対パス)にあるエージェントのプロンプトファイルを読み込みます- Agent ツールを使用してディスパッチします。以下を含めてください。
- エージェントのプロンプトファイルの内容を基本指示として指定
- 調査コンテキスト:対象の名前空間、サービス名、時間範囲(RFC3339)
- 確認すべき具体的なクエリやメトリクス
- 並列実行する独立したサブエージェントは、同じツール呼び出しメッセージ内でディスパッチします
- 各サブエージェントに
allowed-tools: Bash(curl:*), Bash(jq:*), Bash(date:*)を設定します
エージェントファイル
| エージェント | ファイル | 必要な環境変数 | 使用フェーズ |
|---|---|---|---|
| AlertManager の確認 | agents/alertmanager-check.md | VM_ALERTMANAGER_URL + VM_METRICS_URL | フェーズ 1 |
| メトリクスの探索 | agents/metrics-discovery.md | VM_METRICS_URL | フェーズ 2、4 |
| ログの探索 | agents/logs-discovery.md | VM_LOGS_URL | フェーズ 2、4 |
| トレースの探索 | agents/traces-discovery.md | VM_TRACES_URL | フェーズ 2、4 |
スキルと API の対応
victoriametrics-query = Metrics only (MetricsQL/PromQL) → $VM_METRICS_URL
victorialogs-query = Logs only (LogsQL) → $VM_LOGS_URL
victoriatraces-query = Traces only (Jaeger API) → $VM_TRACES_URL
alertmanager-query = AlertManager (silences, routing) → $VM_ALERTMANAGER_URL
バックエンド間で API を混在させないでください。データの種類ごとに適切な環境変数とエンドポイントを使用してください。
AlertManager は、VM アラートでは取得できないサイレンスと抑制状態を提供します。ただし、クラスター内にあり、停止している可能性があるため、利用できない場合は $VM_METRICS_URL/api/v1/alerts にフォールバックしてください。
タイムスタンプ形式
| バックエンド | パラメーター | 形式 | 例 |
|---|---|---|---|
| VictoriaMetrics | start/end | RFC3339 文字列 | 2026-02-06T09:00:00Z |
| VictoriaLogs | start(必須)、end | RFC3339 文字列 | 2026-02-06T09:00:00Z |
| VictoriaTraces | start/end | Unix マイクロ秒の数値 | 1738836000000000(16 桁) |
| VictoriaTraces(依存関係) | endTs/lookback | Unix ミリ秒の数値 | 1738836000000(13 桁) / 3600000 |
VictoriaLogs では start が常に必須です。省略すると、保存されているすべてのデータをスキャンするため、非常に大きなコストがかかります。
探索プロトコル
シグナルの種類ごとに、以下の順序で実行してください。API の詳細や追加のエンドポイントについては、対応するクエリスキルを呼び出してください。
メトリクスの探索 → victoriametrics-query スキル
- キーワードでメタデータを検索:
$VM_METRICS_URL/api/v1/metadata?metric=<keyword>&limit=10 - スコープ指定用のラベル値:
$VM_METRICS_URL/api/v1/label/<label_name>/values(match[]でフィルター) - 名前空間の時系列:
$VM_METRICS_URL/api/v1/series?limit=20とmatch[]={namespace="X"} - その後クエリを実行 — 瞬時クエリは
api/v1/query、範囲クエリはapi/v1/query_range(範囲クエリではstart(RFC3339)が必須)
ログの探索 → victorialogs-query スキル
VictoriaLogs のすべてのエンドポイントで start(RFC3339)が必須です。クエリパラメーターには --data-urlencode を使用してください。
- ストリームフィールド名:
$VM_LOGS_URL/select/logsql/stream_field_names?start=<RFC3339> - ストリームフィールド値:
$VM_LOGS_URL/select/logsql/stream_field_values?start=<RFC3339>&field=namespace - ファセット(最適な探索ツール — 1 回の呼び出しで全フィールドの分布を取得):
$VM_LOGS_URL/select/logsql/facets?start=<RFC3339> - 非ストリームフィールド名:
$VM_LOGS_URL/select/logsql/field_names?start=<RFC3339> - その後クエリを実行(JSON Lines レスポンス):
$VM_LOGS_URL/select/logsql/query?start=<RFC3339>&limit=100
トレースの探索 → victoriatraces-query スキル
トレース探索エンドポイントでは、時間範囲のパラメーターを指定できません。
- サービス一覧:
$VM_TRACES_URL/api/services - サービスのオペレーション:
$VM_TRACES_URL/api/services/<service>/operations - 依存関係(Unix ミリ秒、13 桁):
$VM_TRACES_URL/api/dependencies?endTs=<ms>&lookback=3600000 - その後トレースを検索(
serviceは必須、時刻は Unix マイクロ秒、16 桁):$VM_TRACES_URL/api/traces?service=<svc>&start=<µs>&end=<µs>&limit=20
LogsQL クイックリファレンス
LogsQL の構文全般については、victorialogs-query スキルを呼び出してください。要点は次のとおりです。
- LogsQL はスペース区切りで、デフォルトでは AND です。パイプには
|を使います。 - ストリームフィルター:
{namespace="myapp"} - 単語フィルター:
{namespace="myapp"} error - OR:
(error OR warning)、正規表現:~"err|warn"、フィールド指定:level:error - 時間フィルター:
_time:1h(API のstart/endパラメーターの代替です。どちらか一方だけを使い、両方は使わないでください) - 否定:
-"expected error" - 統計:
| stats by (level) count() as total
よくある間違い: | grep は存在しません(単語フィルターまたは ~"regex" を使います)。| filter が有効なのは | stats の後だけです。ストリームのフィールド名は取り込み設定によって異なるため、まず検出してください。
調査プレイブック
「アプリケーションの動作が遅い」
- フェーズ 1:アラートを確認します。いつレイテンシーが増加したのか、時系列を把握します。
- フェーズ 2:アプリに該当するトレース対象サービスとメトリクスを検出します。
- フェーズ 3:仮説を立てます — 「[アラート/ユーザー報告] に基づくと、レイテンシーは [サービス X] にあります」
- そのサービスのレイテンシー/エラー率メトリクスをクエリします
minDurationフィルターを使ってトレースを検索し、遅いスパンを見つけます
- フェーズ 4:トレースのタイムスタンプと、その時刻付近のログを相関付けます。
「Pod がクラッシュループしている」
- フェーズ 1:アラートを確認します(すでに KubePodCrashLooping が表示されている場合があります)。Pod 名を取得します。
- フェーズ 2:再起動回数とメモリ使用量のメトリクスを検出します。その Pod のログストリームも検出します。
- フェーズ 3:仮説を立てます — OOM でしょうか? ライブネスプローブの失敗でしょうか? 起動時のクラッシュでしょうか?
- 一定間隔でクラッシュする場合 → ライブネスプローブ。クラッシュ前にメモリが急増する場合 → OOM。
- フェーズ 4:エラーログとメトリクスのタイムスタンプを相関付けて、原因を確認します。
「リソースが増加している」
- フェーズ 1:アラートを確認します。どのくらいの速さで増加していますか?
- フェーズ 2:名前空間/Pod のリソース使用量メトリクスを検出します。
- フェーズ 3:仮説を立てます — リークでしょうか? 負荷の増加でしょうか? 制限の設定漏れでしょうか?
deriv()またはincrease()を使って増加率を定量化します- Pod ごとの内訳を確認して、原因の Pod を特定します
- フェーズ 4:ログ内のデプロイイベントと相関付けます。デプロイ後に増加が始まりましたか?
よくある間違い
| 間違い | 修正方法 |
|---|---|
| メトリクス名を推測する | メタデータエンドポイントを使います:$VM_METRICS_URL/api/v1/metadata?metric=keyword |
| LogsQL を記憶だけで書く | 上記の LogsQL クイックリファレンスまたは victorialogs-query スキルを参照します |
| タイムスタンプの形式が間違っている | 上記の「タイムスタンプ形式」表を参照します |
| アラートの確認を省略する | まず $VM_METRICS_URL/api/v1/alerts をクエリします — 無料です |
| 結果が空 →「問題なし」と判断する | まず検出によってメトリクス/フィールド名が存在することを確認します |
ログの調査に facets を使わない | facets を使うと、1 回の呼び出しでフィールドの分布が返されます |
| クエリを URL エンコードしない | POST リクエストには --data-urlencode 'query=...' を使います |
VictoriaLogs で start を指定し忘れる | start を省略すると全データをスキャンします(非常に高コストです) |
match[] に [] が必要なことを忘れる | match だけでは機能しません — match[] が必要です |
| トレースのタイムスタンプ型が間違っている | 検索ではマイクロ秒(16 桁)、依存関係ではミリ秒(13 桁)を使います |
stats_query と stats_query_range を混同する | Instant では time、range では start/end/step を使います |
_time: フィルターと API の start を併用する | どちらか一方だけを使い、両方は使わないでください |
| 「error」を検索して vmselect のノイズを拾う | PromQL テキストを除外するには -"vm_slow_query_stats" を追加します |
cluster フィールドでログをグループ化する | Vector のログには cluster ストリームフィールドがありません — kubernetes.pod_namespace を使います |
| AlertManager の失敗で処理を止める | VM アラートを主に使い、AlertManager はベストエフォートで使います |
| 単一のシグナルだけで結論を出す | 根本原因を断定する前に、少なくとも 2 種類のシグナルを相関付けます |