speerit/airbrake-bundle
A Symfony bundle for integrating Airbrake error tracking. It captures exceptions and reports them to Airbrake, helping teams monitor production issues. Configurable API credentials, environment filtering, and notification settings simplify setup.
First, the honest framing: this is not a Laravel package. speerit/airbrake-bundle is a Symfony2 bundle — it registers through AppKernel, ships a DependencyInjection/*Extension, and is configured under a speerit_airbrake: key in config.yml. Laravel has no bundle system, no AppKernel, and no auto-discovery for it. One star, last release December 2017, and Symfony2-era composer.json constraints mean you almost certainly cannot composer require it into a modern Laravel app without a dependency conflict.
So "getting started" for a Laravel developer is one of two paths:
Path A — read it, don't install it (recommended). Treat the repo as a reference implementation of the Airbrake API v3 notice format. Look first at:
DependencyInjection/Configuration.php — the config surface (project id, project key, host, environment, ignored exceptions).file, line, function), and context.kernel.exception — this is the equivalent of what you'll wire into Laravel's exception handler.Path B — port the notifier into a Laravel service provider. Copy the ~100 lines that build and POST the JSON notice; throw away everything Symfony. That gives you a working integration in an afternoon without the Composer conflict.
Your first concrete use case, either way, is the same: report unhandled exceptions from App\Exceptions\Handler (or bootstrap/app.php's withExceptions on Laravel 11+) to Airbrake, tagged with environment, component, and the current user.
Minimal working skeleton once you've ported the payload logic:
// config/services.php
'airbrake' => [
'project_id' => env('AIRBRAKE_PROJECT_ID'),
'project_key' => env('AIRBRAKE_PROJECT_KEY'),
'host' => env('AIRBRAKE_HOST', 'https://airbrake.io'),
'environment' => env('APP_ENV'),
'timeout' => 2,
],
// App\Exceptions\Handler::report()
public function report(Throwable $e): void
{
parent::report($e);
if ($this->shouldReport($e)) {
app(AirbrakeNotifier::class)->notifyException($e);
}
}
Verify with a throwaway route that throws, then confirm the notice lands in Airbrake and that the request still returns in normal time (see Gotchas — the timeout matters).
Bind the notifier as a singleton, not a facade. Airbrake notices are fire-and-forget; you want one Guzzle/HTTP client instance reused across the request, with the config resolved once.
// App\Providers\AirbrakeServiceProvider.php
public function register(): void
{
$this->app->singleton(AirbrakeNotifier::class, fn ($app) => new AirbrakeNotifier(
config('services.airbrake'),
$app->make(ClientInterface::class),
));
}
Respect shouldReport(). Laravel's handler already knows to skip 404s, ValidationException, AuthenticationException, and anything in $dontReport. Don't bypass it — route your Airbrake call inside the if, as above.
Report non-exception events as notices. The bundle's format supports arbitrary messages, not just exceptions. Wrap it so you can report "payment webhook signature mismatch" without constructing an exception:
app(AirbrakeNotifier::class)->notify(
message: 'Stripe webhook signature mismatch',
context: ['component' => 'billing', 'action' => 'webhook', 'params' => ['id' => $event->id]],
);
Report from queued jobs and console commands, not just HTTP. A huge fraction of Laravel failures happen in failed() hooks. The Symfony bundle only sees kernel.exception; you have to be deliberate:
public function failed(Throwable $e): void
{
app(AirbrakeNotifier::class)->notifyException($e, ['component' => 'queue', 'action' => static::class]);
}
Attach context via middleware rather than threading it through. A terminate()-time hook lets you enrich the notice with the route, user id, and request id without touching every controller:
public function terminate($request, $response): void
{
app(AirbrakeNotifier::class)->setContext([
'url' => $request->fullUrl(),
'route' => optional($request->route())->getName(),
'user_id' => optional($request->user())->id,
'request_id'=> $request->header('X-Request-Id'),
]);
}
Make the send non-blocking. Airbrake sits on the critical path otherwise. Two options: app()->terminating(fn () => $notifier->flush()) so it runs after the response is sent, or push to a queue job with a short retry window. Never do a synchronous 10-second POST inside the exception handler.
Use the same notifier for deploy tracking. The bundle doesn't cover it, but the API v3 deploy endpoint is trivial and pairs naturally with your CI step — POST /api/v3/projects/{id}/deploys with environment, revision, username. One curl in your deploy script.
If you're actually on Symfony 2/3 (the only place the bundle runs as designed): register new Speerit\AirbrakeBundle\SpeeritAirbrakeBundle() in AppKernel, add the speerit_airbrake block to config.yml with %airbrake_project_id% parameters, and let the bundle's exception listener do the work. Everything below about filtering and timeouts still applies.
symfony/symfony, symfony/dependency-injection, and an old Guzzle (3.x or 5.x) collide head-on with the symfony/* 6/7 components Laravel 10/11 pulls in. Don't --ignore-platform-reqs your way past it; you'll get a broken lockfile and a Guzzle class conflict at runtime. Port the notifier instead.object hint changes, let alone PHP 8's deprecations. Expect dynamic-property warnings and possibly fatal errors on PHP 8.x if you do install it. The Airbrake API v3 notice format itself hasn't changed much, so the logic is still valid even though the code is stale.?key=<project_key> on the URL, with <project_id> in the path (/api/v3/projects/{id}/notices). Mixing up the two is the single most common 401. For self-hosted Errbit/Airbrake-compatible servers, point host at your own base URL.try { ... } catch (\Throwable $e) { Log::warning('airbrake failed', ['e' => $e]); }.Authorization, Cookie, password, token, and card fields. Airbrake's own filter_parameters config exists, but if you port the code you own that responsibility. Also make sure .env values never end up in context.Log::error mirrored into Airbrake can burn quota fast — dedupe by giving stable type/message values so Airbrake groups them, and set fingerprint for the ones you can't.storage/logs/laravel.log for your swallowed warning first, then curl the endpoint by hand with a minimal payload. If the manual curl works and the app doesn't, it's almost always the timeout, an SSL/proxy issue, or shouldReport() silently filtering it.airbrake/php notifier (API v3, actively maintained) or Sentry/Bugsnag/Flare have first-class Laravel integrations with queue support and no Symfony baggage. Use this bundle only if you're maintaining a legacy Symfony2 app or you specifically need a self-hosted Errbit endpoint and prefer minimal dependencies.How can I help you explore Laravel packages today?