From 97b5629cab51730e5bcdcadddd90598b5cb2d4d6 Mon Sep 17 00:00:00 2001 From: Tomas Majer Date: Thu, 29 Jan 2026 13:39:18 +0100 Subject: [PATCH 1/2] Add support for ignoring specific exceptions This change adds a new 'ignore_exceptions' configuration option that allows filtering out specific exception types from being sent to Sentry while still logging them locally via Tracy. Use case: In production environments with background workers (e.g., Hermes message queue workers), graceful shutdown is triggered via SIGTERM signal during deployments. This causes ShutdownException to be thrown, which is normal and expected behavior. However, these exceptions were being logged to Sentry, creating noise in error monitoring. With this change, you can configure exceptions to ignore: sentry: ignore_exceptions: - Tomaj\Hermes\Shutdown\ShutdownException Ignored exceptions are still logged to Tracy's local log files but won't be sent to Sentry, reducing noise and improving signal-to-noise ratio in error monitoring. --- README.md | 20 +++++++++++++++++++- src/DI/SentryExtension.php | 4 +++- src/SentryLogger.php | 16 ++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e58506b..0370bdd 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,9 @@ sentry: - mySection priority_mapping: # optional, mapping of custom log levels to ones that's Sentry aware of mypriority: warning + ignore_exceptions: # optional, list of exception class names to ignore + - Tomaj\Hermes\Shutdown\ShutdownException + - App\MyCustomException db_tracing: true # optional, defaults to "false", wraps DB connection so it adds span for every query ``` @@ -48,7 +51,22 @@ Sentry only allows strict set of severities. By default any message with unknown You can map your custom *priority* to Sentry's *severity* in config by using `priority_mapping` as shown in the example. -The allowed set of Sentry severities can be checked in [Sentry's PHP repository](https://github.com/getsentry/sentry-php/blob/master/src/Severity.php). +The allowed set of Sentry severities can be checked in [Sentry's PHP repository](https://github.com/getsentry/sentry-php/blob/master/src/Severity.php). + +### Ignoring exceptions + +In some cases, you might want to prevent certain exceptions from being sent to Sentry while still logging them locally via Tracy. This is useful for expected exceptions like graceful shutdown signals or business logic exceptions that don't require monitoring. + +Use `ignore_exceptions` config option to specify exception class names that should be ignored: + +```neon +sentry: + ignore_exceptions: + - Tomaj\Hermes\Shutdown\ShutdownException + - App\MyCustomException +``` + +Ignored exceptions will still be logged to Tracy's local log files but won't be sent to Sentry. ## Usage diff --git a/src/DI/SentryExtension.php b/src/DI/SentryExtension.php index 63b718d..4c6fa97 100644 --- a/src/DI/SentryExtension.php +++ b/src/DI/SentryExtension.php @@ -39,7 +39,8 @@ public function loadConfiguration() $logger ->addSetup('setUserFields', [$this->config->user_fields]) ->addSetup('setSessionSections', [$this->config->session_sections]) - ->addSetup('setPriorityMapping', [$this->config->priority_mapping]); + ->addSetup('setPriorityMapping', [$this->config->priority_mapping]) + ->addSetup('setIgnoredExceptions', [$this->config->ignore_exceptions]); $integrations = []; @@ -87,6 +88,7 @@ public function getConfigSchema(): Schema 'user_fields' => Expect::listOf(Expect::string())->default([]), 'session_sections' => Expect::listOf(Expect::string())->default([]), 'priority_mapping' => Expect::arrayOf(Expect::string(), Expect::string())->default([]), + 'ignore_exceptions' => Expect::listOf(Expect::string())->default([]), 'traces_sample_rate' => Expect::float()->dynamic(), 'profiles_sample_rate' => Expect::float()->dynamic(), diff --git a/src/SentryLogger.php b/src/SentryLogger.php index 34f0fe2..7dc4a76 100644 --- a/src/SentryLogger.php +++ b/src/SentryLogger.php @@ -30,6 +30,7 @@ class SentryLogger extends Logger private array $userFields = []; private array $sessionSections = []; private array $priorityMapping = []; + private array $ignoredExceptions = []; private ?float $tracesSampleRate = null; private ?float $profilesSampleRate = null; @@ -84,6 +85,11 @@ public function setPriorityMapping(array $priorityMapping) $this->priorityMapping = $priorityMapping; } + public function setIgnoredExceptions(array $ignoredExceptions) + { + $this->ignoredExceptions = $ignoredExceptions; + } + public function setTracesSampleRate(float $tracesSampleRate) { $this->tracesSampleRate = $tracesSampleRate; @@ -123,6 +129,16 @@ public function log($value, $priority = ILogger::INFO) return $response; } + // Check if exception should be ignored + if ($value instanceof Throwable) { + foreach ($this->ignoredExceptions as $ignoredException) { + if ($value instanceof $ignoredException) { + // Still log to Tracy, but skip sending to Sentry + return $response; + } + } + } + configureScope(function (Scope $scope) use ($severity) { if (!$severity) { return; From 0424343e15ada5ef82c9a7fd2159ba88778dffb8 Mon Sep 17 00:00:00 2001 From: Tomas Majer Date: Thu, 29 Jan 2026 14:33:50 +0100 Subject: [PATCH 2/2] Fix test failures on PHP 8.4+ - Suppress deprecation warning from ninjify/nunjuck using @ operator (nunjify/nunjuck uses deprecated lcg_value() function in PHP 8.4+) - Fix ApplicationMonitor hook to check if application.application service exists before trying to access it (fixes tests that don't register application service) --- src/DI/SentryExtension.php | 12 ++++++++---- tests/bootstrap.php | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/DI/SentryExtension.php b/src/DI/SentryExtension.php index 4c6fa97..409aef5 100644 --- a/src/DI/SentryExtension.php +++ b/src/DI/SentryExtension.php @@ -47,13 +47,17 @@ public function loadConfiguration() if ($this->config->traces_sample_rate !== null) { $logger->addSetup('setTracesSampleRate', [$this->config->traces_sample_rate]); - $this->getContainerBuilder() + $builder = $this->getContainerBuilder(); + $builder ->addDefinition($this->prefix('applicationMonitor')) ->setFactory(ApplicationMonitor::class); - /** @var ServiceDefinition $application */ - $application = $this->getContainerBuilder()->getDefinition('application.application'); - $application->addSetup('@Rootpd\NetteSentry\ApplicationMonitor::hook', ['@self']); + // Only hook ApplicationMonitor if application service exists + if ($builder->hasDefinition('application.application')) { + /** @var ServiceDefinition $application */ + $application = $builder->getDefinition('application.application'); + $application->addSetup('@Rootpd\NetteSentry\ApplicationMonitor::hook', ['@self']); + } if ($this->config->profiles_sample_rate !== null) { $logger->addSetup('setProfilesSampleRate', [$this->config->profiles_sample_rate]); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index aa80ed9..ec319c2 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -7,4 +7,5 @@ // Configure environment Environment::setupTester(); Environment::setupTimezone(); -Environment::setupVariables(__DIR__); +// Suppress deprecation warning from ninjify/nunjuck (uses deprecated lcg_value() in PHP 8.4+) +@Environment::setupVariables(__DIR__);