Adding new debugging toolbar
authorJohn Du Hart <johnduhart@users.mediawiki.org>
Sun, 4 Dec 2011 18:29:57 +0000 (18:29 +0000)
committerJohn Du Hart <johnduhart@users.mediawiki.org>
Sun, 4 Dec 2011 18:29:57 +0000 (18:29 +0000)
Needs a UI cleanup still, but for the most part is working.

RELEASE-NOTES-1.19
includes/Article.php
includes/AutoLoader.php
includes/DefaultSettings.php
includes/GlobalFunctions.php
includes/Setup.php
includes/Skin.php
includes/db/Database.php
resources/Resources.php
resources/mediawiki/mediawiki.debug.css [new file with mode: 0644]
resources/mediawiki/mediawiki.debug.js [new file with mode: 0644]

index 3f79787..cf24f33 100644 (file)
@@ -97,6 +97,7 @@ production.
 * (bug 32666) Special:ActiveUsers now allows a subpage to be used as the
   username (eg. Special:ActiveUsers/Username)
 * New JavaScript variable wgPageContentLanguage
+* Added new debugging toolbar, enabled with $wgDebugToolbar
 
 === Bug fixes in 1.19 ===
 * $wgUploadNavigationUrl should be used for file redlinks if.
index 5633e2a..edd9369 100644 (file)
@@ -374,7 +374,7 @@ class Article extends Page {
         */
        public function view() {
                global $wgUser, $wgOut, $wgRequest, $wgParser;
-               global $wgUseFileCache, $wgUseETag;
+               global $wgUseFileCache, $wgUseETag, $wgDebugToolbar;
 
                wfProfileIn( __METHOD__ );
 
@@ -429,7 +429,7 @@ class Article extends Page {
                }
 
                # Try client and file cache
-               if ( $oldid === 0 && $this->mPage->checkTouched() ) {
+               if ( !$wgDebugToolbar && $oldid === 0 && $this->mPage->checkTouched() ) {
                        if ( $wgUseETag ) {
                                $wgOut->setETag( $parserCache->getETag( $this, $parserOptions ) );
                        }
index 908c8fd..f53d9a1 100644 (file)
@@ -436,6 +436,9 @@ $wgAutoloadLocalClasses = array(
        'ResultWrapper' => 'includes/db/DatabaseUtility.php',
        'SQLiteField' => 'includes/db/DatabaseSqlite.php',
 
+       # includes/debug
+       'MWDebug' => 'includes/debug/Debug.php',
+
        # includes/diff
        '_DiffEngine' => 'includes/diff/DairikiDiff.php',
        '_DiffOp' => 'includes/diff/DairikiDiff.php',
index 83e1e56..b62597f 100644 (file)
@@ -4160,6 +4160,14 @@ $wgParserTestRemote = false;
  */
 $wgWikiID = false;
 
+/**
+ * Display the new debugging toolbar. This also enables profiling on database
+ * queries and other useful output.
+ *
+ * @since 1.19
+ */
+$wgDebugToolbar = false;
+
 /** @} */ # end of profiling, testing and debugging }
 
 /************************************************************************//**
index 26157d6..3167b37 100644 (file)
@@ -835,6 +835,8 @@ function wfDebug( $text, $logonly = false ) {
                        wfErrorLog( $text, $wgDebugLogFile );
                }
        }
+
+       MWDebug::debugMsg( $text );
 }
 
 /**
index afde02f..5c08261 100644 (file)
@@ -328,6 +328,8 @@ if ( $wgCookieSecure === 'detect' ) {
        $wgCookieSecure = ( substr( $wgServer, 0, 6 ) === 'https:' );
 }
 
+MWDebug::init();
+
 if ( !defined( 'MW_COMPILED' ) ) {
        if ( !MWInit::classExists( 'AutoLoader' ) ) {
                require_once( "$IP/includes/AutoLoader.php" );
@@ -392,6 +394,7 @@ if ( $wgCommandLineMode ) {
                }
        }
        wfDebug( "$debug\n" );
+       MWDebug::processRequest( $wgRequest );
 }
 
 wfProfileOut( $fname . '-misc1' );
index d69408f..f3a37f9 100644 (file)
@@ -531,13 +531,15 @@ abstract class Skin extends ContextSource {
        protected function generateDebugHTML() {
                global $wgShowDebug;
 
+               $html = MWDebug::getDebugHTML();
+
                if ( $wgShowDebug ) {
                        $listInternals = $this->formatDebugHTML( $this->getOutput()->mDebugtext );
-                       return "\n<hr />\n<strong>Debug data:</strong><ul id=\"mw-debug-html\">" .
+                       $html .= "\n<hr />\n<strong>Debug data:</strong><ul id=\"mw-debug-html\">" .
                                $listInternals . "</ul>\n";
                }
 
-               return '';
+               return $html;
        }
 
        /**
index 6945ceb..3037769 100644 (file)
@@ -840,9 +840,13 @@ abstract class DatabaseBase implements DatabaseType {
                        throw new MWException( 'Tainted query found' );
                }
 
+               $queryId = MWDebug::query( $sql, $fname, $isMaster );
+
                # Do the query and handle errors
                $ret = $this->doQuery( $commentedSql );
 
+               MWDebug::queryTime( $queryId );
+
                # Try reconnecting if the connection was lost
                if ( false === $ret && $this->wasErrorReissuable() ) {
                        # Transaction is gone, like it or not
index 25afaa4..e0837d3 100644 (file)
@@ -489,6 +489,10 @@ return array(
                'debugScripts' => 'resources/mediawiki/mediawiki.log.js',
                'debugRaw' => false,
        ),
+       'mediawiki.debug' => array(
+               'scripts' => 'resources/mediawiki/mediawiki.debug.js',
+               'styles' => 'resources/mediawiki/mediawiki.debug.css',
+       ),
        'mediawiki.htmlform' => array(
                'scripts' => 'resources/mediawiki/mediawiki.htmlform.js',
        ),
diff --git a/resources/mediawiki/mediawiki.debug.css b/resources/mediawiki/mediawiki.debug.css
new file mode 100644 (file)
index 0000000..b087eca
--- /dev/null
@@ -0,0 +1,111 @@
+.mw-debug {
+       width: 100%;
+       text-align: left;
+       position: fixed;
+       bottom: 0;
+       background-color: #eee;
+       border-top: 1px solid #ccc;
+}
+
+.mw-debug pre {
+       font-family: Monaco, "Consolas", "Lucida Console", "Courier New", monospace;
+       font-size: 11px;
+       padding: 0;
+       margin: 0;
+       background: none;
+       border: none;
+}
+
+.mw-debug ul {
+       margin: 0;
+       list-style: none;
+       box-sizing: border-box;
+}
+
+.mw-debug li {
+       padding: 2px 5px;
+       width: 100%;
+       display: table;
+}
+
+.mw-debug-bit {
+       min-height: 25px;
+       display: inline-block;
+       padding: 5px;
+       border-right: 1px solid #ccc;
+       font-size: 13px;
+}
+
+.mw-debug-pane {
+       max-height: 300px;
+       overflow: scroll;
+       border-top: 2px solid #ccc;
+       display: none;
+       font-size: 11px;
+       background-color: #e1eff2;
+       box-sizing: border-box;
+}
+
+.mw-debug-right {
+       float: right;
+}
+
+#mw-debug-querylist tr {
+
+}
+
+#mw-debug-querylist td {
+       padding: 2px 5px;
+       border-bottom: 1px solid #ccc;
+}
+
+.mw-debug-query-time {
+       color: #808080;
+}
+
+#mw-debug-pane-request {
+       padding: 20px;
+}
+
+#mw-debug-pane-request table {
+       width: 100%;
+       margin: 10px 0 30px;
+}
+
+#mw-debug-pane-request tr,
+#mw-debug-pane-request th,
+#mw-debug-pane-request td,
+#mw-debug-pane-request table {
+       border: 1px solid #D0DBB3;
+       border-collapse: collapse;
+       margin: 0;
+}
+
+#mw-debug-pane-request th,
+#mw-debug-pane-request td {
+       font-size: 12px;
+       padding: 8px 10px;
+}
+
+#mw-debug-pane-request th {
+       background-color: #F1F7E2;
+       font-weight: bold;
+}
+
+#mw-debug-pane-request td {
+       background-color: white;
+}
+
+#mw-debug-pane-querylist table {
+       border-spacing: 0;
+}
+
+#mw-debug-pane-includes li,
+#mw-debug-pane-querylist tr td {
+       background-color: #ccc;
+}
+
+#mw-debug-pane-includes li:nth-child(odd),
+#mw-debug-pane-querylist tr:nth-child(odd) td {
+       background-color: #ddd;
+}
diff --git a/resources/mediawiki/mediawiki.debug.js b/resources/mediawiki/mediawiki.debug.js
new file mode 100644 (file)
index 0000000..12755e6
--- /dev/null
@@ -0,0 +1,208 @@
+/**
+ * Javascript for the new debug toolbar, enabled with $wgDebugToolbar
+ *
+ * @author John Du Hart
+ * @since 1.19
+ */
+
+( function( $ ) {
+
+       var debug = mw.Debug = {
+               /**
+                * Toolbar container element
+                *
+                * @var {jQuery}
+                */
+               $container: null,
+
+               /**
+                * Array containing data for the debug toolbar
+                *
+                * @var {Array}
+                */
+               data: {},
+
+               /**
+                * Initializes the debugging pane
+                *
+                * @param {Array} data
+                */
+               init: function( data ) {
+                       this.data = data;
+                       this.buildHtml();
+
+                       // Insert the container into the DOM
+                       $( 'body' ).append( this.$container );
+
+                       $( '.mw-debug-panelink' ).click( this.switchPane );
+               },
+
+               /**
+                * Switches between panes
+                *
+                * @todo Store cookie for last pane open
+                * @context {Element}
+                * @param {jQuery.Event} e
+                */
+               switchPane: function( e ) {
+                       var currentPaneId = debug.$container.data( 'currentPane' ),
+                               requestedPaneId = $(this).parent().attr( 'id' ).substr( 9 ),
+                               $currentPane = $( '#mw-debug-pane-' + currentPaneId ),
+                               $requestedPane = $( '#mw-debug-pane-' + requestedPaneId );
+                       e.preventDefault();
+
+                       // Hide the current pane
+                       if ( requestedPaneId === currentPaneId ) {
+                               $currentPane.slideUp();
+                               debug.$container.data( 'currentPane', null );
+                               return;
+                       }
+
+                       debug.$container.data( 'currentPane', requestedPaneId );
+
+                       if ( currentPaneId === undefined || currentPaneId === null ) {
+                               $requestedPane.slideDown();
+                       } else {
+                               $currentPane.hide();
+                               $requestedPane.show();
+                       }
+               },
+
+               /**
+                * Constructs the HTML for the debugging toolbar
+                */
+               buildHtml: function() {
+                       this.$container = $( '<div></div>' )
+                               .attr({
+                                       id: 'mw-debug-container',
+                                       class: 'mw-debug'
+                               });
+
+                       var html = '';
+
+                       html += '<div class="mw-debug-bit" id="mw-debug-mwversion">'
+                               + '<a href="//www.mediawiki.org/">MediaWiki</a>: '
+                               + this.data.mwVersion + '</div>';
+
+                       html += '<div class="mw-debug-bit" id="mw-debug-phpversion">'
+                               + '<a href="//www.php.net/">PHP</a>: '
+                               + this.data.phpVersion + '</div>';
+
+                       html += '<div class="mw-debug-bit" id="mw-debug-time">'
+                               + 'Time: ' + this.data.time.toFixed( 5 ) + 's</div>';
+                       html += '<div class="mw-debug-bit" id="mw-debug-memory">'
+                               + 'Memory: ' + this.data.memory + ' (<span title="Peak usage">'
+                               + this.data.memoryPeak + '</span>)</div>';
+
+                       var queryLink = '<a href="#" class="mw-debug-panelink" id="mw-debug-query-link">Queries: '
+                               + this.data.queries.length + '</a>';
+                       html += '<div class="mw-debug-bit" id="mw-debug-querylist">'
+                               + queryLink + '</div>';
+
+                       var debugLink = '<a href="#" class="mw-debug-panelink" id="mw-debug-debuglog-link">Debug Log ('
+                               + this.data.debugLog.length + ' lines)</a>';
+                       html += '<div class="mw-debug-bit" id="mw-debug-debuglog">'
+                               + debugLink + '</div>';
+
+                       var requestLink = '<a href="#" class="mw-debug-panelink" id="mw-debug-request-link">Request</a>';
+                       html += '<div class="mw-debug-bit" id="mw-debug-request">'
+                               + requestLink + '</div>';
+
+                       var filesLink = '<a href="#" class="mw-debug-panelink" id="mw-debug-files-includes">'
+                               + this.data.includes.length + ' Files Included</a>';
+                       html += '<div class="mw-debug-bit" id="mw-debug-includes">'
+                               + filesLink + '</div>';
+
+                       html += '<div class="mw-debug-pane" id="mw-debug-pane-querylist">'
+                               + this.buildQueryTable() + '</div>';
+                       html += '<div class="mw-debug-pane" id="mw-debug-pane-debuglog">'
+                               + this.buildDebugLogTable() + '</div>';
+                       html += '<div class="mw-debug-pane" id="mw-debug-pane-request">'
+                               + this.buildRequestPane() + '</div>';
+                       html += '<div class="mw-debug-pane" id="mw-debug-pane-includes">'
+                               + this.buildIncludesPane() + '</div>';
+
+                       this.$container.html( html );
+               },
+
+               /**
+                * Query list pane
+                */
+               buildQueryTable: function() {
+                       var html = '<table id="mw-debug-querylist">';
+
+                       for ( var i = 0, length = this.data.queries.length; i < length; i++ ) {
+                               var query = this.data.queries[i];
+
+                               html += '<tr><td>' + ( i + 1 ) + '</td>';
+
+                               html += '<td>' + query.sql + '</td>';
+                html += '<td><span class="mw-debug-query-time">(' + query.time.toFixed( 4 ) + 'ms)</span> ' + query.function + '</td>';
+
+                html += '</tr>';
+                       }
+
+                       html += '</table>';
+
+                       return html;
+               },
+
+               /**
+                * Legacy debug log pane
+                */
+               buildDebugLogTable: function() {
+                       var html = '<ul>';
+
+                       for ( var i = 0, length = this.data.debugLog.length; i < length; i++ ) {
+                               var line = this.data.debugLog[i];
+                               html += '<li>' + line.replace( /\n/g, "<br />\n" ) +  '</li>';
+                       }
+
+                       return html + '</ul>';
+               },
+
+               /**
+                * Request information pane
+                */
+               buildRequestPane: function() {
+                       var buildTable = function( title, data ) {
+                               var t = '<h2>' + title + '</h2>'
+                                       + '<table> <tr> <th>Key</th> <th>Value</th> </tr>';
+
+                               for ( var key in data ) {
+                                       if ( !data.hasOwnProperty( key ) ) {
+                                               continue;
+                                       }
+                                       var value = data[key];
+
+                                       t += '<tr><th>' + key + '</th><td>' + value + '</td></tr>';
+                               }
+
+                               t += '</table>';
+                               return t;
+                       };
+
+                       var html = this.data.request.method + ' ' + this.data.request.url;
+                       html += buildTable( 'Headers', this.data.request.headers );
+                       html += buildTable( 'Parameters', this.data.request.params );
+
+                       return html;
+               },
+
+               /**
+                * Included files pane
+                */
+               buildIncludesPane: function() {
+                       var html = '<ul>';
+
+                       for ( var i = 0, l = this.data.includes.length; i < l; i++ ) {
+                               var file = this.data.includes[i];
+                               html += '<li><span class="mw-debug-right">' + file.size + '</span> ' + file.name + '</li>';
+                       }
+
+                       html += '</ul>';
+                       return html;
+               }
+       };
+
+} )( jQuery );
\ No newline at end of file