CloudWatch Logs Insightsで5xxエラーを調査するときは、発生時間、エンドポイント、個別リクエストの順に対象を絞ります。本記事では、アプリケーションのJSONログを使い、集計結果から次の確認先を決めるまでの4ステップを解説します。
この記事でわかること
- 5xxエラーが集中する時間帯とエンドポイントの調べ方
- リクエストIDで処理の経過を追うクエリ
- ログから判断できることと、追加確認が必要なこと
- 検索結果が0件になる場合や、件数が重複する場合の確認点
この記事では、CloudWatch Logs Insightsを使い、発生時間 → エンドポイント → 個別リクエスト → 次の確認先の順に調査を進めます。各クエリのあとに「結果から分かること」と「まだ言えないこと」を整理します。
構文を調べたい方は、先にLogs Insightsのクエリパターン10選を参照してください。本記事は、クエリを障害調査の流れにつなげたい方に向けた実践例です。
この記事で扱うログと前提条件

CloudWatch LogsにアプリケーションのJSONログが収集されていることを前提にします。クエリ言語はLogs Insights QLです。ログ収集から確認したい方は、CloudWatch Logsの使い方ガイドを参照してください。
以下は説明用の架空のログです。アプリケーションがリクエスト終了時に1件の完了ログを出す設計を想定しています。
{
"event": "request_completed",
"service": "orders-api",
"status": 503,
"endpoint": "/orders",
"durationMs": 2400,
"requestId": "demo-req-001",
"message": "upstream request failed"
}
statusとdurationMsは数値、endpointはルート単位の値です。実際のログがstatusCodeやpathを使っている場合はクエリのフィールド名を合わせてください。リクエストごとに異なるIDを含むパスは、可能なら/orders/{id}のようなルート名で集計します。
調査前にロググループと時間範囲を絞る

まず対象サービスのロググループを選び、アラート発生時刻の前後を含む短い時間範囲で検索します。たとえば14時10分に通知されたなら、14時00分〜14時20分を最初の確認範囲にします。時刻を共有する際はJSTかUTCかも明記します。
必要なロググループと狭い時間範囲を選ぶことはAWS公式ドキュメントでも推奨されています。結果が少ない場合は、対象や収集状況を確認してから範囲を広げます。参考:Logs Insights QLの構文と利用上の注意
Logs Insightsで5xxの発生時間帯を確認する(ステップ1)
filter event = "request_completed"
and service = "orders-api"
and status >= 500 and status < 600
| stats count(*) as errors by bin(5m) as timeBucket
| sort timeBucket asc
最初に見るのは5分ごとの5xx完了ログ件数です。特定の時間帯だけ増えたのか、継続しているのかを確認します。statsは集計、bin(5m)は5分単位にまとめる指定です。参考:AWS公式のstats解説
ここで分かるのは検索対象に含まれるエラーの件数と時間的な偏りです。リクエスト総数を見ていないため、件数が増えたという結果だけでは、エラー率が悪化したとは言えません。アクセス数が増えている可能性もあります。
また、同じリクエストの完了ログが重複している場合や、ログを間引いている場合は、件数をそのまま失敗リクエスト数として扱えません。ログが出ない時間帯も、正常だったと即断せず、収集遅延や送信停止を確認します。
ステップ2:どのエンドポイントに偏っているか調べる
filter event = "request_completed"
and service = "orders-api"
and status >= 500 and status < 600
| stats count(*) as errors by endpoint, status
| sort errors desc
| limit 20
増加した時間帯へ検索範囲を合わせ、エンドポイントとステータス別に集計します。全体に広がっているか、特定のAPIへ集中しているかが次の調査先を決める手掛かりになります。
たとえば/ordersの503が多ければ、その処理が呼び出す外部サービスやDBへのアクセスを次の確認候補にできます。ただし503だけで「DBが原因」と決めることはできません。アプリケーションがどの条件で503を返すかも確認が必要です。
件数の多いAPIは単にアクセス数が多い可能性もあります。優先度を決めるときはリクエスト総数、利用者への影響、重要な業務が止まっていないかを併せて確認してください。
ステップ3:代表的なリクエストを1件追う
まず気になるエンドポイントの直近の失敗を確認します。
fields @timestamp, requestId, status, durationMs, @message
| filter event = "request_completed"
and service = "orders-api"
and endpoint = "/orders"
and status >= 500 and status < 600
| sort @timestamp desc
| limit 20
確認したrequestIdを使って、同じリクエストに属するログを時刻順に並べます。以下のIDは架空の値なので、実際に見つかった値へ置き換えてください。
fields @timestamp, @logStream, @message
| filter service = "orders-api"
and requestId = "demo-req-001"
| sort @timestamp asc
| limit 200
この段階では完了ログに限定する条件を外しています。処理途中の警告や例外にも同じIDが記録されていれば、「何をしてから失敗したか」を追えます。
リクエストIDが完了ログにしか付いていない場合は、途中経過までは追えません。また、複数サービスを横断するには、IDの伝播と対象ロググループの選択が必要です。1サービス内のログだけで処理全体を説明しないことが重要です。
ステップ4:ログの観測結果を次の確認につなげる

ログを読んだあとに「タイムアウトでした」で止めず、どの処理の何を確かめるかまで整理します。
| ログで観測したこと | 次に確認すること |
|---|---|
| 特定の外部呼び出しでタイムアウト | 呼び出し先の遅延・失敗、接続状況、設定されたタイムアウト値 |
| 同じ例外が特定APIに集中 | 例外直前の処理、入力条件、直近の変更との差分 |
| 複数APIで同時刻から失敗 | 共有する依存先、リソース状況、デプロイ時刻 |
| アラートは継続しているが対象ログがない | アラートの対象、リージョン、時間範囲、ログ収集状況 |
デプロイとエラー増加の時刻が一致しても、それだけで原因確定にはなりません。「観測した事実」と「確認中の仮説」を分けることで、調査を引き継ぎやすくなります。
共有するメモは次の形で十分です。実際の時刻・集計結果へ置き換え、ログ本文に含まれる個人情報や認証情報をそのまま転記しないでください。
対象:orders-api /orders
確認範囲:アラート発生前後の20分間(タイムゾーンを明記)
観測:5xxが集中する時間帯とステータスを集計した
未確認:総リクエスト数に対する失敗割合、影響範囲、原因
次の確認:代表的な失敗リクエストと依存先の状態を照合する
クエリで期待した結果が得られないとき
0件になる
ロググループ、リージョン、時間範囲を確認し、まずfields @timestamp, @message | sort @timestamp desc | limit 20で実際の形式を見ます。この記事の例とフィールド名や値が一致しているかを確認してください。JSONが別フィールドの文字列に埋め込まれている形式などでは、追加の解析が必要です。
同じエラーが何度も数えられる
処理途中のエラーとリクエスト完了ログを一緒に数えていないか確認します。本記事でevent = "request_completed"を指定したのは集計対象をそろえるためです。リトライ時に同じIDを使うかなど、アプリケーション側の記録ルールも確認します。
検索対象が多すぎる
ロググループと時間範囲を見直します。表示行数を絞るlimitだけをコスト対策として当てにせず、必要な範囲で調査を進めてください。実行不要になったクエリは停止します。
クエリを実際の障害調査に役立てる
今回の調査では最初に発生時間を確認し、次にエンドポイントを絞り、代表的なリクエストを追いました。この順番を持っておくと、ログを開いたあとに何を確かめるか決めやすくなります。
実際の環境ではログの形式や障害の起こり方が変わります。クエリをコピーするだけでなく、「この条件で何を数えているか」「結果から何が言えるか」を説明する練習が実務で役立ちます。

コメント