n3rdysouth/rollbar-php-symfony-bundle
Symfony bundle that integrates Rollbar error monitoring with PHP applications. It connects Symfony services to the Rollbar PHP SDK to report exceptions and logs, with configurable handler and client setup for centralized error tracking and visibility.
First, settle the framework question — it decides everything else. This is a Symfony bundle. It registers through config/bundles.php (Symfony Flex) or AppKernel::registerBundles(), and its config surface is a DependencyInjection/*Extension.php that builds a rollbar: config tree. It ships no ServiceProvider, no Illuminate\Contracts bindings, and no extra.laravel.providers in composer.json. Composer will happily install it into a Laravel app because the constraints are framework-agnostic, but nothing will boot it and nothing will report. If you are a Laravel developer, treat this package as reference material for a ~50-line port, not a dependency.
Where to look first (10 minutes of reading, before any install):
composer.json — the require block tells you the PHP and symfony/http-kernel ranges it was actually built against. A 0-star, 0-dependent package is usually pinned to an older Symfony major.DependencyInjection/*Extension.php — this is the authoritative list of config keys (access_token, environment, and whatever else it aliases into the SDK's Rollbar\Config). Read this instead of trusting docs, because there are no docs.Resources/config/services.xml (or .yaml) — shows the service ID the Rollbar client is registered under, which is what you autowire or $container->get().rollbar/rollbar-php-symfony-bundle. Diff it. If it is a fork, your patch path and upgrade path are upstream's, not this repo's.Path A — you actually have a Symfony service in the estate:
composer require n3rdysouth/rollbar-php-symfony-bundle
// config/bundles.php
return [
// ...
N3rdySouth\RollbarBundle\N3rdySouthRollbarBundle::class => ['all' => true],
];
# config/packages/rollbar.yaml (verify key names against the Extension class)
rollbar:
access_token: '%env(ROLLBAR_TOKEN)%'
environment: '%kernel.environment%'
Then throw a deliberate exception in a controller and confirm the item lands in the Rollbar dashboard with the right environment before you wire anything else.
Path B — you are Laravel-only (the common case). Your first use case is a spike: bind rollbar/rollbar-php as a singleton, hook ExceptionHandler::report(), and confirm one exception produces exactly one Rollbar item. Do not install this bundle to get there.
composer require rollbar/rollbar-php
// app/Providers/RollbarServiceProvider.php
public function register(): void
{
$this->app->singleton(\Rollbar\Rollbar::class, fn () => new \Rollbar\Rollbar([
'access_token' => config('services.rollbar.token'),
'environment' => app()->environment(),
'root' => base_path(),
'handle_exceptions' => false, // we hook the handler ourselves
]));
}
// bootstrap/app.php (Laravel 11+)
->withExceptions(function (Exceptions $exceptions) {
$exceptions->report(function (Throwable $e) {
if (app()->bound(\Rollbar\Rollbar::class) && config('services.rollbar.token')) {
app(\Rollbar\Rollbar::class)->report($e);
}
});
})
That is the whole first use case. Validate end-to-end (throw → item visible → correct env/release/user) before scaling to other services.
Wrap it behind your own interface, immediately. This is the single most valuable pattern given the package's provenance. Every call site depends on your interface, not on Rollbar or this bundle. A vendor swap then becomes a one-file change instead of a grep.
interface ErrorReporter
{
public function report(Throwable $e, array $context = []): void;
}
In Symfony, decorate or alias the bundle's client service to this interface. In Laravel, bind it to a RollbarErrorReporter implementation in your service provider.
Context enrichment belongs in middleware, not in call sites. The bundle's listener captures kernel exceptions; it does not know your user, tenant, or release. In Laravel, a terminating middleware is the clean seam:
public function handle($request, Closure $next)
{
if (app()->bound(ErrorReporter::class)) {
app(ErrorReporter::class)->addContext([
'user_id' => optional($request->user())->id,
'tenant' => tenant()?->id,
'route' => $request->route()?->getName(),
'release' => config('app.release'),
]);
}
return $next($request);
}
Use IDs and route names, never raw request bodies, auth headers, or session payloads.
Pick one reporting channel per exception. The bundle's listener and your Monolog stack can both fire on the same throwable. Choose: either the kernel exception hook or a dedicated Monolog handler that forwards to Rollbar — not both. Otherwise you pay twice per event and dashboards show duplicated items during incidents, which is exactly when triage is hardest.
Environment gating is config, not code. Ship a rollbar: / services.rollbar config block where token is null in local and testing, and where sampling is a first-class value. A silently disabled reporter in local is correct; a silently disabled reporter in production is a bug — so assert at boot that production has a token.
Async or batched transport before any high-traffic rollout. The default SDK path sends synchronously, often on request teardown. Under load that becomes tail latency on every 500. Enable the SDK's batching/agent option (or dispatch via a queued job with a flush) and set explicit connect/read timeouts so a Rollbar outage never extends your response times. If you use queue workers, make sure the flush runs on terminate, not once per worker lifetime.
Release and environment tagging are the integration's real payoff. Make APP_RELEASE a deploy-pipeline variable and pass it through both the Symfony config and the Laravel binding. Without it, "did this error start with the last deploy?" is unanswerable, and that is the question the tool exists to answer.
Standard rollout sequence: one non-critical service → verify exception, verify handled-vs-unhandled split, verify PII scrubbing → then expand service by service. Formalize alert routing last, after you trust the signal.
config/bundles.php for that env, or the rollbar: config block is missing, or the token env var is empty, the listener is never registered and no error is ever sent — with zero warnings. Add a startup assertion or a health-check endpoint that emits one synthetic event per environment after deploy.curl the Rollbar items endpoint with the token and the payload shape before you debug the app. A wrong token in a staging deploy is far more common than a wrong hook.^1.0 may resolve to something different tomorrow. "n3rdysouth/rollbar-php-symfony-bundle": "dev-main#<sha>", and record the SHA in your dependency-ownership doc.Extension.php, not the README. Config keys in low-adoption bundles frequently diverge from the docs, and this one's docs are the SDK's docs. The Extension load() method is the ground truth for accepted keys and their defaults.handle_exceptions interplay. If the bundle (or your Laravel binding) sets the SDK's own global handler and you also hook the framework handler, you get double reports. Explicitly disable the SDK's handler when the framework owns exception capture.DataBuilder / payload transformer is where you reshape events (custom fingerprinting, stripping fields, attaching deploy metadata). Bind your own implementation into the container rather than post-processing — and note this is an SDK extension point that survives a vendor swap better than anything the bundle itself offers.How can I help you explore Laravel packages today?