Added secondary error handling in Handler
This should allow Catcher to print errors even if there are errors encountered when logging or exporting variables in stack traces
This commit is contained in:
parent
5d8e77e89a
commit
a525fad96a
2 changed files with 63 additions and 2 deletions
|
@ -7,7 +7,8 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
namespace MensBeam\Catcher;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use MensBeam\Catcher,
|
||||
Psr\Log\LoggerInterface;
|
||||
|
||||
|
||||
abstract class Handler {
|
||||
|
@ -146,6 +147,49 @@ abstract class Handler {
|
|||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* If an error is triggered while logging the error would be output by PHP's
|
||||
* handler. This is used to attempt as best as possible to have the error be
|
||||
* output by Catcher.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function handleError(int $code, string $message, ?string $file = null, ?int $line = null): bool {
|
||||
if ($code && $code & error_reporting()) {
|
||||
// PHP's method for getting the current exception handler is stupid,
|
||||
// but that's how it is...
|
||||
$exceptionHandler = set_exception_handler(null);
|
||||
set_exception_handler($exceptionHandler);
|
||||
|
||||
// If the current exception handler happens to not be Catcher use PHP's handler
|
||||
// instead; this shouldn't happen but is here just in case
|
||||
if (!is_array($exceptionHandler) || !$exceptionHandler[0] instanceof Catcher) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$catcher = $exceptionHandler[0];
|
||||
$handlers = $catcher->getHandlers();
|
||||
$silent = false;
|
||||
foreach ($handlers as $h) {
|
||||
$h->setOption('logger', null);
|
||||
$h->setOption('varExporter', null);
|
||||
$silent = (!$silent) ? $h->getOption('silent') : $silent;
|
||||
}
|
||||
|
||||
// If all of the handlers are silent then use PHP's handler instead; this is
|
||||
// because a valid use for Catcher is to have it be silent but instead have the
|
||||
// logger print the errors to stderr/stdout; if there is an error in the logger
|
||||
// then it wouldn't print.
|
||||
if ($silent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$catcher->handleThrowable(new Error($message, $code, $file, $line));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setOption(string $name, mixed $value): void {
|
||||
$class = get_class($this);
|
||||
if (!property_exists($class, "_$name")) {
|
||||
|
@ -219,7 +263,12 @@ abstract class Handler {
|
|||
abstract protected function invokeCallback(): void;
|
||||
|
||||
protected function log(\Throwable $throwable, string $message): void {
|
||||
if ($this->_logger === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$context = [ 'exception' => $throwable ];
|
||||
set_error_handler([ $this, 'handleError' ]);
|
||||
if ($throwable instanceof \Error) {
|
||||
switch ($throwable->getCode()) {
|
||||
case \E_NOTICE:
|
||||
|
@ -246,6 +295,7 @@ abstract class Handler {
|
|||
} else {
|
||||
$this->_logger->critical($message, $context);
|
||||
}
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
protected function print(string $string): void {
|
||||
|
@ -257,4 +307,15 @@ abstract class Handler {
|
|||
|
||||
echo $string;
|
||||
}
|
||||
|
||||
|
||||
protected function varExporter(mixed $value): string|bool {
|
||||
$exporter = $this->_varExporter;
|
||||
|
||||
set_error_handler([ $this, 'handleError' ]);
|
||||
$value = $exporter($value);
|
||||
restore_error_handler();
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
|
@ -86,7 +86,7 @@ class PlainTextHandler extends Handler {
|
|||
|
||||
if (!empty($frame['args']) && $this->_backtraceArgFrameLimit > $key) {
|
||||
$varExporter = $this->_varExporter;
|
||||
$output .= preg_replace('/^/m', "$indent| ", $varExporter($frame['args'])) . \PHP_EOL;
|
||||
$output .= preg_replace('/^/m', "$indent| ", $this->varExporter($frame['args'])) . \PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue