Matthias Lantsch(3 years, 2 months ago)
Rework error handling to handle errors in production (without whoops) better
Browse Filesdiff --git a/e2e6fe6d1cbd9996b60262dc89f2cee900b0277e b/f1f13ce5f2b7ce470484c5c0707caa60e2a87e39
index e2e6fe6..f1f13ce 100644
--- a/e2e6fe6d1cbd9996b60262dc89f2cee900b0277e
+++ b/f1f13ce5f2b7ce470484c5c0707caa60e2a87e39
@@ -24,6 +24,11 @@ class ErrorDispatcher {
*/
private array $exceptionHandlers = array();
+ /**
+ * @var ErrorHandler $finalHandler Last error handler to be called
+ */
+ private ?ErrorHandler $finalHandler = null;
+
/**
* @var callable[] $shutdownHandlers
*/
@@ -53,6 +58,10 @@ class ErrorDispatcher {
foreach ($this->errorHandlers as $handler) {
$handler(...$args);
}
+
+ if ($this->finalHandler !== null) {
+ $this->finalHandler->handleError(...$args);
+ }
});
/**
@@ -63,6 +72,10 @@ class ErrorDispatcher {
foreach ($this->exceptionHandlers as $handler) {
$handler(...$args);
}
+
+ if ($this->finalHandler !== null) {
+ $this->finalHandler->handleException(...$args);
+ }
});
/**
@@ -73,6 +86,14 @@ class ErrorDispatcher {
foreach ($this->shutdownHandlers as $handler) {
$handler(...$args);
}
+
+ if ($this->finalHandler !== null) {
+ $this->finalHandler->handleShutdown(...$args);
+ }
});
}
+
+ public function setFinalHandler(ErrorHandler $finalHandler): void {
+ $this->finalHandler = $finalHandler;
+ }
}
diff --git a/63f09dabbe2c79b34b800a12ce7f9c89b55282d6 b/4def0ee8dca6b0bd944667f2bbee599dfbe544ae
index 63f09da..4def0ee 100644
--- a/63f09dabbe2c79b34b800a12ce7f9c89b55282d6
+++ b/4def0ee8dca6b0bd944667f2bbee599dfbe544ae
@@ -39,7 +39,9 @@ class ErrorHandler {
\E_USER_DEPRECATED => array('level' => LogLevel::WARNING, 'name' => 'E_USER_DEPRECATED'),
);
- private ?LoggerInterface $logger;
+ protected ?Throwable $lastException = null;
+
+ protected ?LoggerInterface $logger;
public function __construct(?LoggerInterface $logger = null) {
$this->logger = $logger;
@@ -60,7 +62,7 @@ class ErrorHandler {
return null;
}
- list('type' => $type, 'name' => $name) = (self::ERROR_LEVEL_LOOKUP[$errno] ?? self::ERROR_LEVEL_LOOKUP[\E_ERROR]);
+ list('level' => $type, 'name' => $name) = (self::ERROR_LEVEL_LOOKUP[$errno] ?? self::ERROR_LEVEL_LOOKUP[\E_ERROR]);
if ($this->logger !== null) {
$this->logger->log(
@@ -95,6 +97,34 @@ class ErrorHandler {
$this->logger->log(LogLevel::ERROR, $message, array('exception' => $exception));
}
- exit(255);
+ $this->lastException = $exception;
+ }
+
+ /**
+ * Shutdown function
+ * should be changed in extending classes to add more functionality to it.
+ */
+ public function handleShutdown(): void {
+ if (($error = $this->getLastError()) !== null) {
+ echo $error;
+ exit(255);
+ }
+ }
+
+ /**
+ * Return the last error message if there was one.
+ * Can be used in fatal shutdown handlers to help.
+ */
+ protected function getLastError(): ?string {
+ if ($this->lastException !== null) {
+ $class = get_class($this->lastException);
+
+ return "Unwanted crash due to {$class}: {$this->lastException->getMessage()}";
+ }
+ if (($lasterror = error_get_last()) !== null) {
+ return "Unwanted crash due to: {$lasterror['message']} in file {$lasterror['file']} on line {$lasterror['line']}";
+ }
+
+ return null;
}
}