42 E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR,
54 set_exception_handler(
'MWExceptionHandler::handleUncaughtException' );
55 set_error_handler(
'MWExceptionHandler::handleError' );
58 self::$reservedMemory = str_repeat(
' ', 16384 );
59 register_shutdown_function(
'MWExceptionHandler::handleFatalError' );
77 }
catch ( Exception $e2 ) {
94 $services = MediaWikiServices::getInstance();
95 if ( !
$services->isServiceDisabled(
'DBLoadBalancerFactory' ) ) {
100 $services->getDBLoadBalancerFactory()->rollbackMasterChanges( __METHOD__ );
107 self::logException( $e2, self::CAUGHT_BY_HANDLER );
111 self::logException(
$e, self::CAUGHT_BY_HANDLER );
121 self::handleException(
$e );
125 register_shutdown_function(
148 self::rollbackMasterChangesAndLog(
$e );
171 $level, $message, $file =
null,
$line =
null
175 if ( in_array( $level, self::$fatalErrorTypes ) ) {
176 return call_user_func_array(
177 'MWExceptionHandler::handleFatalError', func_get_args()
184 case E_RECOVERABLE_ERROR:
185 $levelName =
'Error';
186 $severity = LogLevel::ERROR;
190 case E_COMPILE_WARNING:
192 $levelName =
'Warning';
193 $severity = LogLevel::WARNING;
197 $levelName =
'Notice';
198 $severity = LogLevel::INFO;
201 $levelName =
'Strict Standards';
202 $severity = LogLevel::DEBUG;
205 case E_USER_DEPRECATED:
206 $levelName =
'Deprecated';
207 $severity = LogLevel::INFO;
210 $levelName =
'Unknown error';
211 $severity = LogLevel::ERROR;
215 $e =
new ErrorException(
"PHP $levelName: $message", 0, $level, $file,
$line );
216 self::logError(
$e,
'error', $severity );
221 return !(
$wgPropagateErrors || $level == E_RECOVERABLE_ERROR || ini_get(
'track_errors' ) );
246 $level =
null, $message =
null, $file =
null,
$line =
null,
251 self::$reservedMemory =
null;
253 if ( $level ===
null ) {
255 if ( static::$handledFatalCallback ) {
261 $lastError = error_get_last();
262 if ( $lastError !==
null ) {
263 $level = $lastError[
'type'];
264 $message = $lastError[
'message'];
265 $file = $lastError[
'file'];
266 $line = $lastError[
'line'];
273 if ( !in_array( $level, self::$fatalErrorTypes ) ) {
279 $url = WebRequest::getGlobalRequestURL();
281 '[{exception_id}] {exception_url} PHP Fatal Error',
282 (
$line || $file ) ?
' from' :
'',
283 $line ?
" line $line" :
'',
284 (
$line && $file ) ?
' of' :
'',
285 $file ?
" $file" :
'',
288 $msg = implode(
'', $msgParts );
293 if ( preg_match(
"/Class (undefined: \w+|'\w+' not found)/", $message ) ) {
298MediaWiki 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.
300Please see <a
href=
"https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries">mediawiki.org</a>
for help on installing the required components.
311 $trace = $trace ?: debug_backtrace();
312 $logger = LoggerFactory::getInstance(
'fatal' );
313 $logger->error( $msg, [
314 'fatal_exception' => [
315 'class' => ErrorException::class,
316 'message' =>
"PHP Fatal Error: {$message}",
320 'trace' => self::prettyPrintTrace( self::redactTrace( $trace ) ),
322 'exception_id' => WebRequest::getRequestId(),
323 'exception_url' => $url,
324 'caught_by' => self::CAUGHT_BY_HANDLER
329 static::$handledFatalCallback =
true;
344 return self::prettyPrintTrace( self::getRedactedTrace(
$e ) );
359 foreach ( $trace as $level => $frame ) {
360 if ( isset( $frame[
'file'] ) && isset( $frame[
'line'] ) ) {
361 $text .=
"{$pad}#{$level} {$frame['file']}({$frame['line']}): ";
367 $text .=
"{$pad}#{$level} [internal function]: ";
370 if ( isset( $frame[
'class'] ) && isset( $frame[
'type'] ) && isset( $frame[
'function'] ) ) {
371 $text .= $frame[
'class'] . $frame[
'type'] . $frame[
'function'];
372 } elseif ( isset( $frame[
'function'] ) ) {
373 $text .= $frame[
'function'];
375 $text .=
'NO_FUNCTION_GIVEN';
378 if ( isset( $frame[
'args'] ) ) {
379 $text .=
'(' . implode(
', ', $frame[
'args'] ) .
")\n";
386 $text .=
"{$pad}#{$level} {main}";
403 return static::redactTrace(
$e->getTrace() );
417 return array_map(
function ( $frame ) {
418 if ( isset( $frame[
'args'] ) ) {
419 $frame[
'args'] = array_map(
function ( $arg ) {
420 return is_object( $arg ) ? get_class( $arg ) : gettype( $arg );
440 return WebRequest::getRequestId();
466 $id = WebRequest::getRequestId();
468 $file =
$e->getFile();
470 $message =
$e->getMessage();
471 $url = self::getURL() ?:
'[no req]';
473 return "[$id] $url $type from line $line of $file: $message";
487 $file =
$e->getFile();
489 $message =
$e->getMessage();
491 return "[{exception_id}] {exception_url} $type from line $line of $file: $message";
499 $reqId = WebRequest::getRequestId();
501 return '[' . $reqId .
'] '
502 . gmdate(
'Y-m-d H:i:s' ) .
': '
503 .
'Fatal exception of type "' .
$type .
'"';
520 'exception_id' => WebRequest::getRequestId(),
521 'exception_url' => self::getURL() ?:
'[no req]',
522 'caught_by' => $catcher
542 'id' => WebRequest::getRequestId(),
543 'type' => get_class(
$e ),
544 'file' =>
$e->getFile(),
545 'line' =>
$e->getLine(),
546 'message' =>
$e->getMessage(),
547 'code' =>
$e->getCode(),
548 'url' => self::getURL() ?:
null,
549 'caught_by' => $catcher
552 if (
$e instanceof ErrorException &&
553 ( error_reporting() &
$e->getSeverity() ) === 0
556 $data[
'suppressed'] =
true;
560 $data[
'backtrace'] = self::getRedactedTrace(
$e );
563 $previous =
$e->getPrevious();
564 if ( $previous !==
null ) {
565 $data[
'previous'] = self::getStructuredExceptionData( $previous, $catcher );
626 $e, $pretty =
false, $escaping = 0, $catcher = self::CAUGHT_BY_OTHER
628 return FormatJson::encode(
629 self::getStructuredExceptionData(
$e, $catcher ),
647 $logger = LoggerFactory::getInstance(
'exception' );
649 self::getLogNormalMessage(
$e ),
650 self::getLogContext(
$e, $catcher )
653 $json = self::jsonSerializeException(
$e,
false, FormatJson::ALL_OK, $catcher );
654 if ( $json !==
false ) {
655 $logger = LoggerFactory::getInstance(
'exception-json' );
656 $logger->error( $json, [
'private' =>
true ] );
659 Hooks::run(
'LogException', [
$e,
false ] );
672 ErrorException
$e, $channel, $level = LogLevel::ERROR
674 $catcher = self::CAUGHT_BY_HANDLER;
678 $suppressed = ( error_reporting() &
$e->getSeverity() ) === 0;
680 $logger = LoggerFactory::getInstance( $channel );
683 self::getLogNormalMessage(
$e ),
684 self::getLogContext(
$e, $catcher )
689 $json = self::jsonSerializeException(
$e,
false, FormatJson::ALL_OK, $catcher );
690 if ( $json !==
false ) {
691 $logger = LoggerFactory::getInstance(
"{$channel}-json" );
692 $logger->log( $level, $json, [
'private' =>
true ] );
$wgLogExceptionBacktrace
If true, send the exception backtrace to the error log.
$wgPropagateErrors
If true, the MediaWiki error handler passes errors/warnings to the default error handler after loggin...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
wfIsCLI()
Check if we are running from the commandline.
if(! $wgDBerrorLogTZ) $wgRequest
WebRequest clone which takes values from a provided array.
Handler class for MWExceptions.
static handleError( $level, $message, $file=null, $line=null)
Handler for set_error_handler() callback notifications.
static getRedactedTraceAsString( $e)
Generate a string representation of an exception's stack trace.
static handleFatalError( $level=null, $message=null, $file=null, $line=null, $context=null, $trace=null)
Dual purpose callback used as both a set_error_handler() callback and a registered shutdown function.
static jsonSerializeException( $e, $pretty=false, $escaping=0, $catcher=self::CAUGHT_BY_OTHER)
Serialize an Exception object to JSON.
static getLogMessage( $e)
Get a message formatting the exception message and its origin.
static getPublicLogMessage( $e)
static prettyPrintTrace(array $trace, $pad='')
Generate a string representation of a stacktrace.
static getLogNormalMessage( $e)
Get a normalised message for formatting with PSR-3 log event context.
static logError(ErrorException $e, $channel, $level=LogLevel::ERROR)
Log an exception that wasn't thrown but made to wrap an error.
static rollbackMasterChangesAndLog( $e)
Roll back any open database transactions and log the stack trace of the exception.
static handleUncaughtException( $e)
Callback to use with PHP's set_exception_handler.
static report( $e)
Report an exception to the user.
static getStructuredExceptionData( $e, $catcher=self::CAUGHT_BY_OTHER)
Get a structured representation of an Exception.
static redactTrace(array $trace)
Redact a stacktrace generated by Exception::getTrace(), debug_backtrace() or similar means.
static logException( $e, $catcher=self::CAUGHT_BY_OTHER)
Log an exception to the exception log (if enabled).
static installHandler()
Install handlers with PHP.
static $handledFatalCallback
static getRedactedTrace( $e)
Return a copy of an exception's backtrace as an array.
static getLogId( $e)
Get the ID for this exception.
static getURL()
If the exception occurred in the course of responding to a request, returns the requested URL.
static getLogContext( $e, $catcher=self::CAUGHT_BY_OTHER)
Get a PSR-3 log event context from an Exception.
static handleException( $e)
Exception handler which simulates the appropriate catch() handling:
static output( $e, $mode, $eNew=null)
returning false will NOT prevent logging a wrapping ErrorException $suppressed
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title after the basic globals have been set but before ordinary actions take place or wrap services the preferred way to define a new service is the $wgServiceWiringFiles array $services
returning false will NOT prevent logging $e