Go to the documentation of this file.
33 public const CAUGHT_BY_HANDLER =
'mwe_handler';
35 public const CAUGHT_BY_ENTRYPOINT =
'entrypoint';
37 public const CAUGHT_BY_OTHER =
'other';
80 set_exception_handler(
'MWExceptionHandler::handleUncaughtException' );
84 set_error_handler(
'MWExceptionHandler::handleError' );
89 self::$reservedMemory = str_repeat(
' ', 16384 );
90 register_shutdown_function(
'MWExceptionHandler::handleFatalError' );
97 protected static function report( Throwable $e ) {
108 }
catch ( Throwable $e2 ) {
127 $catcher = self::CAUGHT_BY_OTHER
129 $services = MediaWikiServices::getInstance();
130 if ( !$services->isServiceDisabled(
'DBLoadBalancerFactory' ) ) {
135 $services->getDBLoadBalancerFactory()->rollbackMasterChanges( __METHOD__ );
160 register_shutdown_function(
183 public static function handleException( Throwable $e, $catcher = self::CAUGHT_BY_OTHER ) {
228 case E_COMPILE_WARNING:
229 $prefix =
'PHP Warning: ';
230 $severity = LogLevel::ERROR;
233 $prefix =
'PHP Notice: ';
234 $severity = LogLevel::ERROR;
238 $prefix =
'PHP Notice: ';
239 $severity = LogLevel::WARNING;
243 $prefix =
'PHP Warning: ';
244 $severity = LogLevel::WARNING;
247 $prefix =
'PHP Strict Standards: ';
248 $severity = LogLevel::WARNING;
251 $prefix =
'PHP Deprecated: ';
252 $severity = LogLevel::WARNING;
254 case E_USER_DEPRECATED:
255 $prefix =
'PHP Deprecated: ';
256 $severity = LogLevel::WARNING;
262 $file = $real[
'file'];
263 $line = $real[
'line'];
264 $message = $real[
'message'];
269 $prefix =
'PHP Unknown error: ';
270 $severity = LogLevel::ERROR;
274 $e =
new ErrorException( $prefix . $message, 0, $level,
$file,
$line );
275 self::logError( $e,
'error', $severity, self::CAUGHT_BY_HANDLER );
300 self::$reservedMemory =
null;
302 $lastError = error_get_last();
303 if ( $lastError ===
null ) {
307 $level = $lastError[
'type'];
308 $message = $lastError[
'message'];
309 $file = $lastError[
'file'];
310 $line = $lastError[
'line'];
312 if ( !in_array( $level, self::$fatalErrorTypes ) ) {
320 '[{reqId}] {exception_url} PHP Fatal Error',
322 $line ?
" line $line" :
'',
324 $file ?
" $file" :
'',
327 $msg = implode(
'', $msgParts );
330 if ( preg_match(
"/Class '\w+' not found/", $message ) ) {
335 MediaWiki or an installed extension requires
this class but it is not embedded directly in
MediaWiki's git repository and must be installed separately by the end user.
337 Please see <a href=
"https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries">mediawiki.org</a>
for help on installing the required components.
342 $e =
new ErrorException(
"PHP Fatal Error: {$message}", 0, $level,
$file,
$line );
343 $logger = LoggerFactory::getInstance(
'exception' );
344 $logger->error( $msg, self::getLogContext( $e, self::CAUGHT_BY_HANDLER ) );
360 $from =
'from ' . $e->getFile() .
'(' . $e->getLine() .
')' .
"\n";
376 foreach ( $trace as $level => $frame ) {
377 if ( isset( $frame[
'file'] ) && isset( $frame[
'line'] ) ) {
378 $text .=
"{$pad}#{$level} {$frame['file']}({$frame['line']}): ";
384 $text .=
"{$pad}#{$level} [internal function]: ";
387 if ( isset( $frame[
'class'] ) && isset( $frame[
'type'] ) && isset( $frame[
'function'] ) ) {
388 $text .= $frame[
'class'] . $frame[
'type'] . $frame[
'function'];
389 } elseif ( isset( $frame[
'function'] ) ) {
390 $text .= $frame[
'function'];
392 $text .=
'NO_FUNCTION_GIVEN';
395 if ( isset( $frame[
'args'] ) ) {
396 $text .=
'(' . implode(
', ', $frame[
'args'] ) .
")\n";
403 $text .=
"{$pad}#{$level} {main}";
420 return static::redactTrace( $e->getTrace() );
434 return array_map(
function ( $frame ) {
435 if ( isset( $frame[
'args'] ) ) {
436 $frame[
'args'] = array_map(
function ( $arg ) {
437 return is_object( $arg ) ? get_class( $arg ) : gettype( $arg );
472 $type = get_class( $e );
473 $message = $e->getMessage();
477 $message =
"A database query error has occurred. Did you forget to run"
478 .
" your application's database schema updater after upgrading?\n\n"
482 return "[$id] $url $type: $message";
495 $type = get_class( $e );
496 $message = $e->getMessage();
498 return "[{reqId}] {exception_url} $type: $message";
507 $type = get_class( $e );
508 return '[' . $reqId .
'] '
509 . gmdate(
'Y-m-d H:i:s' ) .
': '
510 .
'Fatal exception of type "' .
$type .
'"';
525 public static function getLogContext( Throwable $e, $catcher = self::CAUGHT_BY_OTHER ) {
536 'caught_by' => $catcher
554 $catcher = self::CAUGHT_BY_OTHER
560 'type' => get_class( $e ),
561 'file' => $e->getFile(),
562 'line' => $e->getLine(),
563 'message' => $e->getMessage(),
564 'code' => $e->getCode(),
566 'caught_by' => $catcher
569 if ( $e instanceof ErrorException &&
570 ( error_reporting() & $e->getSeverity() ) === 0
573 $data[
'suppressed'] =
true;
580 $previous = $e->getPrevious();
581 if ( $previous !==
null ) {
646 $catcher = self::CAUGHT_BY_OTHER
649 self::getStructuredExceptionData( $e, $catcher ),
668 $catcher = self::CAUGHT_BY_OTHER,
671 if ( !( $e instanceof
MWException ) || $e->isLoggable() ) {
672 $logger = LoggerFactory::getInstance(
'exception' );
675 $context[
'extraData'] = $extraData;
678 self::getLogNormalMessage( $e ),
683 if ( $json !==
false ) {
684 $logger = LoggerFactory::getInstance(
'exception-json' );
685 $logger->error( $json, [
'private' =>
true ] );
709 $suppressed = ( error_reporting() & $e->getSeverity() ) === 0;
710 if ( !$suppressed ) {
711 $logger = LoggerFactory::getInstance( $channel );
714 self::getLogNormalMessage( $e ),
715 self::getLogContext( $e, $catcher )
721 if ( $json !==
false ) {
722 $logger = LoggerFactory::getInstance(
"{$channel}-json" );
729 $unfilteredLevel = $suppressed ? LogLevel::DEBUG : $level;
730 $logger->log( $unfilteredLevel, $json, [
'private' =>
true ] );
static handleFatalError()
Callback used as a registered shutdown function.
WebRequest clone which takes values from a provided array.
static logError(ErrorException $e, $channel, $level, $catcher)
Log an exception that wasn't thrown but made to wrap an error.
static getPublicLogMessage(Throwable $e)
Handler class for MWExceptions.
static redactTrace(array $trace)
Redact a stacktrace generated by Throwable::getTrace(), debug_backtrace() or similar means.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
static installHandler()
Install handlers with PHP.
static getStructuredExceptionData(Throwable $e, $catcher=self::CAUGHT_BY_OTHER)
Get a structured representation of a Throwable.
$wgPropagateErrors
If true, the MediaWiki error handler passes errors/warnings to the default error handler after loggin...
static logException(Throwable $e, $catcher=self::CAUGHT_BY_OTHER, $extraData=[])
Log a throwable to the exception log (if enabled).
static report(Throwable $e)
Report a throwable to the user.
static getRedactedTraceAsString(Throwable $e)
Generate a string representation of a throwable's stack trace.
static prettyPrintTrace(array $trace, $pad='')
Generate a string representation of a stacktrace.
static handleException(Throwable $e, $catcher=self::CAUGHT_BY_OTHER)
Exception handler which simulates the appropriate catch() handling:
static getURL()
If the exception occurred in the course of responding to a request, returns the requested URL.
static $fatalErrorTypes
Error types that, if unhandled, are fatal to the request.
static output(Throwable $e, $mode, Throwable $eNew=null)
$wgLogExceptionBacktrace
If true, send the exception backtrace to the error log.
wfIsCLI()
Check if we are running from the commandline.
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
static getLogNormalMessage(Throwable $e)
Get a normalised message for formatting with PSR-3 log event context.
static getLogContext(Throwable $e, $catcher=self::CAUGHT_BY_OTHER)
Get a PSR-3 log event context from a Throwable.
static handleUncaughtException(Throwable $e)
Callback to use with PHP's set_exception_handler.
static rollbackMasterChangesAndLog(Throwable $e, $catcher=self::CAUGHT_BY_OTHER)
Roll back any open database transactions and log the stack trace of the throwable.
static getRequestId()
Get the unique request ID.
static getGlobalRequestURL()
Return the path and query string portion of the main request URI.
if(! $wgDBerrorLogTZ) $wgRequest
static getRedactedTrace(Throwable $e)
Return a copy of a throwable's backtrace as an array.
static parseCallerDescription( $msg)
Append a caller description to an error message.
static handleError( $level, $message, $file=null, $line=null)
Handler for set_error_handler() callback notifications.
static jsonSerializeException(Throwable $e, $pretty=false, $escaping=0, $catcher=self::CAUGHT_BY_OTHER)
Serialize a Throwable object to JSON.
static getLogMessage(Throwable $e)
Get a message formatting the throwable message and its origin.