# Laravel Ignition Laravel Ignition is a beautiful, customizable error page for Laravel applications running on PHP 8.1+ and Laravel 10+. It transforms exceptions into actionable insights with intelligent solution suggestions, stack trace analysis, and detailed context about queries, logs, and dumps. The package seamlessly integrates with Flare for production error tracking and notification. Beyond displaying errors, Ignition records application context during execution including database queries, log messages, variable dumps, and queued jobs. It provides intelligent solution providers that analyze common Laravel errors and suggest fixes, with some solutions being executable directly from the error page. The package includes middleware for enriching error reports, recorders for capturing runtime data, and a complete API for programmatic error handling and reporting. ## Configuration ### Publishing Configuration Files ```bash # Publish Ignition configuration php artisan vendor:publish --tag=ignition-config # Publish Flare configuration (for error tracking service) php artisan vendor:publish --tag=flare-config ``` ### Basic Configuration Setup ```php // config/ignition.php return [ // Set preferred editor for "Open in Editor" buttons 'editor' => env('IGNITION_EDITOR', 'phpstorm'), // phpstorm, vscode, sublime, etc. // Theme preference 'theme' => env('IGNITION_THEME', 'auto'), // light, dark, auto // Enable/disable error sharing functionality 'enable_share_button' => env('IGNITION_SHARING_ENABLED', true), // Enable runnable solutions (auto-fixes) in local environment 'enable_runnable_solutions' => env('IGNITION_ENABLE_RUNNABLE_SOLUTIONS'), // Configure OpenAI for AI-powered solution suggestions 'open_ai_key' => env('IGNITION_OPEN_AI_KEY'), // Solution providers to load 'solution_providers' => [ \Spatie\LaravelIgnition\Solutions\SolutionProviders\MissingAppKeySolutionProvider::class, \Spatie\LaravelIgnition\Solutions\SolutionProviders\TableNotFoundSolutionProvider::class, \Spatie\LaravelIgnition\Solutions\SolutionProviders\ViewNotFoundSolutionProvider::class, // ... more providers ], // Recorders for capturing runtime context 'recorders' => [ \Spatie\LaravelIgnition\Recorders\DumpRecorder\DumpRecorder::class, \Spatie\LaravelIgnition\Recorders\JobRecorder\JobRecorder::class, \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, ], ]; ``` ### Flare Integration Configuration ```php // config/flare.php return [ // Flare API key for production error tracking 'key' => env('FLARE_KEY'), // Middleware to enrich error reports 'flare_middleware' => [ \Spatie\FlareClient\FlareMiddleware\RemoveRequestIp::class, \Spatie\FlareClient\FlareMiddleware\AddGitInformation::class, \Spatie\LaravelIgnition\FlareMiddleware\AddLogs::class => [ 'maximum_number_of_collected_logs' => 200, ], \Spatie\LaravelIgnition\FlareMiddleware\AddQueries::class => [ 'maximum_number_of_collected_queries' => 200, 'report_query_bindings' => true, ], \Spatie\LaravelIgnition\FlareMiddleware\AddJobs::class => [ 'max_chained_job_reporting_depth' => 5, ], \Spatie\FlareClient\FlareMiddleware\CensorRequestBodyFields::class => [ 'censor_fields' => ['password', 'password_confirmation', 'api_token'], ], \Spatie\FlareClient\FlareMiddleware\CensorRequestHeaders::class => [ 'headers' => ['API-KEY', 'Authorization', 'Cookie', 'Set-Cookie'], ], ], // Control log event sending 'send_logs_as_events' => true, ]; ``` ## Flare Facade API ### Adding Custom Context to Error Reports ```php use Spatie\LaravelIgnition\Facades\Flare; // Add single context value Flare::context('user_role', 'admin'); Flare::context('subscription_plan', 'premium'); Flare::context('feature_flags', ['new_dashboard' => true]); // Add grouped context Flare::group('user_info', [ 'id' => auth()->id(), 'email' => auth()->user()->email, 'plan' => auth()->user()->subscription->plan, 'registered_at' => auth()->user()->created_at, ]); Flare::group('request_metadata', [ 'referer' => request()->headers->get('referer'), 'user_agent' => request()->userAgent(), 'ip' => request()->ip(), ]); ``` ### Recording Custom Events with Glow ```php use Spatie\FlareClient\Enums\MessageLevels; use Spatie\LaravelIgnition\Facades\Flare; // Record informational breadcrumb Flare::glow('User logged in', MessageLevels::INFO, [ 'user_id' => auth()->id(), 'login_method' => 'oauth', ]); // Record warning event Flare::glow('API rate limit approaching', MessageLevels::WARNING, [ 'current_usage' => 950, 'limit' => 1000, 'resets_at' => now()->addHour(), ]); // Record error event Flare::glow('Payment processing failed', MessageLevels::ERROR, [ 'order_id' => $order->id, 'amount' => $order->total, 'error' => $exception->getMessage(), ]); // In your controller public function processPayment(Order $order) { Flare::context('order_id', $order->id); Flare::context('payment_gateway', 'stripe'); try { $charge = Stripe::charges()->create([ 'amount' => $order->total * 100, 'currency' => 'usd', ]); Flare::glow('Payment successful', MessageLevels::INFO, [ 'charge_id' => $charge->id, ]); return response()->json(['success' => true]); } catch (StripeException $e) { Flare::glow('Stripe error occurred', MessageLevels::ERROR, [ 'error_code' => $e->getCode(), 'error_message' => $e->getMessage(), ]); throw $e; } } ``` ## Helper Functions ### Enhanced Dump, Die, Debug (ddd) ```php // Standard Laravel dd() - plain output dd($users, $orders); // Ignition's ddd() - beautiful error page with dump data ddd($users, $orders); // In a controller action public function debug(User $user) { // Dump with full Ignition error page UI ddd([ 'user' => $user, 'permissions' => $user->permissions, 'last_login' => $user->last_login_at, 'debug_info' => [ 'queries' => DB::getQueryLog(), 'memory' => memory_get_usage(true), ], ]); // Execution stops here with beautiful dump display } ``` ## Flare Testing Command ### Test Flare Integration ```bash # Send test exception to Flare php artisan flare:test ``` ```php // Example output: // ✅ Flare key specified // ✅ The Flare logging driver was configured correctly. // // We tried to send an exception to Flare. Please check if it arrived! ``` ## Query Recorder ### Automatic Query Recording ```php // Queries are automatically recorded when recorders are enabled // Access recorded queries in error reports // In a service provider or bootstrap file use Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder; // Customize query recording app(QueryRecorder::class) ->setMaxQueries(500) // Increase from default 200 ->setReportBindings(true); // Include SQL bindings // Example: Queries appear in error context public function calculateReport() { $users = User::where('active', true)->get(); // Query 1: SELECT * FROM users WHERE active = 1 $orders = Order::whereIn('user_id', $users->pluck('id'))->get(); // Query 2: SELECT * FROM orders WHERE user_id IN (...) throw new Exception('Calculation failed'); // Error page shows both queries with bindings } // Access queries programmatically $queries = app(QueryRecorder::class)->getQueries(); // [ // ['query' => 'SELECT * FROM users WHERE active = ?', 'bindings' => [1], 'time' => 2.5], // ['query' => 'SELECT * FROM orders WHERE user_id IN (?, ?)', 'bindings' => [1, 2], 'time' => 5.3], // ] ``` ## Log Recorder ### Automatic Log Recording ```php use Illuminate\Support\Facades\Log; use Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder; // Customize log recording limits app(LogRecorder::class)->setMaxLogs(300); // Default is 200 // Logs are automatically captured and shown in error context public function processOrder(Order $order) { Log::info('Starting order processing', ['order_id' => $order->id]); Log::debug('Validating inventory', [ 'product_id' => $order->product_id, 'requested_quantity' => $order->quantity, ]); if ($order->quantity > $stock) { Log::warning('Insufficient stock', [ 'available' => $stock, 'requested' => $order->quantity, ]); } throw new Exception('Order processing failed'); // Error page displays all log messages in chronological order } // Access recorded logs programmatically $logs = app(LogRecorder::class)->getLogMessages(); // [ // ['level' => 'info', 'message' => 'Starting order processing', 'context' => [...]], // ['level' => 'debug', 'message' => 'Validating inventory', 'context' => [...]], // ['level' => 'warning', 'message' => 'Insufficient stock', 'context' => [...]], // ] ``` ## Dump Recorder ### Recording Variable Dumps ```php use Spatie\LaravelIgnition\Recorders\DumpRecorder\DumpRecorder; // Dumps are automatically recorded when using dump() public function debugFeature() { $user = User::find(1); dump($user); // Captured by DumpRecorder $permissions = $user->permissions()->get(); dump($permissions); // Also captured $config = config('app'); dump($config); // Also captured throw new Exception('Debug point reached'); // Error page shows all three dumps with file locations } // Access recorded dumps $dumps = app(DumpRecorder::class)->getDumps(); // [ // ['html' => '
User {#123 ...}', 'file' => '/app/Controller.php', 'line' => 42],
// ['html' => 'Collection {#456 ...}', 'file' => '/app/Controller.php', 'line' => 45],
// ['html' => 'array:50 [...]]', 'file' => '/app/Controller.php', 'line' => 48], // ] ``` ## Job Recorder ### Recording Failed Jobs ```php use Spatie\LaravelIgnition\Recorders\JobRecorder\JobRecorder; // Customize job recording depth app(JobRecorder::class); // Default max_chained_job_reporting_depth is 5 // Job details are automatically captured on failure class ProcessOrder implements ShouldQueue { public function __construct( public Order $order, public bool $sendNotification = true ) {} public function handle() { // Process order logic throw new Exception('Job failed'); // Captures full job details } } // Chain of jobs is recorded ProcessOrder::dispatch($order) ->chain([ new SendOrderConfirmation($order), new UpdateInventory($order), new GenerateInvoice($order), ]); // If any job fails, entire chain is visible in error report // Access recorded job information $job = app(JobRecorder::class)->getJob(); // [ // 'name' => 'App\Jobs\ProcessOrder', // 'connection' => 'redis', // 'queue' => 'default', // 'data' => ['order' => [...], 'sendNotification' => true], // 'chained' => [ // ['name' => 'App\Jobs\SendOrderConfirmation', 'data' => [...]], // ['name' => 'App\Jobs\UpdateInventory', 'data' => [...]], // ], // ] ``` ## Internal API Routes ### Execute Solution Endpoint ```bash # Execute a runnable solution (only from local IP) curl -X POST http://localhost/_ignition/execute-solution \ -H "Content-Type: application/json" \ -d '{ "solution": "Spatie\\LaravelIgnition\\Solutions\\GenerateAppKey", "parameters": {} }' ``` ### Health Check Endpoint ```bash # Check if Ignition is running curl http://localhost/_ignition/health-check # Response: 200 OK ``` ### Update Configuration Endpoint ```bash # Update Ignition settings (theme, editor, etc.) curl -X POST http://localhost/_ignition/update-config \ -H "Content-Type: application/json" \ -d '{ "theme": "dark", "editor": "vscode" }' ``` ## Creating Custom Solutions ### Generate Solution Provider ```bash # Enable command registration first # In .env: REGISTER_IGNITION_COMMANDS=true php artisan make:solution-provider CustomDatabaseSolutionProvider php artisan make:solution FixDatabaseConnectionSolution ``` ### Custom Solution Provider Example ```php namespace App\Solutions; use Spatie\ErrorSolutions\Contracts\ProvidesSolution; use Spatie\ErrorSolutions\Contracts\Solution; use Illuminate\Database\QueryException; class CustomDatabaseSolutionProvider implements ProvidesSolution { public function canSolve(Throwable $throwable): bool { if (!$throwable instanceof QueryException) { return false; } return str_contains($throwable->getMessage(), 'Unknown database'); } public function getSolutions(Throwable $throwable): array { return [new FixDatabaseConnectionSolution()]; } } class FixDatabaseConnectionSolution implements Solution { public function getSolutionTitle(): string { return 'Database does not exist'; } public function getSolutionDescription(): string { return 'The database specified in your .env file does not exist. Create it or update your configuration.'; } public function getDocumentationLinks(): array { return [ 'Laravel Database Configuration' => 'https://laravel.com/docs/database#configuration', ]; } } // Register in config/ignition.php 'solution_providers' => [ // ...existing providers \App\Solutions\CustomDatabaseSolutionProvider::class, ], ``` ## Remote Development Setup ### Path Mapping Configuration ```php // .env for Docker/Homestead/Remote development IGNITION_REMOTE_SITES_PATH=/home/vagrant/Code IGNITION_LOCAL_SITES_PATH=/Users/yourname/Projects // config/ignition.php 'remote_sites_path' => env('IGNITION_REMOTE_SITES_PATH', base_path()), 'local_sites_path' => env('IGNITION_LOCAL_SITES_PATH', ''), // For PHPStorm remote development 'editor' => 'phpstorm-remote', ``` ## Laravel Ignition is the definitive error handling solution for Laravel applications, transforming cryptic exceptions into actionable intelligence. By combining beautiful error pages, intelligent solution suggestions, automatic context recording, and seamless Flare integration, it accelerates debugging in development while providing robust error tracking in production. The package's extensive configuration options, custom solution provider system, and comprehensive API make it adaptable to any Laravel project's needs. The recorder system automatically captures queries, logs, dumps, and job details during request execution, providing complete context when errors occur. Integration with OpenAI enables AI-powered solution suggestions for complex problems. Runnable solutions allow one-click fixes for common issues in local development. With support for custom solution providers, middleware extensibility, and path mapping for remote development environments, Laravel Ignition scales from simple applications to complex distributed systems.