28use Wikimedia\WrappedString;
29use Wikimedia\WrappedStringList;
48 protected static $log = [];
87 public static function setup() {
114 public static function init() {
115 self::$enabled =
true;
124 self::$enabled =
false;
135 if ( self::$enabled ) {
146 public static function log( $str ) {
147 if ( !self::$enabled ) {
150 if ( !is_string( $str ) ) {
151 $str = print_r( $str,
true );
154 'msg' => htmlspecialchars( $str ),
175 self::$deprecationWarnings = [];
189 public static function warning( $msg, $callerOffset = 1, $level = E_USER_NOTICE, $log =
'auto' ) {
196 if (
$log ===
'debug' ) {
200 $callerDescription = self::getCallerDescription( $callerOffset );
203 self::formatCallerDescription( $msg, $callerDescription ),
222 public static function deprecated( $function, $version =
false,
223 $component =
false, $callerOffset = 2
226 $component = $component ?:
'MediaWiki';
227 $msg =
"Use of $function was deprecated in $component $version.";
229 $msg =
"Use of $function is deprecated.";
231 self::deprecatedMsg( $msg, $version, $component, $callerOffset + 1 );
257 $component =
false, $callerOffset = 2
259 $reflectionMethod =
new ReflectionMethod( $instance, $method );
260 $declaringClass = $reflectionMethod->getDeclaringClass()->getName();
262 if ( $declaringClass === $class ) {
268 $component = $component ?:
'MediaWiki';
269 $msg =
"$declaringClass overrides $method which was deprecated in $component $version.";
270 self::deprecatedMsg( $msg, $version, $component, $callerOffset + 1 );
305 $component =
false, $callerOffset = 2
307 if ( $callerOffset ===
false ) {
311 $callerDescription = self::getCallerDescription( $callerOffset );
312 $callerFunc = $callerDescription[
'func'];
313 $rawMsg = self::formatCallerDescription( $msg, $callerDescription );
319 if ( isset( self::$deprecationWarnings[$msg][$callerFunc] ) ) {
321 } elseif ( isset( self::$deprecationWarnings[$msg] ) ) {
322 if ( self::$enabled ) {
329 self::$deprecationWarnings[$msg][$callerFunc] =
true;
334 $component = $component ?:
'MediaWiki';
336 # Strip -* off the end of $version so that branches can use the
337 # format #.##-branchname to avoid issues if the branch is merged into
338 # a version of MediaWiki later than what it was branched from
339 $comparableVersion = preg_replace(
'/-.*$/',
'', $version );
341 # If the comparableVersion is larger than our release limit then
342 # skip the warning message for the deprecation
349 self::sendRawDeprecated(
369 foreach ( self::$deprecationFilters as $filter => $callback ) {
370 if ( preg_match( $filter, $msg ) ) {
371 if ( is_callable( $callback ) ) {
379 trigger_error( $msg, E_USER_DEPRECATED );
391 string $regex, ?callable $callback =
null
393 if ( !defined(
'MW_PHPUNIT_TEST' ) && !defined(
'MW_PARSER_TEST' ) ) {
394 throw new LogicException( __METHOD__ .
' can only be used in tests' );
396 self::$deprecationFilters[$regex] = $callback;
403 self::$deprecationFilters = [];
413 private static function getCallerDescription( $callerOffset ) {
416 if ( isset( $callers[$callerOffset] ) ) {
417 $callerfile = $callers[$callerOffset];
418 if ( isset( $callerfile[
'file'] ) && isset( $callerfile[
'line'] ) ) {
419 $file = $callerfile[
'file'] .
' at line ' . $callerfile[
'line'];
421 $file =
'(internal function)';
424 $file =
'(unknown location)';
427 if ( isset( $callers[$callerOffset + 1] ) ) {
428 $callerfunc = $callers[$callerOffset + 1];
430 if ( isset( $callerfunc[
'class'] ) ) {
431 $func .= $callerfunc[
'class'] .
'::';
433 if ( isset( $callerfunc[
'function'] ) ) {
434 $func .= $callerfunc[
'function'];
440 return [
'file' => $file,
'func' => $func ];
450 private static function formatCallerDescription( $msg, $caller ) {
452 return $msg .
' [Called from ' . $caller[
'func'] .
' in ' . $caller[
'file'] .
']';
469 preg_match(
'/(.*) \[Called from ([^ ]+) in ([^ ]+) at line (\d+)\]$/', $msg, $match );
472 'message' =>
"{$match[1]} [Called from {$match[2]}]",
490 private static function sendMessage( $msg, $group, $level ) {
491 if ( $level !==
false ) {
492 trigger_error( $msg, $level );
508 public static function debugMsg( $str, $context = [] ) {
514 if ( isset( $context[
'prefix'] ) ) {
515 $prefix = $context[
'prefix'];
516 } elseif ( isset( $context[
'channel'] ) && $context[
'channel'] !==
'wfDebug' ) {
517 $prefix =
"[{$context['channel']}] ";
519 if ( isset( $context[
'seconds_elapsed'] ) && isset( $context[
'memory_used'] ) ) {
520 $prefix .=
"{$context['seconds_elapsed']} {$context['memory_used']} ";
522 $str = LegacyLogger::interpolate( $str, $context );
523 $str = $prefix . $str;
525 $str = rtrim( UtfNormal\Validator::cleanUp( $str ) );
526 self::$debug[] = $str;
527 if ( isset( $context[
'channel'] ) && $context[
'channel'] ===
'error' ) {
528 $message = isset( $context[
'exception'] )
529 ? $context[
'exception']->getMessage()
531 $real = self::parseCallerDescription( $message );
534 $message = $real[
'message'];
535 $caller = $real[
'func'];
537 $trace = isset( $context[
'exception'] ) ? $context[
'exception']->getTrace() : [];
538 if ( ( $trace[5][
'function'] ??
null ) ===
'wfDeprecated' ) {
541 } elseif ( ( $trace[1][
'function'] ??
null ) ===
'trigger_error' ) {
548 $frame = $trace[$offset] ?? $trace[0];
549 $caller = ( isset( $frame[
'class'] ) ? $frame[
'class'] .
'::' :
'' )
550 . $frame[
'function'];
554 'msg' => htmlspecialchars( $message ),
572 public static function query( $sql, $function, $runTime, $dbhost ) {
573 if ( !self::$enabled ) {
581 [\xC0-\xC1] # Invalid UTF-8 Bytes
582 | [\xF5-\xFF] # Invalid UTF-8 Bytes
583 | \xE0[\x80-\x9F] # Overlong encoding of prior code point
584 | \xF0[\x80-\x8F] # Overlong encoding of prior code point
585 | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
586 | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
587 | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
588 | (?<=[\x0-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
589 | (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]
590 | [\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
591 | (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
592 | (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
593 | (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
600 $sql = UtfNormal\Validator::cleanUp( $sql );
603 'sql' =>
"$dbhost: $sql",
604 'function' => $function,
618 $files = get_included_files();
620 foreach ( $files as $file ) {
622 $size = @filesize( $file );
623 if ( $size ===
false ) {
631 'size' => $context->
getLanguage()->formatSize( $size ),
650 if ( self::$enabled ) {
651 self::log(
'MWDebug output complete' );
652 $debugInfo = self::getDebugInfo( $context );
656 $html[] = ResourceLoader::makeInlineScript(
657 ResourceLoader::makeConfigSetScript( [
'debugInfo' => $debugInfo ] )
662 $html[] =
'<!-- Debug output:';
663 foreach ( self::$debug as $line ) {
664 $html[] = htmlspecialchars( $line, ENT_NOQUOTES );
669 return WrappedString::join(
"\n", $html );
685 $html[] = Html::openElement(
'div', [
'id' =>
'mw-html-debug-log' ] );
686 $html[] =
"<hr />\n<strong>Debug data:</strong><ul id=\"mw-debug-html\">";
688 foreach ( self::$debug as $line ) {
689 $display = nl2br( htmlspecialchars( trim( $line ) ) );
691 $html[] =
"<li><code>$display</code></li>";
697 return WrappedString::join(
"\n", $html );
707 if ( !self::$enabled ) {
713 $obContents = ob_get_contents();
715 $obContentArray = explode(
'<br />', $obContents );
716 foreach ( $obContentArray as $obContent ) {
717 if ( trim( $obContent ) ) {
718 self::debugMsg( Sanitizer::stripAllTags( $obContent ) );
723 self::log(
'MWDebug output complete' );
724 $debugInfo = self::getDebugInfo( $context );
726 ApiResult::setIndexedTagName( $debugInfo,
'debuginfo' );
727 ApiResult::setIndexedTagName( $debugInfo[
'log'],
'line' );
728 ApiResult::setIndexedTagName( $debugInfo[
'debugLog'],
'msg' );
729 ApiResult::setIndexedTagName( $debugInfo[
'queries'],
'query' );
730 ApiResult::setIndexedTagName( $debugInfo[
'includes'],
'queries' );
731 $result->
addValue(
null,
'debuginfo', $debugInfo );
741 if ( !self::$enabled ) {
747 $branch = GitInfo::currentBranch();
748 if ( GitInfo::isSHA1( $branch ) ) {
756 'phpEngine' =>
'PHP',
757 'phpVersion' => PHP_VERSION,
758 'gitRevision' => GitInfo::headSHA1(),
759 'gitBranch' => $branch,
760 'gitViewUrl' => GitInfo::headViewUrl(),
761 'time' => $request->getElapsedTime(),
763 'debugLog' => self::$debug,
764 'queries' => self::$query,
766 'method' => $request->getMethod(),
767 'url' => $request->getRequestURL(),
768 'headers' => $request->getAllHeaders(),
769 'params' => $request->getValues(),
771 'memory' => $context->
getLanguage()->formatSize( memory_get_usage() ),
772 'memoryPeak' => $context->
getLanguage()->formatSize( memory_get_peak_usage() ),
773 'includes' => self::getFilesIncluded( $context ),
const MW_VERSION
The running version of MediaWiki.
wfGetCaller( $level=2)
Get the name of the function which called this function wfGetCaller( 1 ) is the function with the wfG...
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
wfDebugBacktrace( $limit=0)
Safety wrapper for debug_backtrace().
if(!defined('MW_SETUP_CALLBACK'))
This class represents the result of the API operations.
addValue( $path, $name, $value, $flags=0)
Add value to the output data at the given path.
static warning( $msg, $callerOffset=1, $level=E_USER_NOTICE, $log='auto')
Adds a warning entry to the log.
static getFilesIncluded(IContextSource $context)
Returns a list of files included, along with their size.
static array $deprecationFilters
Keys are regexes, values are optional callbacks to call if the filter is hit.
static bool $enabled
Is the debugger enabled?
static filterDeprecationForTest(string $regex, ?callable $callback=null)
Deprecation messages matching the supplied regex will be suppressed.
static addModules(OutputPage $out)
Add ResourceLoader modules to the OutputPage object if debugging is enabled.
static parseCallerDescription( $msg)
Append a caller description to an error message.
static appendDebugInfoToApiResult(IContextSource $context, ApiResult $result)
Append the debug info to given ApiResult.
static array $deprecationWarnings
Array of functions that have already been warned, formatted function-caller to prevent a buttload of ...
static clearLog()
Clears internal log array and deprecation tracking.
static sendRawDeprecated( $msg, $sendToLog=true, $callerFunc='')
Send a raw deprecation message to the log and the debug toolbar, without filtering of duplicate messa...
static deinit()
Disable the debugger.
static query( $sql, $function, $runTime, $dbhost)
Begins profiling on a database query.
static getLog()
Returns internal log array.
static array $debug
Debug messages from wfDebug().
static log( $str)
Adds a line to the log.
static detectDeprecatedOverride( $instance, $class, $method, $version=false, $component=false, $callerOffset=2)
Show a warning if $method declared in $class is overridden in $instance.
static getDebugInfo(IContextSource $context)
Returns the HTML to add to the page for the toolbar.
static debugMsg( $str, $context=[])
This method receives messages from LoggerFactory, wfDebugLog, and MWExceptionHandler.
static clearDeprecationFilters()
Clear all deprecation filters.
static array $log
Log lines.
static deprecated( $function, $version=false, $component=false, $callerOffset=2)
Show a warning that $function is deprecated.
static array $query
SQL statements of the database queries.
static getHTMLDebugLog()
Generate debug log in HTML for displaying at the bottom of the main content area.
static init()
Enabled the debugger and load resource module.
static deprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
static getDebugHTML(IContextSource $context)
Returns the HTML to add to the page for the toolbar.
This is one of the Core classes and should be read at least once by any new developers.
addModules( $modules)
Load one or more ResourceLoader modules on this page.
$wgUseCdn
Config variable stub for the UseCdn setting, for use by phpdoc and IDEs.
$wgDeprecationReleaseLimit
Config variable stub for the DeprecationReleaseLimit setting, for use by phpdoc and IDEs.
$wgDebugComments
Config variable stub for the DebugComments setting, for use by phpdoc and IDEs.
$wgShowDebug
Config variable stub for the ShowDebug setting, for use by phpdoc and IDEs.
$wgDebugToolbar
Config variable stub for the DebugToolbar setting, for use by phpdoc and IDEs.
$wgDevelopmentWarnings
Config variable stub for the DevelopmentWarnings setting, for use by phpdoc and IDEs.
$wgUseFileCache
Config variable stub for the UseFileCache setting, for use by phpdoc and IDEs.
Interface for objects which can provide a MediaWiki context on request.