Skip to content

Commit

Permalink
Merge pull request #622 from bugsnag/discard-classes
Browse files Browse the repository at this point in the history
Add ability to discard events based on class/error names
  • Loading branch information
imjoehaines committed Feb 3, 2021
2 parents 3fad001 + b74fe8e commit 1364efe
Show file tree
Hide file tree
Showing 10 changed files with 507 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ Changelog
* Out of memory errors will now be reported by increasing the memory limit by 5 MiB. Use the new `memoryLimitIncrease` configuration option to change the amount of memory, or set it to `null` to disable the increase entirely.
[#621](https://github.com/bugsnag/bugsnag-php/pull/621)

* Add a "discard classes" configuration option that allows events to be discarded based on the exception class name or PHP error name
[#622](https://github.com/bugsnag/bugsnag-php/pull/622)

## 3.25.0 (2020-11-25)

### Enhancements
Expand Down
28 changes: 28 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Bugsnag\Internal\GuzzleCompat;
use Bugsnag\Middleware\BreadcrumbData;
use Bugsnag\Middleware\CallbackBridge;
use Bugsnag\Middleware\DiscardClasses;
use Bugsnag\Middleware\NotificationSkipper;
use Bugsnag\Middleware\SessionData;
use Bugsnag\Request\BasicResolver;
Expand Down Expand Up @@ -137,6 +138,7 @@ public function __construct(
$this->sessionTracker = new SessionTracker($config, $this->http);

$this->registerMiddleware(new NotificationSkipper($config));
$this->registerMiddleware(new DiscardClasses($config));
$this->registerMiddleware(new BreadcrumbData($this->recorder));
$this->registerMiddleware(new SessionData($this));

Expand Down Expand Up @@ -959,4 +961,30 @@ public function getMemoryLimitIncrease()
{
return $this->config->getMemoryLimitIncrease();
}

/**
* Set the array of classes that should not be sent to Bugsnag.
*
* @param array $discardClasses
*
* @return $this
*/
public function setDiscardClasses(array $discardClasses)
{
$this->config->setDiscardClasses($discardClasses);

return $this;
}

/**
* Get the array of classes that should not be sent to Bugsnag.
*
* This can contain both fully qualified class names and regular expressions.
*
* @var array
*/
public function getDiscardClasses()
{
return $this->config->getDiscardClasses();
}
}
35 changes: 35 additions & 0 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,15 @@ class Configuration
*/
protected $memoryLimitIncrease = 5242880;

/**
* An array of classes that should not be sent to Bugsnag.
*
* This can contain both fully qualified class names and regular expressions.
*
* @var array
*/
protected $discardClasses = [];

/**
* Create a new config instance.
*
Expand Down Expand Up @@ -801,4 +810,30 @@ public function getMemoryLimitIncrease()
{
return $this->memoryLimitIncrease;
}

/**
* Set the array of classes that should not be sent to Bugsnag.
*
* @param array $discardClasses
*
* @return $this
*/
public function setDiscardClasses(array $discardClasses)
{
$this->discardClasses = $discardClasses;

return $this;
}

/**
* Get the array of classes that should not be sent to Bugsnag.
*
* This can contain both fully qualified class names and regular expressions.
*
* @var array
*/
public function getDiscardClasses()
{
return $this->discardClasses;
}
}
50 changes: 50 additions & 0 deletions src/Middleware/DiscardClasses.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Bugsnag\Middleware;

use Bugsnag\Configuration;
use Bugsnag\Report;

class DiscardClasses
{
/**
* @var \Bugsnag\Configuration
*/
protected $config;

/**
* @param \Bugsnag\Configuration $config
*/
public function __construct(Configuration $config)
{
$this->config = $config;
}

/**
* @param \Bugsnag\Report $report
* @param callable $next
*
* @return void
*/
public function __invoke(Report $report, callable $next)
{
$errors = $report->getErrors();

foreach ($this->config->getDiscardClasses() as $discardClass) {
foreach ($errors as $error) {
if ($error['errorClass'] === $discardClass
|| @preg_match($discardClass, $error['errorClass']) === 1
) {
syslog(LOG_INFO, sprintf(
'Discarding event because error class "%s" matched discardClasses configuration',
$error['errorClass']
));

return;
}
}
}

$next($report);
}
}
33 changes: 33 additions & 0 deletions src/Report.php
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,39 @@ public function setSessionData(array $session)
$this->session = $session;
}

/**
* Get a list of all errors in a fixed format of:
* - 'errorClass'
* - 'errorMessage'
* - 'type' (always 'php').
*
* @return array
*/
public function getErrors()
{
$errors = [$this->toError()];
$previous = $this->previous;

while ($previous) {
$errors[] = $previous->toError();
$previous = $previous->previous;
}

return $errors;
}

/**
* @return array
*/
private function toError()
{
return [
'errorClass' => $this->name,
'errorMessage' => $this->message,
'type' => 'php',
];
}

/**
* Get the array representation.
*
Expand Down
51 changes: 51 additions & 0 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Exception;
use GuzzleHttp\Client as Guzzle;
use GuzzleHttp\Psr7\Uri;
use LogicException;
use PHPUnit\Framework\MockObject\MockObject;

/**
Expand Down Expand Up @@ -461,6 +462,37 @@ function (Report $report) use (&$pipelineCompleted) {
$this->assertTrue($pipelineCompleted);
}

public function testItAddsDiscardClassesMiddlewareByDefault()
{
$syslog = $this->getFunctionMock('Bugsnag\Middleware', 'syslog');
$syslog->expects($this->once())->with(
LOG_INFO,
'Discarding event because error class "Exception" matched discardClasses configuration'
);

$client = Client::make('foo');
$client->setDiscardClasses([Exception::class]);

$report = Report::fromPHPThrowable(
$client->getConfig(),
new Exception('oh no')
);

$pipeline = $client->getPipeline();
$pipelineCompleted = false;

$pipeline->execute(
$report,
function () use (&$pipelineCompleted) {
$pipelineCompleted = true;

throw new LogicException('This should never be reached!');
}
);

$this->assertFalse($pipelineCompleted);
}

public function testBreadcrumbsWorks()
{
$this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle);
Expand Down Expand Up @@ -1146,6 +1178,25 @@ public function testMemoryLimitIncreaseCanBeSetToNull()
$this->assertNull($this->client->getMemoryLimitIncrease());
}

public function testDiscardClassesDefault()
{
$this->assertSame([], $this->client->getDiscardClasses());
}

public function testDiscardClassesCanBeSet()
{
$discardClasses = [
\RuntimeException::class,
\LogicException::class,
\TypeError::class,
'/^(Under|Over)flowException$/',
];

$this->client->setDiscardClasses($discardClasses);

$this->assertSame($discardClasses, $this->client->getDiscardClasses());
}

private function getGuzzleOption($guzzle, $name)
{
if (GuzzleCompat::isUsingGuzzle5()) {
Expand Down
19 changes: 19 additions & 0 deletions tests/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,23 @@ public function testMemoryLimitIncreaseCanBeSetToNull()

$this->assertNull($this->config->getMemoryLimitIncrease());
}

public function testDiscardClassesDefault()
{
$this->assertSame([], $this->config->getDiscardClasses());
}

public function testDiscardClassesCanBeSet()
{
$discardClasses = [
\RuntimeException::class,
\LogicException::class,
\TypeError::class,
'/^(Under|Over)flowException$/',
];

$this->config->setDiscardClasses($discardClasses);

$this->assertSame($discardClasses, $this->config->getDiscardClasses());
}
}
9 changes: 9 additions & 0 deletions tests/Fakes/SomeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Bugsnag\Tests\Fakes;

use Exception;

final class SomeException extends Exception
{
}
Loading

0 comments on commit 1364efe

Please sign in to comment.