Ignition
Please notice, this is an older version of the package we recommand you to upgrade to the latest Flare client
Installation
On this page, you'll learn how to install Ignition in your project
Laravel apps
In Laravel applications, Ignition is installed by default.
Optionally, you could publish the ignition
and flare
config file to have fine-grained control over how Ignition behaves.
php artisan vendor:publish --tag="ignition-config"
php artisan vendor:publish --tag="flare-config"
@## Non-Laravel apps
In a non-Laravel PHP application, you can install Ignition via Composer.
composer require spatie/ignition
Here's a minimal example on how to register ignition.
use Spatie\Ignition\Ignition;
include 'vendor/autoload.php';
Ignition::make()->register();
In order to display the Ignition error page when an error occurs in your project, you must add this code. Typically, this would be done in the bootstrap part of your application.
Spatie\Ignition\Ignition::make()->register();
Setting the application path
When setting the application path, Ignition will trim the given value from all paths. This will make the error page look more cleaner.
Spatie\Ignition\Ignition::make()
->applicationPath($basePathOfYourApplication)
->register();
Using dark mode
By default, Ignition uses a nice white based theme. If this is too bright for your eyes, you can use dark mode.
Spatie\Ignition\Ignition::make()
->useDarkMode()
->register();
Stack trace arguments
By default, Ignition will show you arguments which are passed to functions and methods in the stack trace. You can find more about how this works in the stack trace arguments section.
Avoid rendering Ignition in a production environment
You don't want to render the Ignition error page in a production environment, as it potentially can display sensitive information.
To avoid rendering Ignition, you can call shouldDisplayException
and pass it a falsy value.
Spatie\Ignition\Ignition::make()
->shouldDisplayException($inLocalEnvironment)
->register();
Security recommendations
Ignition has the ability to run executable solutions. These solutions can make your life better by running migrations when you forgot to run them, generating an APP_KEY
if you set none, fixing variable names in your code, ...
These runnable solutions are only available when Laravel is in debug mode.
We highly recommend to never turn on debug mode on a non-local environment. If you do so then you risk exposing sensitive information and potentially allow outsiders to execute solutions.
Should you have activated debug mode on a non-local environment, then Ignition will display a warning.
Disable executing solutions
Should you, for some reason, do need to set debug mode to true
on a non-local environment, then we highly recommend turning off Ignition's ability to execute solutions. You can do this by setting the ignition.enable_runnable_solutions
config key to false
.
If you're using Ignition v2.6.1 or higher, then it's not possible anymore to run solutions in a non-local environment.
Reporting security issues
Please don't use the public issue tracker, but report all security issues to [email protected]
Sharing errors
Introduction
The error sharing feature in Ignition enables users to easily share their local error occurrences with colleagues. By clicking the "share" button, users can generate a unique and publicly accessible URL that displays their local error. Ignition shares are ideal for attaching to GitHub issues or sharing in Slack because they have no expiration date. The sharing capability is provided by Flare at no cost and without any usage restrictions.
What data gets shared?
When using Ignition's sharing feature, you can choose what exception data and context to include in the shared error page. The following three sections are available for sharing and correspond to Ignition's page sections:
- Stack: Provides a detailed stack trace that shows the sequence of method calls leading to the error, including file paths and arguments.
- Context: Offers relevant contextual information about the error, such as request payload, headers, routing details, and view variables.
- Debug: Displays additional debugging information like
dump
output, SQL queries with bindings, and logs, providing deeper insights into the error.
Generally, the data included in the Ignition error page and its shared errors is safe to share with colleagues. However, as always, common sense applies. It is important to note that the data may contain sensitive information, such as database credentials, API keys, or other secrets. Therefore, it is recommended to review the data visible in Ignition before sharing it with others. Be especially careful when dealing with production data locally.
Removing shared errors
To maintain privacy and control over shared error pages, Flare offers a simple method for removing shares. When sharing an error, an ownership cookie is automatically set in your browser. To delete the shared error, simply visit the shared error from the same browser and look for the "Delete Share" button.
In the rare event that the "Delete Share" button is not visible or you encounter any issues, please contact Flare's dedicated support team at [email protected] and include the share URL you would like to have removed.
Implementing solutions
Ignition ships with a lot of useful solutions out of the box. But you can also take advantage of Ignition's solutions yourself and add custom exceptions to your codebase.
No matter if you are working on your custom application code and want to provide solutions for your colleagues, or if you are working on your next open source package.
Custom solutions
In addition to simply displaying your exception, Ignition can also display a text-based solution along with your exception message.
To add a solution text to your exception, let the exception implement the Spatie\Ignition\Contracts\ProvidesSolution
interface.
If you want to add solutions to an open source package, you can require the
spatie/ignition
as a dependency.
This is what that interface looks like:
namespace Spatie\Ignition\Contracts;
interface ProvidesSolutions
{
public function getSolution(): Solution;
}
The getSolution
method expects you to return an implementation of the Solution
interface. You can either create a custom class that implements that interface or make use of the built-in BaseSolution
class to easily return a textual solution.
Here's an example of an implementation in a custom exception class:
namespace App\Exceptions;
use Exception;
use Spatie\Ignition\Contracts\BaseSolution;
use Spatie\Ignition\Contracts\ProvidesSolution;
use Spatie\Ignition\Contracts\Solution;
class MyException extends Exception implements ProvidesSolution
{
public function getSolution(): Solution
{
return BaseSolution::create('My solution title')
->setSolutionDescription('My solution description')
->setDocumentationLinks([
'My docs' => 'https://flareapp.io/docs',
]);
}
}
This is how the exception would be displayed if you were to throw it.
If you're sending your exception to Flare, the solution will be sent along as well. Here's how the exception above would look like in Flare.
Using solution providers
Instead of adding solutions to exceptions directly, you can also create a solution provider. While exceptions that return a solution, provide the solution directly to Ignition, a solution provider allows you to figure out if an exception can be solved.
For example, you could create a custom "Stack Overflow solution provider", that will look up if a solution can be found for a given throwable.
Solution providers can be added by third party packages or within your own application.
A solution provider is any class that implements the Spatie\Ignition\Contracts\HasSolutionsForThrowable
interface.
This is how the interface looks like:
interface HasSolutionsForThrowable
{
public function canSolve(Throwable $throwable): bool;
/** \Facade\IgnitionContracts\Solution[] */
public function getSolutions(Throwable $throwable): array;
}
When an error occurs in your app, the class will receive the Throwable
in the canSolve
method. In that method you can decide if your solution provider is applicable to the Throwable
passed. If you return true
, getSolutions
will get called.
Here is an example from the Ignition package codebase:
use Throwable;
use RuntimeException;
use Spatie\Ignition\Contracts\Solution;
use Spatie\LaravelIgnition\Solutions\GenerateAppKeySolution;
use Spatie\Ignition\Contracts\HasSolutionsForThrowable;
class MissingAppKeySolutionProvider implements HasSolutionsForThrowable
{
public function canSolve(Throwable $throwable): bool
{
if (! $throwable instanceof RuntimeException) {
return false;
}
return $throwable->getMessage() === 'No application encryption key has been specified.';
}
public function getSolutions(Throwable $throwable): array
{
return [
new GenerateAppKeySolution(),
];
}
}
Registering a solution provider in a non-Laravel app
When Ignition is used in a non-Laravel app, you can call addSolutionProvider
on your Ignition
instance.
\Spatie\Ignition\Ignition::make()
->addSolutionProviders([
new YourSolutionProvider(),
// other solution providers...
])
->register();
Registering a solution provider in a Laravel app
In a Laravel app, you register your solution provider in a service provider.
namespace App\Providers;
use App\Solutions\GenerateAppKeySolution;
use Spatie\Ignition\Contracts\SolutionProviderRepository;
use Illuminate\Support\ServiceProvider;
class YourServiceProvider extends ServiceProvider
{
public function boot()
{
$this->app->make(SolutionProviderRepository::class)->registerSolutionProvider(GenerateAppKeySolution::class);
// alternatively you can register multiple solution providers at once
$this->app
->make(SolutionProviderRepository::class)
->registerSolutionProviders([
MySolution::class,
AnotherSolution::class,
]);
}
}
Alternatively, you could also publish the ignition
config file, and add your solution provider to the solution_providers
config key.
Implementing getSolutions
The getSolutions
method of your solution provider should return an array of Spatie\Ignition\Contracts\Solution
implementations. Here's a possible implementation of GenerateAppKeySolution
for a Laravel app.
namespace App\Solutions;
use Illuminate\Support\Facades\Artisan;
use Spatie\Ignition\Contracts\RunnableSolution;
class GenerateAppKeySolution implements RunnableSolution
{
public function getSolutionTitle(): string
{
return 'Your app key is missing';
}
public function getDocumentationLinks(): array
{
return [
'Laravel' => 'https://laravel.com/docs/master/installation#configuration',
];
}
public function getSolutionActionDescription(): string
{
return 'Generate your application encryption key using `php artisan key:generate`.';
}
/* This method is optional */
public function getRunButtonText(): string
{
return 'Generate app key';
}
/* This method is optional */
public function getSolutionDescription(): string
{
return '';
}
/* This method is optional */
public function run(array $parameters = [])
{
Artisan::call('key:generate');
}
/* This method is optional */
public function getRunParameters(): array
{
return [];
}
}
Tips on writing clear solutions
When writing custom solutions, make sure that the text that your solution provides is helpful to the user reading it.
For all solutions that are built into Ignition, we make use of a solution "style guide". You may want to use them in your solutions too.
Solution title
The solution title should be a full sentence with the "problem" that this solution is trying to fix upfront. It should not contain any punctuation and no caps on all words.
Example:
App Key Missing
Your app key is missing
Solution description
Avoid questions in your solution descriptions. If you are in doubt that your solutions are going to fix the problem 100% of the time, use verbs like "seems", "might", "could", etc. Optionally state the problem in full sentences and give clear instructions on what the user can do to solve the problem.
You can use markdown inside your solution description to highlight inline-code snippets to point to files or classes.
Example:
Is your application key missing? Try adding it to your environment variables.
Generate your application encryption key using php artisan key:generate
.
Runnable solutions
If there is a chance to let you automatically fix the problem for the user, provide a runnable solution. This way, developers can quickly try and fix the problem with the press of a button.
Make sure also to provide the information on how to manually perform the fix, in case something goes wrong.
The button of a runnable solution should point out what happens when the button gets clicked.
Example:
Fix the problem
Run missing migrations
Solution links
In addition to a solution title and description, you can also point the user to various links where the user can read more about how the issue can be fixed or avoided. When linking to external resources, try to be as specific as possible, where the link will take the user.
Example:
Laracasts
Watch "Laravel 5 Fundamentals - Migrations" on Laracasts
Implementing Runnable solutions
Ignition can also help and run custom solutions to try and automatically fix an error. Here's how a runnable solution looks like.
To mark your solution as "runnable", let it implement the Facade\IgnitionContracts\RunnableSolution
interface. Here is how that interface looks like:
namespace Spatie\Ignition\Contracts;
interface RunnableSolution extends Solution
{
public function getSolutionActionDescription(): string;
public function getRunButtonText(): string;
public function run(array $parameters = []);
public function getRunParameters(): array;
}
To return that solution in one of your exceptions, let your exception implement the Facade\IgnitionContracts\ProvidesSolution
interface.
class MyException extends Exception implements ProvidesSolutions
{
public function getSolutions(): array
{
return [new MyRunnableSolution()];
}
}
And this is an example of a runnable solution class.
namespace App\Solutions;
use Spatie\Ignition\Contracts\RunnableSolution;
class MyRunnableSolution implements RunnableSolution
{
public function getSolutionTitle(): string
{
return 'My solution title';
}
public function getSolutionDescription(): string
{
return 'My solution description';
}
public function getDocumentationLinks(): array
{
return [
'My docs' => 'https://flareapp.io/docs',
];
}
public function getSolutionActionDescription(): string
{
return 'We can try to solve this exception by running a little code';
}
public function getRunButtonText(): string
{
return 'Press me to run the solution';
}
public function run(array $parameters = [])
{
// code that tries to fix the problem
}
/*
* The array you return here will be passed to the `run` function.
*
* Make sure everything you return here is serializable.
*
*/
public function getRunParameters(): array
{
return [];
}
}
Using AI powered solutions
Ignition can send your exception to OpenAI that will attempt to automatically suggest a solution. In many cases, the suggested solutions is quite useful, but keep in mind that the solution may not be 100% correct for your context.
Configuration in a Laravel app
To generate AI powered solutions, you must first install this optional dependency.
composer require openai-php/client
We use cache to minimize calls made to OpenAI when your API generates many similar errors.
Configuration in a non-Laravel app
To generate AI powered solutions, you must first install this optional dependency.
composer require openai-php/client
To start sending your errors to OpenAI, you must instanciate the OpenAiSolutionProvider
. The constructor expects a OpenAI API key to be passed, you should generate this key at OpenAI.
use \Spatie\Ignition\Solutions\OpenAi\OpenAiSolutionProvider;
$aiSolutionProvider = new OpenAiSolutionProvider($openAiKey);
To use the solution provider, you should pass it to addSolutionProviders
when registering Ignition.
\Spatie\Ignition\Ignition::make()
->addSolutionProviders([
$aiSolutionProvider,
// other solution providers...
])
->register();
By default, the solution provider will send these bits of info to OpenAI:
- the error message
- the error class
- the stack frame
- other small bits of info of context surrounding your error
It will not send the request payload or any environment variables to avoid sending sensitive data to OpenAI.
Caching requests to AI
By default, all errors will be sent to OpenAI. Optionally, you can add caching so similar errors will only get sent to OpenAI once. To cache errors, you can call useCache
on $aiSolutionProvider
. You should pass a simple-cache-implementation. Here's the signature of the useCache
method.
public function useCache(CacheInterface $cache, int $cacheTtlInSeconds = 60 * 60)
Hinting the application type
To increase the quality of the suggested solutions, you can send along the application type (Symfony, Drupal, WordPress, ...) to the AI.
To send the application type call applicationType
on the solution provider.
$aiSolutionProvider->applicationType('WordPress 6.2');