Skip to content

Commit 3b09f81

Browse files
authored
Add the IgnoreErrorsIntegration integration and deprecate the excluded_exceptions option (#928)
1 parent a59b1ec commit 3b09f81

20 files changed

+393
-66
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Fix remaining PHP 7.4 deprecations (#930)
66
- Make the `integrations` option accept a `callable` that will receive the list of default integrations and returns a customized list (#919)
7+
- Add the `IgnoreErrorsIntegration` integration to deprecate and replace the `exclude_exceptions` option (#928)
78

89
## 2.2.5 (2019-11-27)
910

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
# Sentry for PHP
88

9-
[![Build Status](https://secure.travis-ci.org/getsentry/sentry-php.png?branch=develop)](http://travis-ci.org/getsentry/sentry-php)
10-
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/getsentry/sentry-php?branch=master&svg=true)](https://ci.appveyor.com/project/sentry/sentry-php)
9+
[![Build Status](https://img.shields.io/travis/getsentry/sentry-php/develop?logo=travis)](http://travis-ci.org/getsentry/sentry-php)
10+
[![AppVeyor Build Status](https://img.shields.io/appveyor/ci/sentry/sentry-php/develop?logo=appveyor)](https://ci.appveyor.com/project/sentry/sentry-php)
1111
[![Total Downloads](https://poser.pugx.org/sentry/sentry/downloads)](https://packagist.org/packages/sentry/sentry)
1212
[![Monthly Downloads](https://poser.pugx.org/sentry/sentry/d/monthly)](https://packagist.org/packages/sentry/sentry)
1313
[![Latest Stable Version](https://poser.pugx.org/sentry/sentry/v/stable)](https://packagist.org/packages/sentry/sentry)
@@ -24,8 +24,8 @@ information needed to prioritize, identify, reproduce and fix each issue.
2424
To install the SDK you will need to be using [Composer]([https://getcomposer.org/)
2525
in your project. To install it please see the [docs](https://getcomposer.org/download/).
2626

27-
This is our "core" SDK, meaning that all the important code regarding error handling lives here.
28-
If you are happy with using the HTTP client we recommend install the SDK like: [`sentry/sdk`](https://github.com/getsentry/sentry-php-sdk)
27+
This is our "core" SDK, meaning that all the important code regarding error handling lives here.
28+
If you are happy with using the HTTP client we recommend install the SDK like: [`sentry/sdk`](https://github.com/getsentry/sentry-php-sdk)
2929

3030
```bash
3131
php composer.phar require sentry/sdk

phpstan.neon

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ parameters:
3131
-
3232
message: '/^Property Sentry\\HttpClient\\HttpClientFactory::\$httpClient \(Http\\Client\\HttpAsyncClient\|null\) does not accept Http\\Client\\Curl\\Client.$/'
3333
path: src/HttpClient/HttpClientFactory.php
34+
-
35+
message: '/^Access to an undefined property Sentry\\Integration\\IntegrationInterface::\$options\.$/'
36+
path: src/Integration/IgnoreErrorsIntegration.php
37+
-
38+
message: '/^Call to an undefined method Sentry\\Integration\\IntegrationInterface::shouldDropEvent\(\)\.$/'
39+
path: src/Integration/IgnoreErrorsIntegration.php
3440
excludes_analyse:
3541
- tests/resources
3642
- tests/Fixtures

src/Client.php

+12-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use GuzzleHttp\Promise\FulfilledPromise;
88
use GuzzleHttp\Promise\PromiseInterface;
99
use Sentry\Integration\Handler;
10+
use Sentry\Integration\IgnoreErrorsIntegration;
1011
use Sentry\Integration\IntegrationInterface;
1112
use Sentry\State\Scope;
1213
use Sentry\Transport\ClosableTransportInterface;
@@ -45,7 +46,9 @@ final class Client implements FlushableClientInterface
4546
private $eventFactory;
4647

4748
/**
48-
* @var IntegrationInterface[] The stack of integrations
49+
* @var array<string, IntegrationInterface> The stack of integrations
50+
*
51+
* @psalm-var array<class-string<IntegrationInterface>, IntegrationInterface>
4952
*/
5053
private $integrations;
5154

@@ -96,7 +99,7 @@ public function captureMessage(string $message, ?Severity $level = null, ?Scope
9699
*/
97100
public function captureException(\Throwable $exception, ?Scope $scope = null): ?string
98101
{
99-
if ($this->options->isExcludedException($exception)) {
102+
if (!isset($this->integrations[IgnoreErrorsIntegration::class]) && $this->options->isExcludedException($exception, false)) {
100103
return null;
101104
}
102105

@@ -135,9 +138,12 @@ public function captureLastError(?Scope $scope = null): ?string
135138

136139
/**
137140
* {@inheritdoc}
141+
*
142+
* @psalm-template T of IntegrationInterface
138143
*/
139144
public function getIntegration(string $className): ?IntegrationInterface
140145
{
146+
/** @psalm-var T|null */
141147
return $this->integrations[$className] ?? null;
142148
}
143149

@@ -178,6 +184,10 @@ private function prepareEvent(array $payload, ?Scope $scope = null, bool $withSt
178184

179185
if (null !== $scope) {
180186
$event = $scope->applyToEvent($event, $payload);
187+
188+
if (null === $event) {
189+
return null;
190+
}
181191
}
182192

183193
return \call_user_func($this->options->getBeforeSendCallback(), $event);

src/ClientInterface.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,15 @@ public function captureLastError(?Scope $scope = null): ?string;
5252
public function captureEvent(array $payload, ?Scope $scope = null): ?string;
5353

5454
/**
55-
* Returns the integration instance if it is installed on the Client.
55+
* Returns the integration instance if it is installed on the client.
5656
*
5757
* @param string $className the classname of the integration
58+
*
59+
* @psalm-template T of IntegrationInterface
60+
*
61+
* @psalm-param class-string<T> $className
62+
*
63+
* @psalm-return T|null
5864
*/
5965
public function getIntegration(string $className): ?IntegrationInterface;
6066
}

src/Integration/Handler.php

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ final class Handler
2222
* @param IntegrationInterface[] $integrations The integrations
2323
*
2424
* @return array<string, IntegrationInterface>
25+
*
26+
* @psalm-return array<class-string<IntegrationInterface>, IntegrationInterface>
2527
*/
2628
public static function setupIntegrations(array $integrations): array
2729
{
+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sentry\Integration;
6+
7+
use Sentry\Event;
8+
use Sentry\SentrySdk;
9+
use Sentry\State\Scope;
10+
use Symfony\Component\OptionsResolver\OptionsResolver;
11+
12+
/**
13+
* This integration decides whether an event should not be captured according
14+
* to a series of options that must match with its data.
15+
*
16+
* @author Stefano Arlandini <[email protected]>
17+
*/
18+
final class IgnoreErrorsIntegration implements IntegrationInterface
19+
{
20+
/**
21+
* @var array<string, mixed> The options
22+
*/
23+
private $options;
24+
25+
/**
26+
* Creates a new instance of this integration and configures it with the
27+
* given options.
28+
*
29+
* @param array<string, mixed> $options The options
30+
*
31+
* @psalm-param array{
32+
* ignore_exceptions?: bool
33+
* } $options
34+
*/
35+
public function __construct(array $options = [])
36+
{
37+
$resolver = new OptionsResolver();
38+
$resolver->setDefaults([
39+
'ignore_exceptions' => [],
40+
]);
41+
42+
$resolver->setAllowedTypes('ignore_exceptions', ['array']);
43+
44+
$this->options = $resolver->resolve($options);
45+
}
46+
47+
/**
48+
* {@inheritdoc}
49+
*/
50+
public function setupOnce(): void
51+
{
52+
Scope::addGlobalEventProcessor(function (Event $event): ?Event {
53+
$currentHub = SentrySdk::getCurrentHub();
54+
$integration = $currentHub->getIntegration(self::class);
55+
56+
if (null !== $integration && $integration->shouldDropEvent($event, $integration->options)) {
57+
return null;
58+
}
59+
60+
return $event;
61+
});
62+
}
63+
64+
/**
65+
* Checks whether the given event should be dropped according to the options
66+
* that configures the current instance of this integration.
67+
*
68+
* @param Event $event The event to check
69+
* @param array<string, mixed> $options The options of the integration
70+
*/
71+
private function shouldDropEvent(Event $event, array $options): bool
72+
{
73+
if ($this->isIgnoredException($event, $options)) {
74+
return true;
75+
}
76+
77+
return false;
78+
}
79+
80+
/**
81+
* Checks whether the given event should be dropped or not according to the
82+
* criteria defined in the integration's options.
83+
*
84+
* @param Event $event The event instance
85+
* @param array<string, mixed> $options The options of the integration
86+
*/
87+
private function isIgnoredException(Event $event, array $options): bool
88+
{
89+
$exceptions = $event->getExceptions();
90+
91+
if (empty($exceptions) || !isset($exceptions[0]['type'])) {
92+
return false;
93+
}
94+
95+
foreach ($options['ignore_exceptions'] as $ignoredException) {
96+
if (is_a($exceptions[0]['type'], $ignoredException, true)) {
97+
return true;
98+
}
99+
}
100+
101+
return false;
102+
}
103+
}

src/Options.php

+19-2
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,13 @@ public function setEnvironment(string $environment): void
225225
* events to Sentry.
226226
*
227227
* @return string[]
228+
*
229+
* @deprecated since version 2.3, to be removed in 3.0
228230
*/
229231
public function getExcludedExceptions(): array
230232
{
233+
@trigger_error(sprintf('Method %s() is deprecated since version 2.3 and will be removed in 3.0. Use the "IgnoreErrorsIntegration" integration instead.', __METHOD__), E_USER_DEPRECATED);
234+
231235
return $this->options['excluded_exceptions'];
232236
}
233237

@@ -236,9 +240,13 @@ public function getExcludedExceptions(): array
236240
* events to Sentry.
237241
*
238242
* @param string[] $exceptions The list of exception classes
243+
*
244+
* @deprecated since version 2.3, to be removed in 3.0
239245
*/
240246
public function setExcludedExceptions(array $exceptions): void
241247
{
248+
@trigger_error(sprintf('Method %s() is deprecated since version 2.3 and will be removed in 3.0. Use the "IgnoreErrorsIntegration" integration instead.', __METHOD__), E_USER_DEPRECATED);
249+
242250
$options = array_merge($this->options, ['excluded_exceptions' => $exceptions]);
243251

244252
$this->options = $this->resolver->resolve($options);
@@ -248,10 +256,19 @@ public function setExcludedExceptions(array $exceptions): void
248256
* Checks whether the given exception should be ignored when sending events
249257
* to Sentry.
250258
*
251-
* @param \Throwable $exception The exception
259+
* @param \Throwable $exception The exception
260+
* @param bool $throwDeprecation Flag indicating whether to throw a
261+
* deprecation for the usage of this
262+
* method
263+
*
264+
* @deprecated since version 2.3, to be removed in 3.0
252265
*/
253-
public function isExcludedException(\Throwable $exception): bool
266+
public function isExcludedException(\Throwable $exception, bool $throwDeprecation = true): bool
254267
{
268+
if ($throwDeprecation) {
269+
@trigger_error(sprintf('Method %s() is deprecated since version 2.3 and will be removed in 3.0. Use the "IgnoreErrorsIntegration" integration instead.', __METHOD__), E_USER_DEPRECATED);
270+
}
271+
255272
foreach ($this->options['excluded_exceptions'] as $exceptionClass) {
256273
if ($exception instanceof $exceptionClass) {
257274
return true;

src/State/HubInterface.php

+6-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use Sentry\Breadcrumb;
88
use Sentry\ClientInterface;
99
use Sentry\Integration\IntegrationInterface;
10-
use Sentry\SentrySdk;
1110
use Sentry\Severity;
1211

1312
/**
@@ -110,7 +109,6 @@ public function addBreadcrumb(Breadcrumb $breadcrumb): bool;
110109
* @return HubInterface
111110
*
112111
* @deprecated since version 2.2, to be removed in 3.0
113-
* @see SentrySdk::getCurrentHub()
114112
*/
115113
public static function getCurrent(): self;
116114

@@ -122,14 +120,19 @@ public static function getCurrent(): self;
122120
* @return HubInterface
123121
*
124122
* @deprecated since version 2.2, to be removed in 3.0
125-
* @see SentrySdk::setCurrentHub()
126123
*/
127124
public static function setCurrent(self $hub): self;
128125

129126
/**
130127
* Gets the integration whose FQCN matches the given one if it's available on the current client.
131128
*
132129
* @param string $className The FQCN of the integration
130+
*
131+
* @psalm-template T of IntegrationInterface
132+
*
133+
* @psalm-param class-string<T> $className
134+
*
135+
* @psalm-return T|null
133136
*/
134137
public function getIntegration(string $className): ?IntegrationInterface;
135138
}

tests/ClientTest.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Sentry\ClientBuilder;
1212
use Sentry\Event;
1313
use Sentry\Options;
14+
use Sentry\SentrySdk;
1415
use Sentry\Serializer\Serializer;
1516
use Sentry\Severity;
1617
use Sentry\Stacktrace;
@@ -71,6 +72,7 @@ public function testCaptureException(): void
7172
*/
7273
public function testCaptureExceptionDoesNothingIfExcludedExceptionsOptionMatches(bool $shouldCapture, string $excluded, \Throwable $thrown): void
7374
{
75+
/** @var TransportInterface&MockObject $transport */
7476
$transport = $this->createMock(TransportInterface::class);
7577
$transportFactory = $this->createTransportFactory($transport);
7678

@@ -86,7 +88,8 @@ public function testCaptureExceptionDoesNothingIfExcludedExceptionsOptionMatches
8688
->setTransportFactory($transportFactory)
8789
->getClient();
8890

89-
$client->captureException($thrown);
91+
SentrySdk::getCurrentHub()->bindClient($client);
92+
SentrySdk::getCurrentHub()->captureException($thrown);
9093
}
9194

9295
public function captureExceptionDoesNothingIfExcludedExceptionsOptionMatchesDataProvider(): array

0 commit comments

Comments
 (0)