From 2ec8ff5d9b79f435330db4a5bad0ba4bf41410f5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Nov 2023 10:47:24 +0900 Subject: [PATCH 1/3] fix: bug where ExceptionHandler displays incorrect Exception classname It showed the first Exception, but devs must catch the thrown Exception. --- app/Views/errors/cli/error_exception.php | 17 +++++++++++++---- app/Views/errors/html/error_exception.php | 23 +++++++++++++++++++++++ system/Debug/BaseExceptionHandler.php | 9 ++++++++- system/Debug/Exceptions.php | 14 ++++++++------ 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/app/Views/errors/cli/error_exception.php b/app/Views/errors/cli/error_exception.php index f24e98fb9a49..98d83b0ed3a6 100644 --- a/app/Views/errors/cli/error_exception.php +++ b/app/Views/errors/cli/error_exception.php @@ -3,17 +3,26 @@ use CodeIgniter\CLI\CLI; // The main Exception -CLI::newLine(); CLI::write('[' . get_class($exception) . ']', 'light_gray', 'red'); -CLI::newLine(); CLI::write($message); -CLI::newLine(); CLI::write('at ' . CLI::color(clean_path($exception->getFile()) . ':' . $exception->getLine(), 'green')); CLI::newLine(); +$last = $exception; + +while ($prevException = $last->getPrevious()) { + $last = $prevException; + + CLI::write(' Caused by:'); + CLI::write(' [' . get_class($prevException) . ']', 'red'); + CLI::write(' ' . $prevException->getMessage()); + CLI::write(' at ' . CLI::color(clean_path($prevException->getFile()) . ':' . $prevException->getLine(), 'green')); + CLI::newLine(); +} + // The backtrace if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) { - $backtraces = $exception->getTrace(); + $backtraces = $last->getTrace(); if ($backtraces) { CLI::write('Backtrace:', 'green'); diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php index 1c094d728872..406b48ec6772 100644 --- a/app/Views/errors/html/error_exception.php +++ b/app/Views/errors/html/error_exception.php @@ -44,6 +44,29 @@ +
+ getPrevious()) { + $last = $prevException; + ?> + +
+    Caused by:
+    getCode() ? ' #' . $prevException->getCode() : '') ?>
+
+    getMessage())) ?>
+    getMessage())) ?>"
+       rel="noreferrer" target="_blank">search →
+    getFile()) . ':' . $prevException->getLine()) ?>
+    
+ + +
+
diff --git a/system/Debug/BaseExceptionHandler.php b/system/Debug/BaseExceptionHandler.php index 0330c53cf97c..8b67d2153f9f 100644 --- a/system/Debug/BaseExceptionHandler.php +++ b/system/Debug/BaseExceptionHandler.php @@ -67,7 +67,14 @@ abstract public function handle( */ protected function collectVars(Throwable $exception, int $statusCode): array { - $trace = $exception->getTrace(); + // Get the first exception. + $firstException = $exception; + + while ($prevException = $firstException->getPrevious()) { + $firstException = $prevException; + } + + $trace = $firstException->getTrace(); if ($this->config->sensitiveDataInTrace !== []) { $trace = $this->maskSensitiveData($trace, $this->config->sensitiveDataInTrace); diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index a9887fba15ce..37b0376990de 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -136,11 +136,6 @@ public function exceptionHandler(Throwable $exception) $this->request = Services::request(); $this->response = Services::response(); - // Get the first exception. - while ($prevException = $exception->getPrevious()) { - $exception = $prevException; - } - if (method_exists($this->config, 'handler')) { // Use new ExceptionHandler $handler = $this->config->handler($statusCode, $exception); @@ -325,7 +320,14 @@ protected function render(Throwable $exception, int $statusCode) */ protected function collectVars(Throwable $exception, int $statusCode): array { - $trace = $exception->getTrace(); + // Get the first exception. + $firstException = $exception; + + while ($prevException = $firstException->getPrevious()) { + $firstException = $prevException; + } + + $trace = $firstException->getTrace(); if ($this->config->sensitiveDataInTrace !== []) { $trace = $this->maskSensitiveData($trace, $this->config->sensitiveDataInTrace); From 181b93f922959294b5b837e002cbeb9814183f19 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Nov 2023 13:10:45 +0900 Subject: [PATCH 2/3] docs: add upgrade guide --- user_guide_src/source/installation/upgrade_444.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/user_guide_src/source/installation/upgrade_444.rst b/user_guide_src/source/installation/upgrade_444.rst index b3773947efd9..e21a1850d613 100644 --- a/user_guide_src/source/installation/upgrade_444.rst +++ b/user_guide_src/source/installation/upgrade_444.rst @@ -16,6 +16,14 @@ Please refer to the upgrade instructions corresponding to your installation meth Mandatory File Changes ********************** +Error Files +=========== + +Update the following files to show correct error messages: + +- app/Views/errors/cli/error_exception.php +- app/Views/errors/html/error_exception.php + **************** Breaking Changes **************** From 886aa89de958c7998a82f664cc919bdec0c5bae5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Nov 2023 19:06:27 +0900 Subject: [PATCH 3/3] feat: log exception classname and all previous exceptions --- system/Debug/Exceptions.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 37b0376990de..4b3e5cf3ea3e 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -125,12 +125,26 @@ public function exceptionHandler(Throwable $exception) [$statusCode, $exitCode] = $this->determineCodes($exception); if ($this->config->log === true && ! in_array($statusCode, $this->config->ignoreCodes, true)) { - log_message('critical', "{message}\nin {exFile} on line {exLine}.\n{trace}", [ + log_message('critical', get_class($exception) . ": {message}\nin {exFile} on line {exLine}.\n{trace}", [ 'message' => $exception->getMessage(), 'exFile' => clean_path($exception->getFile()), // {file} refers to THIS file 'exLine' => $exception->getLine(), // {line} refers to THIS line 'trace' => self::renderBacktrace($exception->getTrace()), ]); + + // Get the first exception. + $last = $exception; + + while ($prevException = $last->getPrevious()) { + $last = $prevException; + + log_message('critical', '[Caused by] ' . get_class($prevException) . ": {message}\nin {exFile} on line {exLine}.\n{trace}", [ + 'message' => $prevException->getMessage(), + 'exFile' => clean_path($prevException->getFile()), // {file} refers to THIS file + 'exLine' => $prevException->getLine(), // {line} refers to THIS line + 'trace' => self::renderBacktrace($prevException->getTrace()), + ]); + } } $this->request = Services::request();