From 721fb6f2120f34ba370c6a806b3fbebad93479f0 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Wed, 22 Mar 2023 02:23:50 +0100 Subject: [PATCH 1/8] feat: Add ignore_exceptions & ignore_transactions --- phpstan-baseline.neon | 10 +++++ src/Client.php | 46 ++++++++++++++++++++ src/Integration/IgnoreErrorsIntegration.php | 2 + src/Options.php | 48 +++++++++++++++++++++ tests/ClientTest.php | 47 ++++++++++++++++++++ tests/OptionsTest.php | 18 ++++++++ 6 files changed, 171 insertions(+) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c3ddeb163..cfa8e8af6 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -150,6 +150,16 @@ parameters: count: 1 path: src/Options.php + - + message: "#^Method Sentry\\\\Options\\:\\:getIgnoreExceptions\\(\\) should return array\\ but returns mixed\\.$#" + count: 1 + path: src/Options.php + + - + message: "#^Method Sentry\\\\Options\\:\\:getIgnoreTransactions\\(\\) should return array\\ but returns mixed\\.$#" + count: 1 + path: src/Options.php + - message: "#^Method Sentry\\\\Options\\:\\:getInAppExcludedPaths\\(\\) should return array\\ but returns mixed\\.$#" count: 1 diff --git a/src/Client.php b/src/Client.php index 3d090cac9..333fb6812 100644 --- a/src/Client.php +++ b/src/Client.php @@ -281,6 +281,11 @@ private function prepareEvent(Event $event, ?EventHint $hint = null, ?Scope $sco return null; } + $event = $this->applyIgnoreOptions($event, $hint); + if (null === $event) { + return null; + } + if (null !== $scope) { $beforeEventProcessors = $event; $event = $scope->applyToEvent($event, $hint); @@ -311,6 +316,47 @@ private function prepareEvent(Event $event, ?EventHint $hint = null, ?Scope $sco return $event; } + private function applyIgnoreOptions(Event $event, ?EventHint $hint): ?Event + { + if ($event->getType() === EventType::event()) { + $exceptions = $event->getExceptions(); + + if (empty($exceptions)) { + return $event; + } + + foreach ($exceptions as $exception) { + if (\in_array($exception->getType(), $this->options->getIgnoreExceptions(), true)) { + $this->logger->info( + 'The event will be discarded because it matches an entry in "ignore_exceptions".', + ['event' => $event] + ); + + return null; + } + } + } + + if ($event->getType() === EventType::transaction()) { + $transactionName = $event->getTransaction(); + + if (null === $transactionName) { + return $event; + } + + if (\in_array($transactionName, $this->options->getIgnoreTransactions(), true)) { + $this->logger->info( + 'The event will be discarded because it matches a entry "ignore_transactions".', + ['event' => $event] + ); + + return null; + } + } + + return $event; + } + private function applyBeforeSendCallback(Event $event, ?EventHint $hint): ?Event { if ($event->getType() === EventType::event()) { diff --git a/src/Integration/IgnoreErrorsIntegration.php b/src/Integration/IgnoreErrorsIntegration.php index aae22e10b..7264be103 100644 --- a/src/Integration/IgnoreErrorsIntegration.php +++ b/src/Integration/IgnoreErrorsIntegration.php @@ -13,6 +13,8 @@ * This integration decides whether an event should not be captured according * to a series of options that must match with its data. * + * @deprecated since version 3.17, to be removed in 4.0. Use the `ignore_exceptions` option instead + * * @author Stefano Arlandini * * @psalm-type IntegrationOptions array{ diff --git a/src/Options.php b/src/Options.php index dbee7d128..1c0e4b8a6 100644 --- a/src/Options.php +++ b/src/Options.php @@ -416,6 +416,50 @@ public function setServerName(string $serverName): void $this->options = $this->resolver->resolve($options); } + /** + * Gets a list of exceptions to be ignored and not sent to Sentry. + * + * @return string[] + */ + public function getIgnoreExceptions(): array + { + return $this->options['ignore_exceptions']; + } + + /** + * Sets a list of exceptions to be ignored and not sent to Sentry. + * + * @param string[] $ignoreErrors The list of exceptions to be ignored + */ + public function setIgnoreExceptions(array $ignoreErrors): void + { + $options = array_merge($this->options, ['ignore_exceptions' => $ignoreErrors]); + + $this->options = $this->resolver->resolve($options); + } + + /** + * Gets a list of transaction names to be ignored and not sent to Sentry. + * + * @return int[] + */ + public function getIgnoreTransactions(): array + { + return $this->options['ignore_transactions']; + } + + /** + * Sets a list of transaction names to be ignored and not sent to Sentry. + * + * @param int[] $ignoreTransaction The list of transaction names to be ignored + */ + public function setIgnoreTransactions(array $ignoreTransaction): void + { + $options = array_merge($this->options, ['ignore_transactions' => $ignoreTransaction]); + + $this->options = $this->resolver->resolve($options); + } + /** * Gets a callback that will be invoked before an event is sent to the server. * If `null` is returned it won't be sent. @@ -872,6 +916,8 @@ private function configureOptions(OptionsResolver $resolver): void 'release' => $_SERVER['SENTRY_RELEASE'] ?? null, 'dsn' => $_SERVER['SENTRY_DSN'] ?? null, 'server_name' => gethostname(), + 'ignore_exceptions' => [], + 'ignore_transactions' => [], 'before_send' => static function (Event $event): Event { return $event; }, @@ -916,6 +962,8 @@ private function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('server_name', 'string'); $resolver->setAllowedTypes('before_send', ['callable']); $resolver->setAllowedTypes('before_send_transaction', ['callable']); + $resolver->setAllowedTypes('ignore_exceptions', 'string[]'); + $resolver->setAllowedTypes('ignore_transactions', 'string[]'); $resolver->setAllowedTypes('trace_propagation_targets', 'string[]'); $resolver->setAllowedTypes('tags', 'string[]'); $resolver->setAllowedTypes('error_types', ['null', 'int']); diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 078ddc1b1..8ceaf1108 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -587,6 +587,53 @@ public function processEventDiscardsEventWhenItIsSampledDueToSampleRateOptionDat ]; } + public function testProcessEventDiscardsEventWhenIgnoreExceptionsMatches(): void + { + $exception = new \Exception('Some foo error'); + + /** @var LoggerInterface&MockObject $logger */ + $logger = $this->createMock(LoggerInterface::class); + $logger->expects($this->once()) + ->method('info') + ->with('The event will be discarded because it matches an entry in "ignore_exceptions".', $this->callback(static function (array $context): bool { + return isset($context['event']) && $context['event'] instanceof Event; + })); + + $options = [ + 'ignore_exceptions' => [\Exception::class], + ]; + + $client = ClientBuilder::create($options) + ->setLogger($logger) + ->getClient(); + + $client->captureException($exception); + } + + public function testProcessEventDiscardsEventWhenIgnoreTransactionsMatches(): void + { + $event = Event::createTransaction(); + $event->setTransaction('GET /foo'); + + /** @var LoggerInterface&MockObject $logger */ + $logger = $this->createMock(LoggerInterface::class); + $logger->expects($this->once()) + ->method('info') + ->with('The event will be discarded because it matches a entry "ignore_transactions".', $this->callback(static function (array $context): bool { + return isset($context['event']) && $context['event'] instanceof Event; + })); + + $options = [ + 'ignore_transactions' => ['GET /foo'], + ]; + + $client = ClientBuilder::create($options) + ->setLogger($logger) + ->getClient(); + + $client->captureEvent($event); + } + public function testProcessEventDiscardsEventWhenBeforeSendCallbackReturnsNull(): void { /** @var LoggerInterface&MockObject $logger */ diff --git a/tests/OptionsTest.php b/tests/OptionsTest.php index c58424878..178165b6c 100644 --- a/tests/OptionsTest.php +++ b/tests/OptionsTest.php @@ -266,6 +266,24 @@ static function (): void {}, null, ]; + yield [ + 'ignore_exceptions', + ['foo', 'bar'], + 'getIgnoreExceptions', + 'setIgnoreExceptions', + null, + null, + ]; + + yield [ + 'ignore_transactions', + ['foo', 'bar'], + 'getIgnoreTransactions', + 'setIgnoreTransactions', + null, + null, + ]; + yield [ 'before_send', static function (): void {}, From 18757f5ad83a11ea662c90cba75bffe5f2d15b62 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Wed, 22 Mar 2023 10:26:30 +0100 Subject: [PATCH 2/8] Fix type annotation --- src/Options.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Options.php b/src/Options.php index 1c0e4b8a6..fd216cb76 100644 --- a/src/Options.php +++ b/src/Options.php @@ -441,7 +441,7 @@ public function setIgnoreExceptions(array $ignoreErrors): void /** * Gets a list of transaction names to be ignored and not sent to Sentry. * - * @return int[] + * @return string[] */ public function getIgnoreTransactions(): array { @@ -451,7 +451,7 @@ public function getIgnoreTransactions(): array /** * Sets a list of transaction names to be ignored and not sent to Sentry. * - * @param int[] $ignoreTransaction The list of transaction names to be ignored + * @param string[] $ignoreTransaction The list of transaction names to be ignored */ public function setIgnoreTransactions(array $ignoreTransaction): void { From 693c0b2e7e620f545aa797a83449f0dbbd5ab445 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Wed, 22 Mar 2023 10:53:18 +0100 Subject: [PATCH 3/8] Remove unsued parameter --- src/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client.php b/src/Client.php index 333fb6812..bd43038fe 100644 --- a/src/Client.php +++ b/src/Client.php @@ -316,7 +316,7 @@ private function prepareEvent(Event $event, ?EventHint $hint = null, ?Scope $sco return $event; } - private function applyIgnoreOptions(Event $event, ?EventHint $hint): ?Event + private function applyIgnoreOptions(Event $event): ?Event { if ($event->getType() === EventType::event()) { $exceptions = $event->getExceptions(); From abfb323f60ccb34fa363447237390d2127a9aeb8 Mon Sep 17 00:00:00 2001 From: Michi Hoffmann Date: Wed, 22 Mar 2023 10:53:33 +0100 Subject: [PATCH 4/8] Update src/Client.php Co-authored-by: Alex Bouma --- src/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client.php b/src/Client.php index bd43038fe..3180c73d1 100644 --- a/src/Client.php +++ b/src/Client.php @@ -346,7 +346,7 @@ private function applyIgnoreOptions(Event $event): ?Event if (\in_array($transactionName, $this->options->getIgnoreTransactions(), true)) { $this->logger->info( - 'The event will be discarded because it matches a entry "ignore_transactions".', + 'The event will be discarded because it matches a entry in "ignore_transactions".', ['event' => $event] ); From c8347938eae80bc2d0e8af02f2372e19d4b4696d Mon Sep 17 00:00:00 2001 From: Michi Hoffmann Date: Wed, 22 Mar 2023 10:53:46 +0100 Subject: [PATCH 5/8] Update tests/ClientTest.php Co-authored-by: Alex Bouma --- tests/ClientTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 8ceaf1108..f5cf5beac 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -619,7 +619,7 @@ public function testProcessEventDiscardsEventWhenIgnoreTransactionsMatches(): vo $logger = $this->createMock(LoggerInterface::class); $logger->expects($this->once()) ->method('info') - ->with('The event will be discarded because it matches a entry "ignore_transactions".', $this->callback(static function (array $context): bool { + ->with('The event will be discarded because it matches a entry in "ignore_transactions".', $this->callback(static function (array $context): bool { return isset($context['event']) && $context['event'] instanceof Event; })); From 88f89d22651cf7f34ca372f1d25421dc7a47c962 Mon Sep 17 00:00:00 2001 From: Michi Hoffmann Date: Wed, 22 Mar 2023 10:53:55 +0100 Subject: [PATCH 6/8] Update src/Client.php Co-authored-by: Stefano Arlandini --- src/Client.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Client.php b/src/Client.php index 3180c73d1..26d06a1b9 100644 --- a/src/Client.php +++ b/src/Client.php @@ -282,6 +282,7 @@ private function prepareEvent(Event $event, ?EventHint $hint = null, ?Scope $sco } $event = $this->applyIgnoreOptions($event, $hint); + if (null === $event) { return null; } From 521d3a10f1d384ddf0867b8f92042b5aec14dc93 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Wed, 22 Mar 2023 10:55:32 +0100 Subject: [PATCH 7/8] CS --- src/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client.php b/src/Client.php index 26d06a1b9..40b092b04 100644 --- a/src/Client.php +++ b/src/Client.php @@ -282,7 +282,7 @@ private function prepareEvent(Event $event, ?EventHint $hint = null, ?Scope $sco } $event = $this->applyIgnoreOptions($event, $hint); - + if (null === $event) { return null; } From 8613949f6ec351fdbb1c7e5ca3960cbebd905e2a Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Wed, 22 Mar 2023 11:37:32 +0100 Subject: [PATCH 8/8] CS --- phpstan-baseline.neon | 2 +- src/Client.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index cfa8e8af6..a4f7cfdc8 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -156,7 +156,7 @@ parameters: path: src/Options.php - - message: "#^Method Sentry\\\\Options\\:\\:getIgnoreTransactions\\(\\) should return array\\ but returns mixed\\.$#" + message: "#^Method Sentry\\\\Options\\:\\:getIgnoreTransactions\\(\\) should return array\\ but returns mixed\\.$#" count: 1 path: src/Options.php diff --git a/src/Client.php b/src/Client.php index 40b092b04..a324c1153 100644 --- a/src/Client.php +++ b/src/Client.php @@ -281,7 +281,7 @@ private function prepareEvent(Event $event, ?EventHint $hint = null, ?Scope $sco return null; } - $event = $this->applyIgnoreOptions($event, $hint); + $event = $this->applyIgnoreOptions($event); if (null === $event) { return null;