diff --git a/core/includes/errors.inc b/core/includes/errors.inc index 23ed7d4bb7880033e731c07eada81bec011e1482..62179edf63ce3ecbbbdb851a5acbec70bc246a63 100644 --- a/core/includes/errors.inc +++ b/core/includes/errors.inc @@ -79,6 +79,7 @@ function _drupal_error_handler_real($error_level, $message, $filename, $line) { 'severity_level' => $severity_level, 'backtrace' => $backtrace, '@backtrace_string' => (new \Exception())->getTraceAsString(), + 'exception' => NULL, ], $recoverable || $to_string); } // If the site is a test site then fail for user deprecations so they can be @@ -133,10 +134,12 @@ function error_displayable($error = NULL) { * Logs a PHP error or exception and displays an error page in fatal cases. * * @param $error - * An array with the following keys: %type, @message, %function, %file, - * %line, @backtrace_string, severity_level, and backtrace. All the parameters - * are plain-text, with the exception of @message, which needs to be an HTML - * string, and backtrace, which is a standard PHP backtrace. + * An array with the following keys: %type, @message, %function, %file, %line, + * @backtrace_string, severity_level, backtrace, and exception. All the + * parameters are plain-text, with the exception of @message, which needs to + * be an HTML string, backtrace, which is a standard PHP backtrace, and + * exception, which is the exception object (or NULL if the error is not an + * exception). * @param bool $fatal * TRUE for: * - An exception is thrown and not caught by something else. @@ -146,13 +149,12 @@ function error_displayable($error = NULL) { function _drupal_log_error($error, $fatal = FALSE) { $is_installer = InstallerKernel::installationAttempted(); - // Remove 'severity_level' as is not a valid replacement for t(). - $severity = $error['severity_level']; - unset($error['severity_level']); - - // Backtrace array is not a valid replacement value for t(). + // Backtrace, exception and 'severity_level' are not valid replacement values + // for t(). $backtrace = $error['backtrace']; - unset($error['backtrace']); + $exception = $error['exception']; + $severity = $error['severity_level']; + unset($error['backtrace'], $error['exception'], $error['severity_level']); // When running inside the testing framework, we relay the errors // to the tested site by the way of HTTP headers. @@ -167,10 +169,10 @@ function _drupal_log_error($error, $fatal = FALSE) { // installer. if (\Drupal::hasService('logger.factory')) { try { - // Provide the PHP backtrace to logger implementations. Add + // Provide the PHP backtrace and exception to logger implementations. Add // 'severity_level' to the context to maintain BC and allow logging // implementations to use it. - \Drupal::logger('php')->log($severity, '%type: @message in %function (line %line of %file) @backtrace_string.', $error + ['backtrace' => $backtrace, 'severity_level' => $severity]); + \Drupal::logger('php')->log($severity, '%type: @message in %function (line %line of %file) @backtrace_string.', $error + ['backtrace' => $backtrace, 'exception' => $exception, 'severity_level' => $severity]); } catch (\Exception $e) { // We can't log, for example because the database connection is not diff --git a/core/includes/update.inc b/core/includes/update.inc index bea0c861e37a979a4f231f115de20f22001e28c8..d5818d005aaab967209d363737ba7687d483d6ec 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -231,8 +231,7 @@ function update_do_one($module, $number, $dependency_map, &$context) { watchdog_exception('update', $e); $variables = Error::decodeException($e); - unset($variables['backtrace']); - unset($variables['severity_level']); + unset($variables['backtrace'], $variables['exception'], $variables['severity_level']); $ret['#abort'] = ['success' => FALSE, 'query' => t('%type: @message in %function (line %line of %file).', $variables)]; } } @@ -299,7 +298,7 @@ function update_invoke_post_update($function, &$context) { watchdog_exception('update', $e); $variables = Error::decodeException($e); - unset($variables['backtrace']); + unset($variables['backtrace'], $variables['exception']); $ret['#abort'] = [ 'success' => FALSE, 'query' => t('%type: @message in %function (line %line of %file).', $variables), diff --git a/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php index a2a09ecf54c922ee83ec752e4b1a23ea20f1f6de..87d716932296c08bad8c0e6958d0df5ee804bece 100644 --- a/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php @@ -93,8 +93,7 @@ public function onException(ExceptionEvent $event) { $error = $this->simplifyFileInError($error); - unset($error['backtrace']); - unset($error['severity_level']); + unset($error['backtrace'], $error['exception'], $error['severity_level']); if (!$this->isErrorLevelVerbose()) { // Without verbose logging, use a simple message. diff --git a/core/lib/Drupal/Core/Utility/Error.php b/core/lib/Drupal/Core/Utility/Error.php index 092f7626e21031f73a0b4b34e6977a293bf86781..306486ed7a56e056b1491a49b27a6d51b9d73b82 100644 --- a/core/lib/Drupal/Core/Utility/Error.php +++ b/core/lib/Drupal/Core/Utility/Error.php @@ -71,6 +71,7 @@ public static function decodeException($exception) { 'severity_level' => static::ERROR, 'backtrace' => $backtrace, '@backtrace_string' => $exception->getTraceAsString(), + 'exception' => $exception, ]; } @@ -86,7 +87,7 @@ public static function decodeException($exception) { public static function renderExceptionSafe($exception) { $decode = static::decodeException($exception); $backtrace = $decode['backtrace']; - unset($decode['backtrace']); + unset($decode['backtrace'], $decode['exception']); // Remove 'main()'. array_shift($backtrace); diff --git a/core/modules/dblog/src/Logger/DbLog.php b/core/modules/dblog/src/Logger/DbLog.php index 5933e222810c35c183d20cbf45ba1b93a9d3776a..4207a5c9db09fb62634a4d188628f37bd242b57b 100644 --- a/core/modules/dblog/src/Logger/DbLog.php +++ b/core/modules/dblog/src/Logger/DbLog.php @@ -53,8 +53,8 @@ public function __construct(Connection $connection, LogMessageParserInterface $p * {@inheritdoc} */ public function log($level, $message, array $context = []) { - // Remove any backtraces since they may contain an unserializable variable. - unset($context['backtrace']); + // Remove backtrace and exception since they may contain an unserializable variable. + unset($context['backtrace'], $context['exception']); // Convert PSR3-style messages to \Drupal\Component\Render\FormattableMarkup // style, so they can be translated too in runtime. diff --git a/core/tests/Drupal/Tests/Core/Error/DrupalLogErrorTest.php b/core/tests/Drupal/Tests/Core/Error/DrupalLogErrorTest.php index a867cd196b0a4be154811240e0392c70a1b7c6a9..40103f08abba33e0f370d457bfef02e95ac89309 100644 --- a/core/tests/Drupal/Tests/Core/Error/DrupalLogErrorTest.php +++ b/core/tests/Drupal/Tests/Core/Error/DrupalLogErrorTest.php @@ -35,6 +35,7 @@ public function testFatalExitCode() { '@backtrace_string' => 'backtrace', 'severity_level' => 0, 'backtrace' => [], + 'exception' => NULL, ]; _drupal_log_error($error, TRUE); EOT;