debug: Use native E_USER_DEPRECATED instead of custom channel

* Always use trigger_error for deprecation warnings, not just in development.
  They are still silent from the run-time perspective (not thrown as
  exceptions).

  Previously this code path was only called when $wgDevelopmentWarnings
  is set to true. For most dev environments and for CI, this means
  nothing much changes given that DevelopmentSettings.php set this to true.

* In the code path that handles native PHP warnings, when setting the $file
  and $line attribution that Logstash/Kibana report as "exception.file"
  use the same offset as the one that wfDeprecated() has computed from
  the back trace. This means it no longer (wrongly/uselessly) attributes
  all deprecation warnings to MWDebug.php.

* Trim the message suffix from "Called from <method> in <file>" to
  just "Called from <method>". This reduces noise and makes the message
  more stable over multiple MW branches. The stack trace is still there
  like before.

== Before (only with $wgDevelopmentWarnings) ==

> PHP Deprecated: Use of wfGetScriptUrl was deprecated in MediaWiki 1.35.
> [Called from MediaWiki::__construct in /var/mediawiki/includes/MediaWiki.php at line 67]
>
> Error from line 393 of /var/mediawiki/includes/debug/MWDebug.php
>
> #0 [internal function]: MWExceptionHandler::handleError()
> #1 /var/mediawiki/includes/debug/MWDebug.php(393): trigger_error()
> #2 /var/mediawiki/includes/debug/MWDebug.php(297): MWDebug::sendMessage()
> #3 /var/mediawiki/includes/debug/MWDebug.php(270): MWDebug::sendRawDeprecated()
> #4 /var/mediawiki/includes/GlobalFunctions.php(1032): MWDebug::deprecated()
> #5 /var/mediawiki/includes/GlobalFunctions.php(2548): wfDeprecated()
> #6 /var/mediawiki/includes/MediaWiki.php(67): wfGetScriptUrl(string)
> #7 /var/mediawiki/load.php(50): MediaWiki->__construct()

== After (always) ==

> Use of wfGetScriptUrl was deprecated in MediaWiki 1.35. [Called from MediaWiki::__construct]
>
> Error from line 67 of /var/mediawiki/includes/MediaWiki.php
>
> #0 [internal function]: MWExceptionHandler::handleError()
> #1 /var/mediawiki/includes/debug/MWDebug.php(293): trigger_error()
> #2 /var/mediawiki/includes/debug/MWDebug.php(270): MWDebug::sendRawDeprecated()
> #3 /var/mediawiki/includes/GlobalFunctions.php(1038): MWDebug::deprecated()
> #4 /var/mediawiki/includes/GlobalFunctions.php(2548): wfDeprecated()
> #5 /var/mediawiki/includes/MediaWiki.php(67): wfGetScriptUrl(string)
> #6 /var/mediawiki/load.php(50): MediaWiki->__construct()

Bug: T252923
Change-Id: I1d4a166b6dff8b0e19fce3fab409f4a89e734ee6
This commit is contained in:
Timo Tijhof 2020-05-28 03:14:07 +01:00 committed by Krinkle
parent 7620a28407
commit f2543d442a
2 changed files with 44 additions and 9 deletions

View file

@ -313,9 +313,8 @@ class MWDebug {
*
* @param string $msg The complete message including relevant caller information.
* @param bool $sendToLog If true, the message will be sent to the debug
* toolbar, the debug log, and raised as a warning if indicated by
* $wgDevelopmentWarnings. If false, the message will only be sent to
* the debug toolbar.
* toolbar, the debug log, and raised as a warning to PHP. If false, the message
* will only be sent to the debug toolbar.
* @param string $callerFunc The caller, for display in the debug toolbar's
* caller column.
*/
@ -327,12 +326,7 @@ class MWDebug {
}
if ( $sendToLog ) {
global $wgDevelopmentWarnings; // we could have a more specific $wgDeprecationWarnings setting.
self::sendMessage(
$msg,
'deprecated',
$wgDevelopmentWarnings ? E_USER_DEPRECATED : false
);
trigger_error( $msg, E_USER_DEPRECATED );
}
if ( self::$enabled ) {
@ -414,9 +408,37 @@ class MWDebug {
* @return string
*/
private static function formatCallerDescription( $msg, $caller ) {
// When changing this, update the below parseCallerDescription() method as well.
return $msg . ' [Called from ' . $caller['func'] . ' in ' . $caller['file'] . ']';
}
/**
* Append a caller description to an error message
*
* @internal For use by MWExceptionHandler to override 'exception.file' in error logs.
* @param string $msg Formatted message from formatCallerDescription() and getCallerDescription()
* @return null|array<string,string> Null if unable to recognise all parts, or array with:
* - 'file': string of file path
* - 'line': string of line number
* - 'func': string of function or method name
* - 'message': Re-formatted version of $msg for use with ErrorException,
* so as to not include file/line twice.
*/
public static function parseCallerDescription( $msg ) {
$match = null;
preg_match( '/(.*) \[Called from ([^ ]+) in ([^ ]+) at line (\d+)\]$/', $msg, $match );
if ( $match ) {
return [
'message' => "{$match[1]} [Called from {$match[2]}]",
'func' => $match[2],
'file' => $match[3],
'line' => $match[4],
];
} else {
return null;
}
}
/**
* Send a message to the debug log and optionally also trigger a PHP
* error, depending on the $level argument.

View file

@ -248,9 +248,22 @@ class MWExceptionHandler {
$severity = LogLevel::WARNING;
break;
case E_DEPRECATED:
$prefix = 'PHP Deprecated: ';
$severity = LogLevel::WARNING;
break;
case E_USER_DEPRECATED:
$prefix = 'PHP Deprecated: ';
$severity = LogLevel::WARNING;
$real = MWDebug::parseCallerDescription( $message );
if ( $real ) {
// Used by wfDeprecated(), MWDebug::deprecated()
// Apply caller offset from wfDeprecated() to the native error.
// This makes errors easier to aggregate and find in e.g. Kibana.
$file = $real['file'];
$line = $real['line'];
$message = $real['message'];
$prefix = '';
}
break;
default:
$prefix = 'PHP Unknown error: ';