practo/sentry-bundle
A Laravel bundle that integrates Sentry error tracking into your application, helping you capture exceptions, log errors, and monitor application health from a centralized dashboard. Simple to install and configure.
What you're actually installing. practo/sentry-bundle is a fork of kunstmaan/sentry-bundle, a Symfony2-era bundle that wires the (now EOL) raven-php client into the kernel via an exception listener. If you are working in a Laravel codebase, this is not the package you want for day-to-day work — the equivalent is sentry/sentry-laravel. Reach for this bundle only if you are maintaining a legacy Symfony 2.x/3.x application that already depends on it, or if you are explicitly evaluating the fork against the upstream KunstmaanSentryBundle.
Minimal steps.
Add the package. Since it is a fork with 0 stars and 0 dependents, it is almost certainly not on Packagist under this name — install via a VCS repository entry and pin a commit:
{
"repositories": [
{ "type": "vcs", "url": "https://github.com/practo/KunstmaanSentryBundle" }
],
"require": {
"practo/sentry-bundle": "dev-master#<commit-sha>"
}
}
Register the bundle in app/AppKernel.php (this is the Symfony2 layout — the fact that the README talks about AppKernel is your first signal that this codebase is old):
new Kunstmaan\SentryBundle\KunstmaanSentryBundle(),
Configure the DSN. The bundle uses a kunstmaan_sentry config root with a nested client block, not a flat sentry.dsn key like modern SDKs:
# app/config/config.yml
kunstmaan_sentry:
report_exceptions: true
report_console_exceptions: true
client:
dsn: "%sentry_dsn%"
options:
environment: "%kernel.environment%"
Clear the cache and trigger an uncaught exception in a non-local environment — the listener should ship it to Sentry.
Where to look first.
DependencyInjection/Configuration.php — this is the authoritative list of config keys. The README will be stale relative to this file.EventListener/ExceptionListener.php and EventListener/ConsoleExceptionListener.php — this is where the "autoload exception handler" description lives. Read both before trusting the docs on what gets reported.Resources/config/services.xml — the service IDs you will be injecting or overriding. Note down kunstmaan_sentry.client (the Raven wrapper) since that is your manual-capture handle.KunstmaanSentryBundle — with a fork like this, "minor modification and improvements" usually means a small patch to the exception listener or the skip-capture logic, and that patch is the only reason the fork exists. Diff it against upstream before adopting so you know what you're inheriting.First use case. Enable it in the prod environment only, verify that a thrown exception and an uncaught fatal both land in Sentry with the correct environment tag, and confirm the same does not happen in dev and test. Then immediately configure skip_capture so a 404 storm does not consume your Sentry quota.
Global exception capture (the intended path). With report_exceptions: true, the bundle's kernel exception listener catches everything bubbling out of the kernel and forwards it to Raven. You generally should not wrap controllers in try/catch + manual capture — that is what this listener exists for, and hand-rolled catches are how you end up with duplicate events.
Manual capture via the client service. For caught-and-handled failures where you want a breadcrumb but still want the app to succeed, inject the wrapper:
use Kunstmaan\SentryBundle\Sentry\ClientInterface; // verify the exact interface name in your pinned version
public function __construct(private ClientInterface $sentry) {}
public function charge(): void
{
try {
$this->gateway->charge($order);
} catch (GatewayException $e) {
$this->sentry->captureException($e);
$this->logger->warning('gateway charge failed', ['order' => $order->id]);
}
}
Treat the service ID as API surface: because this is an unmaintained fork, the wrapper's methods are what your code is coupled to, not the Raven APIs underneath.
Noise suppression as a first-class concern. skip_capture (exception class list) is the main quality lever. The standard set for any Symfony app:
kunstmaan_sentry:
skip_capture:
- Symfony\Component\HttpKernel\Exception\NotFoundHttpException
- Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
- Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
- Symfony\Component\Security\Core\Exception\AuthenticationException
skip_commands:
- "doctrine:migrations:*"
- "cache:*"
The console-side equivalent matters just as much: cron jobs and migration commands that exit non-zero will flood Sentry otherwise.
Per-environment configuration. Follow the standard Symfony config.yml / config_prod.yml split. Keep report_exceptions: false in config_dev.yml and config_test.yml. In production, put the DSN in parameters.yml sourced from the environment (SENTRY_DSN) rather than committed to VCS — the bundle's client.dsn key accepts a %parameter% string.
Wiring user context. Raven supports per-request user context but this bundle does not populate it automatically. The pattern is a small kernel request listener that runs after security and calls the client's user-set method with id / email / username. Do this as your own listener rather than patching the bundle — it is your extension point and keeps the fork untouched.
Monolog bridging. Many apps end up with double reporting: the exception listener ships the exception, and a Monolog handler ships the log record written by Symfony's ExceptionListener. Pick one. In practice, keep the bundle's kernel listener for true uncaught errors and configure Monolog to not forward Exception context at error level, or vice versa. Verify by throwing a deliberate exception and counting the events in Sentry.
Integration tip — health-check the wiring. Because the fork has no test suite you can rely on, add a one-line smoke test in CI: boot the kernel in prod, resolve kunstmaan_sentry.client, and assert it is an instance of the expected class with a non-empty DSN. This catches the common failure where a config key typo silently disables reporting instead of erroring.
Raven is dead and this bundle inherits that. raven-php was superseded by sentry/sentry (2.x/3.x) years ago. There is no PHP 8 support path here, no breadcrumbs/tracing/performance, and no Sentry\init(). If you are on PHP 8 or Symfony 5+, do not attempt to make this work — the migration target is sentry/sentry-symfony. For Laravel, the only correct answer day-to-day is sentry/sentry-laravel.
Pin the commit, always. Zero stars, zero dependents, and "minor modifications" means the dev-master branch can move under you with no release tags and no changelog. Composer's #<sha> constraint is the only thing keeping your build reproducible.
Silent no-op when misconfigured. With an empty or malformed client.dsn, the bundle tends to construct the client but drop events rather than fail loudly. Symptom: no exceptions in Sentry, no errors in the logs. Debug by setting a DSN against a local relay (a throwaway Sentry project, or sentry-cli/a local collector) and confirming a test event arrives before you trust the integration.
Symfony 4+ autowiring does not apply. The services are declared in XML with old-style IDs and no autoconfigure. If you are in a hybrid app, you will need explicit services: aliases or constructor arguments referencing kunstmaan_sentry.client. Expect ServiceNotFoundException when you try to type-hint the client without an alias.
Double reporting is the most common real bug. Kernel listener + Monolog handler + any hand-rolled captureException in a controller all fire for the same throw. Audit all three. Also check report_console_exceptions — a failing console command in a try/catch will still bubble and report, which is usually desirable but occasionally surprising for scripts that intentionally exit non-zero.
Skip lists are exact-match on class names. Subclasses of a skipped exception are not automatically skipped in some upstream versions — verify against your pinned code before assuming a parent class covers the family. This bites people with custom NotFoundHttpException subclasses.
Extension points worth using instead of forking again. In order of preference: (1) skip_capture / skip_commands config, (2) a decorator around kunstmaan_sentry.client registered as the same ID, (3) a compiler pass if you need to swap the listener. Adding a third fork of a fork is how teams end up with three bespoke Sentry bundles and no upgrade path.
Testing is awkward. Raven transmits over the network at event time, so unit tests either mock the client wrapper or set a DSN pointing at a sink. There is no before_send hook exposed by this bundle version in most forks; if you need PII scrubbing (and you do, given user_context), it must go in your own decorator wrapping the client, filtering the payload before it hands off to Raven.
Verdict for a Laravel developer. Read this repo only as a historical reference for how Symfony2 bundles bound a global handler into the kernel — the pattern is useful, the code is not. In a Laravel app, use sentry/sentry-laravel and its ExceptionHandler integration; do not attempt to bridge this bundle through laravel/symfony-bundle style glue.
How can I help you explore Laravel packages today?