laravel-debugbarとIgnitionで詰まりを素早く解消する

概要

Laravel開発では「画面が真っ白」「レスポンスは返るが中身がおかしい」「SQLが想定より何倍も飛んでいる」といった詰まりが日常的に起きます。これらを勘とログの往復で潰すのは非効率です。

本記事では、Laravel標準のエラー画面を担う Ignition(spatie/laravel-ignition) と、リクエストの内部挙動を可視化する laravel-debugbar(barryvdh/laravel-debugbar) を組み合わせ、「どこで詰まっているか」を素早く切り分ける手順を整理します。公開情報とパッケージの一般的な挙動に基づいています。

この2つは守備範囲が異なります。例外が発生して処理が止まったときはIgnition、例外は出ないが挙動が怪しいときはDebugbar、という役割分担を押さえると切り分けが速くなります。

環境

  • PHP 8.2 以上(Laravel 13 は 8.3 以上)
  • Laravel 11 / 12 / 13 系
  • barryvdh/laravel-debugbar(開発依存)
  • spatie/laravel-ignition(Laravel 9 以降は標準同梱、Laravel 8.x 以前は facade/ignition)

なお、Laravel 11 以降は例外ハンドラの登録先が bootstrap/app.php の withExceptions() に移っています(従来の App\Exceptions\Handler 中心の構成から変更)。Ignition が標準同梱である点は変わりません。

Debugbar は明示的に追加します。

composer require barryvdh/laravel-debugbar --dev

--dev を付けて開発依存にするのが重要です。本番混入を防ぐ第一の防波堤になります。

発生した問題

典型的な「詰まり」を3パターンに分けます。

  1. 例外で処理が止まる: フォーム送信後に500、または画面が真っ白
  2. 処理は通るが結果が変: 一覧に出るはずのデータが欠ける、更新が反映されない
  3. 動くが遅い: 一覧ページの読み込みが遅い(N+1クエリの疑い)

ログを tail して該当行を探すだけでは、どの層(ルーティング/コントローラ/クエリ/ビュー)で起きているかが見えにくく、調査が長引きます。

原因

詰まりの正体は多くの場合、次のいずれかに収束します。

  • 例外の発生箇所と、実際に修正すべき箇所がずれている(トレースを追えていない)
  • Eloquentのリレーションをループ内で都度ロードしている(N+1)
  • ビューに渡したつもりの変数が渡っていない/型が想定と違う
  • セッションや認証状態が想定と異なる

「どの層で何が起きたか」を可視化できれば、原因特定までの時間が大きく短縮されます。

対応方法

Ignitionで「止まった場所」を特定する

.env で APP_DEBUG=true のとき、例外発生時にIgnitionの詳細エラー画面が表示されます。見るべき点は3つです。

  • スタックトレースの「アプリ側のフレーム」まで降りて確認する(ベンダー内部で止まらない)
  • 例外の型で原因の層を先に絞る: QueryException→SQL、ViewException→Blade、TypeError→型不一致
  • Request / Context タブで、送られたパラメータが想定どおりか確認する

Debugbarで「通っているが怪しい処理」を覗く

APP_DEBUG=true でDebugbarが有効なとき、画面下部にバーが表示されます。よく使うタブは以下です。

タブ 見るもの 切り分け
Queries 実行SQL・件数・実行時間 N+1、想定外のWHERE、重い結合
Views レンダリングされたBladeと渡された変数 変数未定義・型違い
Route ルート・コントローラ・ミドルウェア ルーティングの取り違え
Request 入力・セッション・認証ユーザ 認証状態・入力値
Timeline 処理区間の時間 どの処理が遅いか

特に Queriesタブのクエリ件数 は強力です。一覧ページを開いた瞬間に数十〜数百のクエリが並んでいれば、N+1がほぼ確定します。

コード側からDebugbarに情報を送る

use Barryvdh\Debugbar\Facades\Debugbar;

public function index()
{
    $orders = Order::with('customer')->get();

    Debugbar::info($orders->count());

    Debugbar::startMeasure('aggregate', '集計処理');
    $summary = $this->buildSummary($orders);
    Debugbar::stopMeasure('aggregate');

    return view('orders.index', compact('orders', 'summary'));
}

dd() のように処理を止めずに値や処理時間を確認できるため、流れを追う調査と相性が良いです。

実装例

N+1をDebugbarで見つけて潰す

まず問題のあるコードです。

// 遅い: ループ内で customer を都度ロード(N+1)
$orders = Order::all();

foreach ($orders as $order) {
    echo $order->customer->name; // 毎回クエリが飛ぶ
}

Debugbarの Queries タブを開くと、select * from customers where id = ? が注文件数ぶん並びます。「感覚的に遅い」が「クエリが多い」という具体に変わります。

対策は eager loading です。

// 速い: 関連を一括ロード
$orders = Order::with('customer')->get();

foreach ($orders as $order) {
    echo $order->customer->name; // 追加クエリは飛ばない
}

修正後にもう一度 Queries タブを確認し、件数が2クエリ程度に減っていれば解消です。同じ画面で件数の前後比較をするのがポイントです。

「変数が渡っていない」をViewsタブで確認する

compact() の綴りミスなど「渡しているつもりで渡せていない」ケースは、Views タブで実際に渡っている変数一覧を見るのが確実です。

確認方法

  • Ignition: APP_DEBUG=true でわざと例外を起こし、詳細画面が出るか
  • Debugbar: 任意ページでバーが表示されるか
  • N+1: 修正前後でクエリ件数が明確に減ったか
  • 本番で両方とも無効化されているか

注意点

最重要は本番での無効化です。 DebugbarもIgnitionの詳細表示も、内部構造・SQL・環境情報を画面に露出します。本番で有効なままだと情報漏えいに直結します。

  • 本番は APP_DEBUG=false を徹底する。Ignitionの詳細画面は標準エラーページに切り替わる
  • Debugbar は DEBUGBAR_ENABLED または config/debugbar.php の enabled で制御する
  • Debugbar は必ず --dev で導入し、本番の composer install --no-dev で混入させない
  • Debugbar自体が負荷をかけるため、計測の絶対値ではなく傾向・件数比較に使う
  • API / JSONレスポンスにはバーが出ないため、クエリ確認は別手段と併用する

まとめ

  • 止まる系はIgnition、通るけど怪しい系はDebugbar、という役割分担で切り分けを速くする
  • N+1はDebugbarのQueriesタブの件数で可視化し、with()修正後に件数比較まで行う
  • Debugbar::info() / startMeasure() で、処理を止めずに流れと時間を追える
  • 本番では APP_DEBUG=false とDebugbar無効化・--dev導入を徹底し、情報露出を防ぐ

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。