
AIにログ出力の不足を指摘させる|障害調査で困らない設計
「昨日の夕方、注文が通らなかったお客様がいるそうです」
朝いちばんにそう言われて、ログを開く。該当しそうな時間帯までさかのぼって、目で追って、そして手が止まります。残っているのは、エラーが発生しました の1行だけ。
誰の注文なのか。どの処理まで進んでいたのか。何を渡して、何が返ってきたのか。どれも書いてありません。調べる気がないわけではなく、調べるための材料が、その場に残っていなかっただけです。
ログは、動いているときはほとんど誰も見ません。見るのは、困ったときだけです。だから「足りているか」は、いつも足りなかったと分かった後に判明します。
この記事では、その順番をひっくり返す方法——AIにログの不足を先に指摘させる進め方を整理します。コードを書き直す話ではありません。いま出しているログで、昨日の障害を説明できるかを確かめる話です。
結論:見るのは3つだけです。①たどる——1件の処理を、入口から出口まで1本の線でつなげるか。相関ID(同じ処理に付けて回す1つの目印)が入っていないと、ここで止まります。②わかる——ログ1行から、いつ・誰の・何の処理が・どうなったかが復元できるか。③出さない——個人情報・秘密情報・巨大なデータを、ログに書かないと決められているか。
覚え方は たどる → わかる → 出さない。①がないと②をいくら足しても線にならず、③を後回しにすると、増やしたログがそのままリスクになります。
そしてAIに頼むときのコツは1つ。「ログを足して」と頼まないことです。そう頼むと、関数の入口と出口すべてに1行ずつ、という案が返ってきます。量は10倍になり、調査は逆に遅くなります。頼むのは、「この障害を再現なしで説明するには、どの情報が足りないか」です。
全部を今週やる必要はありません。①の相関IDを1つ通すだけでも、次の調査の景色が変わります。
何が起きているのか——ログは「書いた人」の視点で残ってしまう

打ち手の前に、なぜ足りなくなるのかを整理します。原因が分かっていると、AIに渡す前提も書きやすくなります。
1つ目は、ログを書くのが「実装している最中」だということ。実装中は、自分がいま何をしているか全部わかっています。だから 処理開始 の3文字でも困りません。困るのは、半年後に、別の人が、状況を知らないまま読むときです。ログの不足は、腕前の話ではなく、書く時点と読む時点で持っている情報が違うという話です。
2つ目は、成功したときのログばかり残ること。ハッピーパス(うまくいく道筋)はテスト中に何度も通るので、自然とログも整います。一方、めったに通らない分岐は、通らないまま本番に出ます。調査で見たいのは、まさにその通らなかった側です。
3つ目は、例外の情報が途中で削れること。catch したあと、ログ.error("失敗しました") とだけ書いて、元の例外を渡し忘れる。よくある形です。スタックトレース(どこで落ちたかの経路)が消えると、原因の場所そのものが分からなくなります(AIにエラーハンドリング方針を相談する|握りつぶさない設計)。
4つ目は、多すぎて読めないこと。足りないのと同じくらい厄介なのが、多すぎるログです。1リクエストで数百行出ていると、必要な1行がその中に埋もれます。しかも保存料金がかさむので、「量を減らそう」という話になり、大事な行まで一緒に消えたりします。
5つ目は、処理が分かれていて線にならないこと。画面、API、非同期のワーカー、外部サービス。ログはそれぞれの場所に、それぞれの時刻で残ります。同じ処理だと分かる目印がないと、突き合わせは人の勘に頼ることになります(AIに非同期・並行処理を書かせる|競合とデッドロックの確認)。
6つ目は、AIに頼むとまさに量が増えること。「ログが足りないので足してください」と頼むと、律儀に全関数へ入口・出口のログを入れてくれます。動きますし、レビューでも指摘しにくい。でも調査は速くなりません。AIが悪いのではなく、「調査で何を知りたいか」を渡していないからです。ここは前提の渡し方でほぼ決まります(AIにコードを書かせる前に渡す前提と制約|伝え方の型)。
裏を返せば、これは注意力の問題ではなく、見る順番の問題です。順番が決まっていれば、AIはかなり役に立つ相談相手になります。
具体例——つい、こうなりがちという形
どれも「まず動くものを」という自然な流れから生まれます。心当たりのある行があれば、そこだけ見れば十分です。
エラーが発生しましただけが残る:何のエラーかも、どのデータでかも書いていない。調査は、その時刻の周辺を目で追うところから始まります。- 例外を握って、メッセージだけログに出す:
e.getMessage()相当だけを出して、例外そのものを渡していない。落ちた場所が消えます(スタックトレースをAIに読ませる|バグ調査を速くする渡し方)。 - 同じ例外が、各層で3回ログに出る:下位でも中位でも上位でも
errorを出していて、1つの障害が3件に見える。件数が信用できなくなります。 - 成功だけ
INFO、失敗は何も出ない:分岐の片側にしかログがない。「通らなかった」のか「通って失敗した」のかが区別できません。 DEBUGに大事な情報が入っている:本番ではDEBUGを出していないので、いざというとき何も残っていない。- ログはあるが、どのユーザーの処理か書いていない:問い合わせは「Aさんの注文」で来ます。ログ側にひもづける手がかりがないと、突き合わせができません。
- JSONの本文をまるごとログに出している:見た目は親切ですが、住所や電話番号が混ざります。便利さと引き換えに、消しにくいものが残ります(社内データをAIに渡す前の線引き|情報漏えいを防ぐ型)。
- リトライのログが出ていない:2回目・3回目の試行が黙って行われていて、あとから「本当に1回だったのか」が分からない(AIに冪等性の設計を相談する|リトライで二重実行させない型)。
- 時刻がサーバのローカル時刻:複数台のログを並べると、順番が入れ替わって見える。原因と結果が逆に見えることさえあります。
- 外部サービスの応答を、成功時しか記録していない:相手が返した内容が分からないので、こちら側の問題か向こう側の問題かを切り分けられません。
影響——「調査できない」は、静かにコストになる
急いで全部直さないと危ない、という話ではありません。ただ、出方が地味で、出たときに時間を持っていかれる種類の問題なので、書いておきます。
- 原因究明が、推測になる:材料がないと、「たぶんこの辺です」としか言えません。直しても、直った確信が持てません。
- 調査時間が読めない:見積もれないので、他の予定が全部後ろにずれます。障害対応そのものより、待たせている時間のほうが痛いことがあります。
- 再現待ちになる:ログで分からないと、「また起きたら教えてください」になります。お客様にもう一度困ってもらう、という形になりがちです(AIに障害の再現手順を整理させる|報告と切り分けを速く)。
- 説明が苦しくなる:「原因は特定できていません」と報告するのは、実装の何倍もエネルギーが要ります。不注意に聞こえてしまうのもつらいところです。
- 個人情報がログに残り続ける:出すのは一瞬ですが、消すのは大仕事です。バックアップや転送先にも複製されていることがあります。
- 保存料金が、静かに増える:量で殴る運用は、月々の請求として効いてきます。しかも増えた分の多くは、読まれません。
- AI機能では特に効く:応答が毎回同じとは限らないので、そのとき何を渡して何が返ったかが残っていないと、後から検証しようがありません(AIのハルシネーションの見抜き方|開発現場で気づく型)。
少し安心できる話をすると、この領域は費用対効果がはっきりしています。作り替えは要りません。相関IDを1つ通して、ログの形を揃えるだけで、次の調査は目に見えて楽になります。
明日からやること(たどる・わかる・出さない)
上から順に、小さく始められます。今日は①だけで構いません。
1. たどる——1件の処理を、1本の線にする
ここを飛ばして情報量だけ増やしても、点が散らばるだけです。逆に、ここさえ通れば、後の作業は楽になります。
- 相関ID(リクエストID)を1つ決めて、最初から最後まで持ち回る。入口で1つ発番して、そこから先のログすべてに同じ値を載せます。これ1つで、バラバラだったログが1本の線になります。
- 非同期の先にも、必ず引き継ぐ。キューに積むとき、ジョブを起こすとき、別サービスを呼ぶとき。切れやすいのは、処理が別のところへ渡る瞬間です。ここだけは意識して確認します。
- 外部との受け渡しは、標準の形に乗せると楽。HTTPの呼び出しでは、トレース情報をヘッダで受け渡す共通の決まり(W3C の Trace Context など)があります。分散トレースの仕組み(OpenTelemetry など)を使うなら、それに合わせておくと後が楽です。まずは自前のヘッダ1つでも十分なので、通すことを優先します。
- 問い合わせ番号として使えるようにする。エラー画面や返却する応答に相関IDを出しておくと、お客様やサポートから「この番号です」と言ってもらえます。探す時間がまるごと消えます。
- 1件だけ、実際にたどってみる。設計として通っているかではなく、本番相当のログを検索して、入口から出口まで並ぶかを目で確かめます。ここで初めて、切れている場所が見つかります。
2. わかる——1行から、状況が復元できるようにする
情報を足す工程ですが、足すのは「行数」ではなく「1行の中身」です。
- 1行に入れる項目を、チームで決める。目安は、時刻(タイムゾーンを含む形)・相関ID・利用者や対象の識別子・処理名・結果・かかった時間。決めておくと、書く人ごとのばらつきが減ります。
- 時刻はタイムゾーンが分かる形で統一する。複数台・複数サービスで並べたときに、順番が正しく並ぶことが調査では効きます(AIに日付・タイムゾーン処理を書かせる|ズレる定番バグの確認手順)。
- 機械が読める形(構造化ログ)にする。項目ごとに分かれていると、後から絞り込みや集計ができます。文章にして埋め込むと、検索でしか探せなくなります。
- 失敗の側を厚くする。成功は件数と所要時間くらいで足ります。大事なのは、失敗したときに何を握っていたかです。入力の要約(識別子や件数など、中身そのものではないもの)、判定結果、外部からの応答コード。
- 例外は、例外オブジェクトごと渡す。メッセージを文字列にして出すのではなく、ログの仕組みに例外を渡してスタックトレースを残します。出すのは、最終的に処理する場所で1回だけ。各層で出すと、同じ障害が何件にも見えます。
- 分岐の「通らなかった側」にもログを置く。とくに、早期リターン・条件で弾いた・上限に達した、といった箇所。「何も起きなかった」の理由が残っていると、調査が一気に短くなります。
- ログレベルの意味を、チームで一言ずつ決める。「
WARNは続行できるが人が見たほうがよいこと」「ERRORは処理が完了しなかったこと」など。決まっていないと、ERRORの件数がアラートの役に立ちません。 - 量が多い場所は、まとめて出す。ループの中で1件ずつ出さず、終わったところで件数と失敗数を1行に。読めるログのほうが、多いログより強いです。
3. 出さない——書いてはいけないものを、先に決める
②で情報を増やすなら、③は同時にやります。順番を逆にすると、消す作業が発生します。
- 出さないものを、具体名で列挙する。パスワード、認証トークン、APIキー、クレジットカード番号、氏名・住所・電話番号・メールアドレス、健康や信条に関わる情報。「機密情報に注意」では運用されません。具体名にします。
- 本文まるごとを出すのをやめる。リクエストやレスポンスの全文ログは、最初は便利で、あとで必ず困ります。出すのは識別子と件数、必要なら項目名だけにします。
- マスクは、出力の直前でまとめてかける。書く人ごとに気をつける形だと、いつか漏れます。共通の処理に寄せて、そこだけレビューすれば済むようにするのが現実的です。
- 保持期間を決める。「ずっと残す」は、事故が起きたときに影響範囲が広がります。調査に必要な期間+αで決めて、それ以上は消えるようにします。
- 誰が見られるかを決める。ログの閲覧権限は、意外と広くなりがちです。本番ログは、本番データと同じ扱いが原則です(AIエージェントに本番環境と認証情報を渡す前に|権限の絞り方)。
- AIに調査を手伝わせるときは、貼る前に外す。ログをそのままAIに貼って原因を聞くのは有効ですが、貼る前に個人情報と鍵を落とす。ここは手順として決めておきます。
AIに相談するときのプロンプト(コピーして使えます)
前提を渡さないと、AIは素直に「全関数にログを追加」を出してきます。調査の場面を先に渡すのがコツです。
いま動いているコードのログ出力に不足がないかを点検したいので、相談に乗ってください。目的は量を増やすことではなく、障害調査を速くすることです。
①まず、この処理で起こりうる失敗を、思いつく限り挙げてください(入力不正、外部サービスの失敗・遅延、権限不足、データ不整合、タイムアウト、想定外の状態など)。
②その失敗が実際に起きたとき、いまのログだけで原因を説明できるかを1件ずつ判定し、説明できないものだけ「何の情報が足りないか」を書いてください。
③「すべての関数の入口と出口にログを足す」案は出さないでください。読む量が増えて調査が遅くなるためです。足すなら、失敗の分岐と外部との境界に絞って提案してください。
④1件の処理を最初から最後まで追えるか(相関IDが引き継がれているか)を確認し、切れている箇所を指摘してください。とくに非同期処理・キュー・外部呼び出しの前後を見てください。
⑤ログに出してはいけない情報が混ざっていないかを指摘してください(個人情報、認証情報、リクエスト本文の全文など)。
⑥逆に、多すぎて減らしてよいログがあれば挙げてください。
⑦最後に、この点検では分からないことを正直に挙げてください。
なお、確実でない部分は「不明」と書いてください。埋めなくて構いません。
対象の処理:( ) 言語・ログの仕組み:( ) 外部連携:( ) 実際に起きた障害(あれば):( )
```
(対象のコードと、いま出ているログの実例を貼る。個人情報・鍵は外してから)
```
③と⑥が効きます。「増やすな」と「減らせ」を同時に言うと、返ってくる指摘がぐっと実務的になります(設計レビューの見落としをAIに洗わせる|プロンプトの型)。
もうひとつ、実際に効く使い方があります。過去に起きた障害を1件持ってきて、そのときのログだけをAIに渡し、「これで原因を説明できますか」と聞く。説明できないと返ってきたら、その「足りない」がそのまま改善リストです。仮の話より、実際に困った1件のほうが、はるかに正確に不足を炙り出せます。
出てきた指摘は、次の3点だけ自分の目で確かめます。(1)相関IDが本当に非同期の先まで届いているか、(2)例外がスタックトレースごと残っているか、(3)増やそうとしているログに、出してはいけない情報が混ざっていないか。この3点は、もっともらしい説明で埋まっていても抜けていることがあります(AIにコードレビューの一次チェックを任せる|範囲と注意点)。
ログを見直すチェックリスト(コピーして使えます)
全部に○が要るわけではありません。気になった行だけで十分です。
① たどる
- 入口で相関ID(リクエストID)を発番しているか
- その値が、ログのすべての行に載っているか
- 非同期処理・キュー・ジョブの先まで引き継がれているか
- 外部サービスの呼び出しでも受け渡しているか
- エラー画面や応答に、問い合わせ用として出しているか
- 1件を実際に検索して、入口から出口まで並ぶことを確かめたか
② わかる
- 1行に入れる項目(時刻・相関ID・対象・処理名・結果・所要時間)を決めたか
- 時刻がタイムゾーンの分かる形で統一されているか
- 機械が読める形(構造化ログ)になっているか
- 失敗したときに、入力の要約と外部の応答が残るか
- 例外をオブジェクトごと渡して、スタックトレースが残っているか
- 同じ例外を複数の層で重ねて出していないか
- 早期リターンや条件で弾いた箇所にも、理由が残るか
- ログレベルの意味をチームで決めたか
- ループの中で1件ずつ出さず、まとめて出しているか
③ 出さない
- 出してはいけない情報を、具体名で列挙したか
- リクエスト・レスポンスの全文を出していないか
- マスク処理を共通の場所に寄せたか
- 保持期間を決めたか
- 本番ログの閲覧権限を決めたか
- AIにログを貼る前に、個人情報と鍵を落とす手順があるか
この記事のまとめ
ログの不足は、書いた人の腕前ではなく、書く時点と読む時点のズレから生まれます。だから、実装中に気をつけるより、あとから点検して埋めるほうが確実です。
見るのは3つ。①たどる——相関IDを1つ通して、非同期の先まで引き継ぐ。②わかる——1行の中身を揃え、失敗の側を厚くし、例外はスタックトレースごと1回だけ出す。③出さない——出してはいけない情報を具体名で決め、マスクを共通の場所に寄せる。
AIに頼むときは、「ログを足して」ではなく「この障害を説明できるか」と聞く。そして「全関数に入口と出口のログを足す案は出さないで」と先に一言添える。それだけで、返ってくる指摘の質が変わります。

ログが足りなかった朝、たぶん「なんで自分は書いておかなかったんだろう」と思ったはずです。でも、実装していたときのあなたは、その障害をまだ知りませんでした。知らないことは、書けません。
ログは、一度で完成させるものではありません。困るたびに1か所ずつ厚くしていくものです。今回困った場所は、次の人が困らない場所になります。
今日は、直近で調べにくかった障害を1件だけ思い出して、「あのとき何が残っていれば早かったか」を1行書いてみる。それだけで、次の朝のログは、少し親切になっています。
よければ、こちらも
- 落ちた場所を読むならスタックトレースをAIに読ませる|バグ調査を速くする渡し方
- 調査の入口はAIに障害の再現手順を整理させる|報告と切り分けを速く
- 例外の扱いはAIにエラーハンドリング方針を相談する|握りつぶさない設計
- 指標としてのログはAI機能の効果測定|導入後に見るログと指標の設計
- 出してはいけない情報は社内データをAIに渡す前の線引き|情報漏えいを防ぐ型
- 前提の渡し方はAIにコードを書かせる前に渡す前提と制約|伝え方の型
- 一次チェックの任せ方はAIにコードレビューの一次チェックを任せる|範囲と注意点
- 時刻のズレはAIに日付・タイムゾーン処理を書かせる|ズレる定番バグの確認手順