Chris@0: configFactory = $config_factory; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the configured error level. Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: protected function getErrorLevel() { Chris@0: if (!isset($this->errorLevel)) { Chris@0: $this->errorLevel = $this->configFactory->get('system.logging')->get('error_level'); Chris@0: } Chris@0: return $this->errorLevel; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Handles exceptions for this subscriber. Chris@0: * Chris@0: * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event Chris@0: * The event to process. Chris@0: */ Chris@0: public function onException(GetResponseForExceptionEvent $event) { Chris@0: $exception = $event->getException(); Chris@0: $error = Error::decodeException($exception); Chris@0: Chris@0: // Display the message if the current error reporting level allows this type Chris@0: // of message to be displayed, and unconditionally in update.php. Chris@0: $message = ''; Chris@0: if ($this->isErrorDisplayable($error)) { Chris@0: // If error type is 'User notice' then treat it as debug information Chris@0: // instead of an error message. Chris@0: // @see debug() Chris@0: if ($error['%type'] == 'User notice') { Chris@0: $error['%type'] = 'Debug'; Chris@0: } Chris@0: Chris@0: $error = $this->simplifyFileInError($error); Chris@0: Chris@0: unset($error['backtrace']); Chris@0: Chris@0: if (!$this->isErrorLevelVerbose()) { Chris@0: // Without verbose logging, use a simple message. Chris@0: Chris@17: // We use \Drupal\Component\Render\FormattableMarkup directly here, Chris@17: // rather than use t() since we are in the middle of error handling, and Chris@17: // we don't want t() to cause further errors. Chris@17: $message = new FormattableMarkup('%type: @message in %function (line %line of %file).', $error); Chris@0: } Chris@0: else { Chris@0: // With verbose logging, we will also include a backtrace. Chris@0: Chris@0: $backtrace_exception = $exception; Chris@0: while ($backtrace_exception->getPrevious()) { Chris@0: $backtrace_exception = $backtrace_exception->getPrevious(); Chris@0: } Chris@0: $backtrace = $backtrace_exception->getTrace(); Chris@0: // First trace is the error itself, already contained in the message. Chris@0: // While the second trace is the error source and also contained in the Chris@0: // message, the message doesn't contain argument values, so we output it Chris@0: // once more in the backtrace. Chris@0: array_shift($backtrace); Chris@0: Chris@0: // Generate a backtrace containing only scalar argument values. Chris@0: $error['@backtrace'] = Error::formatBacktrace($backtrace); Chris@17: $message = new FormattableMarkup('%type: @message in %function (line %line of %file).
@backtrace
', $error); Chris@0: } Chris@0: } Chris@0: Chris@0: $content = $this->t('The website encountered an unexpected error. Please try again later.'); Chris@0: $content .= $message ? '

' . $message : ''; Chris@0: $response = new Response($content, 500, ['Content-Type' => 'text/plain']); Chris@0: Chris@0: if ($exception instanceof HttpExceptionInterface) { Chris@0: $response->setStatusCode($exception->getStatusCode()); Chris@0: $response->headers->add($exception->getHeaders()); Chris@0: } Chris@0: else { Chris@0: $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR, '500 Service unavailable (with message)'); Chris@0: } Chris@0: Chris@0: $event->setResponse($response); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public static function getSubscribedEvents() { Chris@0: // Run as the final (very late) KernelEvents::EXCEPTION subscriber. Chris@0: $events[KernelEvents::EXCEPTION][] = ['onException', -256]; Chris@0: return $events; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Checks whether the error level is verbose or not. Chris@0: * Chris@0: * @return bool Chris@0: */ Chris@0: protected function isErrorLevelVerbose() { Chris@0: return $this->getErrorLevel() === ERROR_REPORTING_DISPLAY_VERBOSE; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Wrapper for error_displayable(). Chris@0: * Chris@0: * @param $error Chris@0: * Optional error to examine for ERROR_REPORTING_DISPLAY_SOME. Chris@0: * Chris@0: * @return bool Chris@0: * Chris@0: * @see \error_displayable Chris@0: */ Chris@0: protected function isErrorDisplayable($error) { Chris@0: return error_displayable($error); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Attempts to reduce error verbosity in the error message's file path. Chris@0: * Chris@0: * Attempts to reduce verbosity by removing DRUPAL_ROOT from the file path in Chris@0: * the message. This does not happen for (false) security. Chris@0: * Chris@0: * @param $error Chris@0: * Optional error to examine for ERROR_REPORTING_DISPLAY_SOME. Chris@0: * Chris@0: * @return Chris@0: * The updated $error. Chris@0: */ Chris@0: protected function simplifyFileInError($error) { Chris@0: // Attempt to reduce verbosity by removing DRUPAL_ROOT from the file path Chris@0: // in the message. This does not happen for (false) security. Chris@0: $root_length = strlen(DRUPAL_ROOT); Chris@0: if (substr($error['%file'], 0, $root_length) == DRUPAL_ROOT) { Chris@0: $error['%file'] = substr($error['%file'], $root_length + 1); Chris@0: } Chris@0: return $error; Chris@0: } Chris@0: Chris@0: }