nowo-tech/sentry-bundle
A Symfony bundle that integrates Sentry error tracking and monitoring into your application, providing sensible defaults for capturing exceptions, logging events, and reporting performance data with minimal configuration.
This is a Symfony bundle, not a Laravel package. There is no package discovery, no config/sentry.php, and no App\Http\Middleware hook. If you are coming from sentry/sentry-laravel, translate the mental model to: DI extension + config tree + event-subscriber listeners on top of sentry/sentry-symfony.
Reviewed at v1.11.2. This release is maintenance-only — dependency refresh, demo/CI/docs. No runtime BC breaks for consumers, but note the package now sits on the 1.x line (1.11.1 → 1.11.2), so the old 0.* install constraint is stale.
Prerequisites to confirm before you commit to it:
sentry/sentry-symfony (and thus sentry/sentry) in require — this bundle "extends" upstream, so check composer.json to see the exact constraint it pins. That constraint is your real compatibility contract.Install (pin it — see Gotchas):
composer require nowo-tech/sentry-bundle:^1.11 # then lock to the exact version you reviewed (1.11.2)
bin/console cache:clear
Manual registration is almost certainly required (no Flex recipe, no meaningful dependent count):
// config/bundles.php
Nowo\SentryBundle\NowoSentryBundle::class => ['all' => true],
Where to look first, in this order:
README.md — the only guaranteed usage doc.src/DependencyInjection/Configuration.php — the authored config tree. This is the truth for every option name/default. Do not guess keys.src/Resources/config/*.yaml|php — which services/listeners are registered by default and their priorities.src/EventListener/ — what it actually adds over upstream. Diff this against sentry/sentry-symfony's bundled listeners before trusting it.composer.json require + CHANGELOG/UPGRADING — for v1.11.2 specifically, UPGRADING.md#to-1112.docs/SECURITY.md — new/expanded in 1.11.2: attack surface, threat model, dependency policy. Read this before sending production user data through it.Then dump the real config reference instead of reading source:
bin/console config:dump-reference <alias_from_Configuration.php>
First use case (15 minutes): wire the DSN, then prove one exception reaches Sentry with the right environment and release.
# config/packages/nowo_tech_sentry.yaml (root key: verify in Configuration.php)
nowo_tech_sentry:
dsn: '%env(SENTRY_DSN)%'
environment: '%kernel.environment%'
release: '%env(SENTRY_RELEASE)%'
# .env.prod only — never commit a real DSN
SENTRY_DSN=https://[email protected]/0
SENTRY_RELEASE=git-$(git rev-parse --short HEAD)
Throw from a throwaway route in prod, confirm the event, then delete the route. If it doesn't arrive, the bundle isn't the first suspect — upstream sentry/sentry-symfony is.
Layer, don't stack. sentry/sentry-symfony already registers exception/request/console listeners. This bundle adds "enhanced" ones. Configure the bundle; leave the upstream bundle's YAML minimal so you don't get double breadcrumbs or double capture. If both register an ExceptionListener, you will see duplicated events — disable one.
Per-env DSN, always. Reporting in dev/test is noise and CI flakiness:
# config/packages/nowo_tech_sentry.yaml
when@prod:
nowo_tech_sentry:
dsn: '%env(SENTRY_DSN)%'
release: '%env(SENTRY_RELEASE)%'
Attach business context in your code, not the bundle. Use SentrySdk/HubInterface from a small kernel-request or security listener so user/tags are set once per request:
use Sentry\State\HubInterface;
final class SentryUserContextListener
{
public function __construct(private HubInterface $hub) {}
public function onKernelRequest(RequestEvent $event): void
{
$user = $event->getRequest()->attributes->get('_security_user');
if ($user) {
$this->hub->configureScope(fn (Scope $s) => $s->setUser(['id' => $user->getId()]));
}
}
}
Keep this in src/, not in the vendor bundle — it survives upgrades.
Ignore noise at the config layer. 404s, AccessDeniedHttpException, and validation failures are the usual volume killers. Prefer the ignore_exceptions/excluded_exceptions option key you find in Configuration.php over writing a before_send filter; it runs earlier and is cheaper.
Release hygiene from CI. Set SENTRY_RELEASE to the git SHA or tag in your deploy pipeline (env var, not code) so issues group correctly and source-map/commit association works. Wrong or missing release is the #1 cause of "Sentry is useless for us".
Custom breadcrumbs / instrumentation: subscribe to domain events and add breadcrumbs, rather than editing the bundle:
$this->hub->addBreadcrumb(new Breadcrumb($category, $message, null, $level, $data));
DBAL/exception-reporter demo is the closest thing to a worked example. 1.11.2 moved it from SQLite to a MySQL 8.4 service — read it as reference wiring for the reporter integration, but don't copy the demo's .env/DNS assumptions into your app; only the DATABASE_URL shape is instructive.
Test it without network. In test env, leave SENTRY_DSN empty, and assert on captured events by swapping the transport/hub client in KernelTestCase:
public function testExceptionIsReported(): void
{
$client = static::createClient();
$this->expectException(\RuntimeException::class);
$client->catchExceptions(false);
$client->request('GET', '/boom');
}
Combine with a fake transport (implement TransportInterface) bound via a test-only service override to assert capture count == 1. Asserting "only once" is the highest-value test here, because double registration is the likeliest bug.
Upgrade pattern: the project now enforces a 99% coverage gate, PHPStan, Rector and Igor in CI, which raises confidence in refactors — but that is the bundle's tests, not yours. Still bump one version at a time, run your exception-reporting test, then widen the constraint. Start each upgrade at UPGRADING.md#to-<version>.
docs/SECURITY.md, dependency policy, static analysis, coverage gate, open-PR release gate) but that documents intent — it does not audit the listener code for you. Pin the exact version ("1.11.2"), commit composer.lock, and read every listener before production. If the enhanced listeners don't buy you something concrete, drop it and use sentry/sentry-symfony directly — it's maintained by Sentry.nowo-tech/sentry-bundle:0.* no longer tracks the current line. The reviewed release is 1.11.2; check CHANGELOG for anything between the 0.x you may have benchmarked and 1.x.nowo_tech_sentry vs nowo_sentry vs nested sentry: — Symfony will fail with Unrecognized option, and nested trees silently differ between versions. Always config:dump-reference.priority in src/Resources/config/ — a listener with priority below Symfony's ErrorListener may see an already-normalized exception.sentry/sentry-symfony are enabled. Symptom: every issue has 2 events, 1 second apart, or duplicated breadcrumbs. Bisect by disabling one bundle.bin/console failures get reported with no environment distinction. Set environment: prod-console or a console tag so a broken nightly job doesn't page the on-call for web traffic.NotFoundHttpException is captured, bots and security scanners will burn your quota. Exclude 403/404 explicitly and verify with a curl to a random path.extra/request. Scrub with the SDK's before_send (and options.integrations / default-integrations removal) — this is your legal obligation, not the bundle's. docs/SECURITY.md gives you the threat model to justify your scrubbing decisions; it does not implement the scrubbing.SENTRY_DSN leaks into .env.test. Set it empty there; the client no-ops.traces_sample_rate off (or very low) until you've measured, and don't run Xdebug in the request cycle.services.yaml, override config, or use a compiler pass for priority. If you find yourself editing vendor/nowo-tech/..., you've found a bug worth upstreaming or forking — forking two listeners remains a legitimate strategy.How can I help you explore Laravel packages today?