夜のオフィスで、左右に並んだ2台のモニターを見比べながら、片方の画面にだけ赤い警告マークが出ていることに首をかしげる保守運用の担当者

本番でしか起きない不具合を追う|ログとデータ差分の調べ方

「本番で、また例のエラーが出ました」

連絡を受けて、検証環境で同じ操作をしてみる。何度やっても、ちゃんと動く。ローカルでも動く。コードも同じはずなのに、本番だけで、しかも「ときどき」起きる。再現しない不具合ほど、手の打ちようがなくて落ち着かないものです。

これは、あなたの調べ方が足りないわけではありません。本番と検証は、コードが同じでも「まったく同じ環境」ではないからです。データの中身、設定、アクセスの量やタイミング、つながっている外部のサービス。本番だけで起きる不具合は、たいていこの「違い」のどこかに隠れています。

この記事では、本番でしか起きない不具合を、ログとデータの差分から追っていく順番を、小さく分けて一緒に整理していきます。

結論:本番だけの不具合は、次の4つの順で追います。①起きた瞬間をログでつかむ(いつ・誰が・どのデータで)、②「違い」をデータ・設定・量とタイミング・外部の4つに分けて当たりをつける、③失敗した行と成功した行を並べて、差分を見つける、④見つけた差分を検証環境に持ち込んで再現してから直す。本番では「見るだけ」に徹し、データを書き換えたり、試しに設定を変えたりしないのが基本です。

なお、コマンドや設定の名前・確認方法は、OS・ミドルウェア・バージョンで変わります。ここで持ち帰ってほしいのは順番と観点です。手元の環境の公式ドキュメントで確かめ、変更は必ず検証環境で試してから本番に反映してください。

何が起きているか:本番と検証には「4つの違い」がある

本番だけで起きる不具合の原因は、ほとんどが次の4つのどれかです。

「再現しない」は、言いかえると「検証には、本番のどれかの違いが足りていない」ということです。足りない違いを1つずつ探していけば、再現にちゃんと近づけます。

本番だけの不具合を追う4つの手順

① 起きた瞬間をログでつかむ

最初にやるのは、検証で再現させることではなく、本番で起きたときの事実を集めることです。エラーログ・アクセスログ・アプリのログから、次の3つを書き出します。

# エラーが出た時刻の前後だけを見る(パスやログの形式は環境に合わせて)
grep "2026-10-07 14:3" /var/log/app/error.log | less

# 同じエラーが何回、どの時間帯に出ているかを数える
grep "Undefined index" /var/log/app/error.log | cut -c1-13 | sort | uniq -c

大量のログから絞り込むコツはgrep・tail・lessでエラーを絞り込むにまとめています。ログに対象のIDが出ていなくて追えないときは、次に起きたときのために、処理の入口でIDを書き出すログを1行足しておきます(改修時にログを仕込んで原因を追う)。パスワードや個人情報はログに出さないよう、気をつけてください。

② 「違い」を4つに分けて当たりをつける

集めた事実を、さっきの4つの違いに当てはめます。症状から、疑う場所がかなり絞れます。

症状のくせ疑う違いまず見るところ
特定の注文・会員・ファイルでだけ起きるデータの違いエラーになった行そのものの中身
どの操作でも起きる、または特定の機能だけ必ず起きる設定の違いPHP・DB・Webサーバの設定値、環境変数
夕方や月末、バッチの時間帯に起きる。たまにしか起きない量とタイミングの違いその時間の件数・同時アクセス・スロークエリ
決済・メール・連携の前後でだけ起きる外部とのつながりの違い外部への通信ログ、相手から返ってきた応答

いちばん多いのは、データの違いです。「たまに起きる」と感じる不具合も、実は「特定の行に当たったときだけ起きる」ことがよくあります。迷ったら、まずデータから疑ってみてください。

③ 失敗した行と成功した行を並べて、差分を見つける

左に緑のチェックがついた正常な書類カード、右に赤いバツがついたエラーの書類カードが並び、右のカードの空欄になった1行だけに虫眼鏡が当てられている図
うまくいった行と、エラーになった行を並べてくらべる。片方にだけある「くせ」が、本番だけの不具合の入口になる

ここがいちばん効く手順です。①で特定したエラーになったデータと、同じ操作で問題なく動いたデータを1件ずつ選び、横に並べてくらべます。

-- エラーになった注文と、正常に処理された注文を並べて見る(閲覧だけ。テーブル名・列名は環境に合わせて)
SELECT * FROM orders WHERE id IN (10234, 10235)\G

見るポイントは、片方にだけある「くせ」です。

設定の違いを疑うときも、同じように本番と検証の値を並べて差分を出します。目で見くらべるより、ファイルに書き出して diff にかけるほうが確実です。

# PHPの設定を本番・検証それぞれで書き出し、手元で差分を見る
php -i > php_honban.txt     # 本番で実行
php -i > php_kensho.txt     # 検証で実行
diff php_kensho.txt php_honban.txt
-- DBの設定値を書き出す(MySQLの例。PostgreSQLなら SHOW ALL;)
SHOW VARIABLES WHERE Variable_name IN ('sql_mode', 'character_set_server', 'max_allowed_packet', 'time_zone');

ライブラリのバージョンも、composer show や pip freeze などで両方の一覧を書き出せば、同じように diff でくらべられます。差分が出た行が、そのまま調べる候補のリストになります。

④ 見つけた差分を検証環境に持ち込んで再現する

差分が見つかったら、それを検証環境に持ち込んで、同じエラーが起きるかを確かめます。

検証で同じエラーが出せたら、原因はほぼ確定です。そこから先は、ふだんのバグ調査と同じ流れで直していけます(バグ報告から再現・原因特定までの最短ルート)。

具体例:「ときどき注文確定でエラーになる」を4つの手順で追う

社内のECサイトを一人で保守している担当者の、よくある流れです。

変わったのは、調べる腕ではありません。「検証で再現させよう」とする前に、本番で起きた行と、うまくいった行を並べたことです。「もう一度お試しください」と返す日も、それきりなくなりました。

影響:本番だけの不具合を追えるようになると、何が変わるか

明日やること

  1. 最近の「再現しない」不具合を1つ思い出す。②の表の4つの違いのどれに近いか、当てはめてみます。
  2. その不具合のログに、対象データのIDが出ているか確かめる。出ていなければ、IDを書き出すログを1行足す候補にします。
  3. 本番と検証の設定を1つだけ書き出してくらべる。php -i でも、DBの SHOW VARIABLES でも、どちらか1つで大丈夫です。
  4. 検証データに「くせのある行」を1件足す。空欄・長い名前・絵文字が入った会員や注文を1件作っておきます。

今日やるのは、3の「設定を1つ書き出してくらべる」だけでも十分です。差分が出なければ一安心、出たら、次に「本番だけ」が起きたときの有力な手がかりが1つ見つかったということです。

本番だけの不具合を追うチェックリスト

全部を一度にそろえなくても大丈夫です。まずは「起きた瞬間をログでつかむ」と「失敗した行と成功した行を並べる」の2つだけで、つかめなかった不具合がぐっと近くに見えてきます。

よければ、こちらも

明るい朝のオフィスで、左右2台のモニターの両方に緑のチェックマークが出ているのを見て、ほっとした笑顔を浮かべる保守運用の担当者
違いが見つかれば、「本番だけ」はもう謎ではなくなる

「本番でしか起きない」と悩んだ時間は、無駄ではありません。それは、検証で動いたことに安心しきらずに、本番で困っている人のほうを向き続けたしるしです。本番だけの不具合にも、必ずどこかに「違い」があります。違いを1つずつ並べていけば、その場所に少しずつ近づけます。

まずは明日、本番と検証の設定を、1つだけ書き出してくらべてみてください。

ほかの実務ヒントは記事一覧からどうぞ。保守運用の小さな備えを、メールでも少しずつお届けしています。

関連用語