_drupal_log_error($error, $fatal = FALSE)
Logs a PHP error or exception and displays an error page in fatal cases.
Parameters
$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.
bool $fatal: TRUE for:
- An exception is thrown and not caught by something else.
- A recoverable fatal error, which is a fatal error.
Non-recoverable fatal errors cannot be logged by Drupal.
File
- core/includes/errors.inc, line 129
- Functions for error handling.
Code
function _drupal_log_error($error, $fatal = FALSE) { $is_installer = drupal_installation_attempted(); // Backtrace array is not a valid replacement value for t(). $backtrace = $error['backtrace']; unset($error['backtrace']); // When running inside the testing framework, we relay the errors // to the tested site by the way of HTTP headers. if (DRUPAL_TEST_IN_CHILD_SITE && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) { // $number does not use drupal_static as it should not be reset // as it uniquely identifies each PHP error. static $number = 0; $assertion = array( $error['@message'], $error['%type'], array( 'function' => $error['%function'], 'file' => $error['%file'], 'line' => $error['%line'], ), ); // For non-fatal errors (e.g. PHP notices) _drupal_log_error can be called // multiple times per request. In that case the response is typically // generated outside of the error handler, e.g., in a controller. As a // result it is not possible to use a Response object here but instead the // headers need to be emitted directly. header('X-Drupal-Assertion-' . $number . ': ' . rawurlencode(serialize($assertion))); $number++; } $response = new Response(); // Only call the logger if there is a logger factory available. This can occur // if there is an error while rebuilding the container or during the // installer. if (\Drupal::hasService('logger.factory')) { try { \Drupal::logger('php')->log($error['severity_level'], '%type: @message in %function (line %line of %file) @backtrace_string.', $error); } catch (\Exception $e) { // We can't log, for example because the database connection is not // available. At least try to log to PHP error log. error_log(strtr('Failed to log error: %type: @message in %function (line %line of %file). @backtrace_string', $error)); } } // Log fatal errors, so developers can find and debug them. if ($fatal) { error_log(sprintf('%s: %s in %s on line %d %s', $error['%type'], $error['@message'], $error['%file'], $error['%line'], $error['@backtrace_string'])); } if (PHP_SAPI === 'cli') { if ($fatal) { // When called from CLI, simply output a plain text message. // Should not translate the string to avoid errors producing more errors. $response->setContent(html_entity_decode(strip_tags(SafeMarkup::format('%type: @message in %function (line %line of %file).', $error))) . "\n"); $response->send(); exit; } } if (\Drupal::hasRequest() && \Drupal::request()->isXmlHttpRequest()) { if ($fatal) { if (error_displayable($error)) { // When called from JavaScript, simply output the error message. // Should not translate the string to avoid errors producing more errors. $response->setContent(SafeMarkup::format('%type: @message in %function (line %line of %file).', $error)); $response->send(); } exit; } } else { // Display the message if the current error reporting level allows this type // of message to be displayed, and unconditionally in update.php. $message = ''; $class = NULL; if (error_displayable($error)) { $class = 'error'; // If error type is 'User notice' then treat it as debug information // instead of an error message. // @see debug() if ($error['%type'] == 'User notice') { $error['%type'] = 'Debug'; $class = 'status'; } // Attempt to reduce verbosity by removing DRUPAL_ROOT from the file path // in the message. This does not happen for (false) security. if (\Drupal::hasService('app.root')) { $root_length = strlen(\Drupal::root()); if (substr($error['%file'], 0, $root_length) == \Drupal::root()) { $error['%file'] = substr($error['%file'], $root_length + 1); } } // Check if verbose error reporting is on. $error_level = _drupal_get_error_level(); if ($error_level != ERROR_REPORTING_DISPLAY_VERBOSE) { // Without verbose logging, use a simple message. // We call SafeMarkup::format() directly here, rather than use t() since // we are in the middle of error handling, and we don't want t() to // cause further errors. $message = SafeMarkup::format('%type: @message in %function (line %line of %file).', $error); } else { // With verbose logging, we will also include a backtrace. // First trace is the error itself, already contained in the message. // While the second trace is the error source and also contained in the // message, the message doesn't contain argument values, so we output it // once more in the backtrace. array_shift($backtrace); // Generate a backtrace containing only scalar argument values. $error['@backtrace'] = Error::formatBacktrace($backtrace); $message = SafeMarkup::format('%type: @message in %function (line %line of %file). <pre class="backtrace">@backtrace</pre>', $error); } } if ($fatal) { // We fallback to a maintenance page at this point, because the page generation // itself can generate errors. // Should not translate the string to avoid errors producing more errors. $message = 'The website encountered an unexpected error. Please try again later.' . '<br />' . $message; if ($is_installer) { // install_display_output() prints the output and ends script execution. $output = array( '#title' => 'Error', '#markup' => $message, ); install_display_output($output, $GLOBALS['install_state'], $response->headers->all()); exit; } $response->setContent($message); $response->setStatusCode(500, '500 Service unavailable (with message)'); $response->send(); // An exception must halt script execution. exit; } if ($message) { if (\Drupal::hasService('session')) { // Message display is dependent on sessions being available. drupal_set_message($message, $class, TRUE); } else { print $message; } } } }
Please login to continue.