feat: support frame filters

This commit is contained in:
Shakir El Amrani
2023-02-19 15:09:19 +00:00
parent b32e315e5d
commit 30fa50c046
11 changed files with 148 additions and 10 deletions
+4 -3
View File
@@ -14,10 +14,11 @@ class Formatter
* Returns all basic information about the exception in a simple array
* for further convertion to other languages
* @param InspectorInterface $inspector
* @param bool $shouldAddTrace
* @param bool $shouldAddTrace
* @param array<callable> $frameFilters
* @return array
*/
public static function formatExceptionAsDataArray(InspectorInterface $inspector, $shouldAddTrace)
public static function formatExceptionAsDataArray(InspectorInterface $inspector, $shouldAddTrace, array $frameFilters = [])
{
$exception = $inspector->getException();
$response = [
@@ -29,7 +30,7 @@ class Formatter
];
if ($shouldAddTrace) {
$frames = $inspector->getFrames();
$frames = $inspector->getFrames($frameFilters);
$frameData = [];
foreach ($frames as $frame) {
+11 -1
View File
@@ -176,9 +176,12 @@ class Inspector implements InspectorInterface
/**
* Returns an iterator for the inspected exception's
* frames.
*
* @param array<callable> $frameFilters
*
* @return \Whoops\Exception\FrameCollection
*/
public function getFrames()
public function getFrames(array $frameFilters = [])
{
if ($this->frames === null) {
$frames = $this->getTrace($this->exception);
@@ -234,6 +237,13 @@ class Inspector implements InspectorInterface
$newFrames->prependFrames($outerFrames->topDiff($newFrames));
$this->frames = $newFrames;
}
// Apply frame filters callbacks on the frames stack
if (!empty($frameFilters)) {
foreach ($frameFilters as $filterCallback) {
$this->frames->filter($filterCallback);
}
}
}
return $this->frames;
+4 -2
View File
@@ -60,7 +60,8 @@ class JsonResponseHandler extends Handler
'errors' => [
Formatter::formatExceptionAsDataArray(
$this->getInspector(),
$this->addTraceToOutput()
$this->addTraceToOutput(),
$this->getRun()->getFrameFilters()
),
]
];
@@ -68,7 +69,8 @@ class JsonResponseHandler extends Handler
$response = [
'error' => Formatter::formatExceptionAsDataArray(
$this->getInspector(),
$this->addTraceToOutput()
$this->addTraceToOutput(),
$this->getRun()->getFrameFilters()
),
];
}
+1 -1
View File
@@ -282,7 +282,7 @@ class PlainTextHandler extends Handler
return '';
}
$inspector = $this->getInspector();
$frames = $inspector->getFrames();
$frames = $inspector->getFrames($this->getRun()->getFrameFilters());
$response = "\nStack trace:";
+1 -1
View File
@@ -304,7 +304,7 @@ class PrettyPageHandler extends Handler
*/
protected function getExceptionFrames()
{
$frames = $this->getInspector()->getFrames();
$frames = $this->getInspector()->getFrames($this->getRun()->getFrameFilters());
if ($this->getApplicationPaths()) {
foreach ($frames as $frame) {
+2 -1
View File
@@ -43,7 +43,8 @@ class XmlResponseHandler extends Handler
$response = [
'error' => Formatter::formatExceptionAsDataArray(
$this->getInspector(),
$this->addTraceToOutput()
$this->addTraceToOutput(),
$this->getRun()->getFrameFilters()
),
];
+4 -1
View File
@@ -62,7 +62,10 @@ interface InspectorInterface
/**
* Returns an iterator for the inspected exception's
* frames.
*
* @param array<callable> $frameFilters
*
* @return \Whoops\Exception\FrameCollection
*/
public function getFrames();
public function getFrames(array $frameFilters = []);
}
+28
View File
@@ -76,6 +76,11 @@ final class Run implements RunInterface
*/
private $inspectorFactory;
/**
* @var array<callable>
*/
private $frameFilters = [];
public function __construct(SystemFacade $system = null)
{
$this->system = $system ?: new SystemFacade;
@@ -176,6 +181,17 @@ final class Run implements RunInterface
return $this;
}
public function getFrameFilters()
{
return $this->frameFilters;
}
public function clearFrameFilters()
{
$this->frameFilters = [];
return $this;
}
/**
* Registers this instance as an error handler.
*
@@ -511,6 +527,18 @@ final class Run implements RunInterface
$this->inspectorFactory = $factory;
}
public function addFrameFilter($filterCallback)
{
if (!is_callable($filterCallback)) {
throw new \InvalidArgumentException(sprintf(
"A frame filter must be of type callable, %s type given.",
gettype($filterCallback)
));
}
$this->frameFilters[] = $filterCallback;
return $this;
}
/**
* @param Throwable $exception
+18
View File
@@ -49,6 +49,16 @@ interface RunInterface
*/
public function clearHandlers();
/**
* @return array<callable>
*/
public function getFrameFilters();
/**
* @return Run
*/
public function clearFrameFilters();
/**
* Registers this instance as an error handler.
*
@@ -137,4 +147,12 @@ interface RunInterface
* Special case to deal with Fatal errors and the like.
*/
public function handleShutdown();
/**
* Registers a filter callback in the frame filters stack.
*
* @param callable $filterCallback
* @return \Whoops\Run
*/
public function addFrameFilter($filterCallback);
}
+36
View File
@@ -95,6 +95,42 @@ class InspectorTest extends TestCase
$this->assertInstanceOf('Whoops\\Exception\\FrameCollection', $inspector->getFrames());
}
/**
* @covers Whoops\Exception\Inspector::getFrames
*/
public function testGetFramesWithFiltersReturnsCollection()
{
$exception = $this->getException();
$inspector = $this->getInspectorInstance($exception);
$frames = $inspector->getFrames([
function(Frame $frame) {
return true;
},
]);
$this->assertInstanceOf('Whoops\\Exception\\FrameCollection', $frames);
$this->assertNotEmpty($frames);
}
/**
* @covers Whoops\Exception\Inspector::getFrames
*/
public function testGetFramesWithFiltersReturnsEmptyCollection()
{
$exception = $this->getException();
$inspector = $this->getInspectorInstance($exception);
$frames = $inspector->getFrames([
function(Frame $frame) {
return false;
},
]);
$this->assertInstanceOf('Whoops\\Exception\\FrameCollection', $frames);
$this->assertEmpty($frames);
}
/**
* @covers Whoops\Exception\Inspector::hasPreviousException
* @covers Whoops\Exception\Inspector::getPreviousExceptionInspector
+39
View File
@@ -12,6 +12,7 @@ use InvalidArgumentException;
use Mockery as m;
use RuntimeException;
use Whoops\Handler\Handler;
use Whoops\Exception\Frame;
class RunTest extends TestCase
{
@@ -532,4 +533,42 @@ class RunTest extends TestCase
$this->getRunInstance()->sendExitCode(255);
}
/**
* @covers Whoops\Run::addFrameFilter
* @covers Whoops\Run::getFrameFilters
*/
public function testAddFrameFilter()
{
$run = $this->getRunInstance();
$filterCallbackOne = function(Frame $frame) {};
$filterCallbackTwo = function(Frame $frame) {};
$run
->addFrameFilter($filterCallbackOne)
->addFrameFilter($filterCallbackTwo);
$frameFilters = $run->getFrameFilters();
$this->assertCount(2, $frameFilters);
$this->assertContains($filterCallbackOne, $frameFilters);
$this->assertContains($filterCallbackTwo, $frameFilters);
$this->assertInstanceOf("Whoops\\RunInterface", $run);
}
/**
* @covers Whoops\Run::clearFrameFilters
* @covers Whoops\Run::getFrameFilters
*/
public function testClearFrameFilters()
{
$run = $this->getRunInstance();
$run->addFrameFilter(function(Frame $frame) {});
$run = $run->clearFrameFilters();
$this->assertEmpty($run->getFrameFilters());
$this->assertInstanceOf("Whoops\\RunInterface", $run);
}
}