Advanced Debugging Techniques in MediaWiki Development
Why Debugging MediaWiki Needs a Little Extra Muscle
Why Debugging MediaWiki Needs a Little Extra Muscle
When you first spin up a MediaWiki instance the “Hello World” page looks perfect, but as soon as you start adding extensions, custom skins, or heavy template logic the stack can turn into a maze of silent failures. The core itself ships with a basic $wgDebugLogFile and a tiny toolbar, yet seasoned developers quickly discover that those tools alone rarely expose the root cause of a problem. Below is a compact guide to the more advanced tricks that let you see under the hood without drowning in log noise.
1. Turn on Core Debugging Flags – The First Layer
Before you reach for an external profiler, make sure MediaWiki’s built‑in debug switches are set. In LocalSettings.php add:
$wgDebugLogFile = "/var/log/mediawiki/debug.log";
$wgDebugToolbar = true;
$wgShowExceptionDetails = true;
$wgDebugRedirects = true; // avoid silent redirects
These three lines give you:
- Log file – all PHP notices, warnings and explicit
wfDebugLogcalls. - Toolbar – a tiny floating panel with request time, memory usage and a link to the full profile.
- Exception details – stack traces for uncaught exceptions (handy when a hook throws).
Don’t forget to turn off $wgDebugLogFile on production; the file can grow fast.
2. Xdebug + IDE – Remote Breakpoints Made Easy
If you prefer “stop‑and‑inspect” over reading logs, Xdebug is the way to go. Install it on the server, then configure a simple “idekey” that matches your favourite editor:
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_host = 192.168.1.100 ; your host machine
xdebug.client_port = 9003
xdebug.idekey = PHPSTORM
Most IDEs (PhpStorm, VS Code, Eclipse PDT) let you set breakpoints in any PHP file—even inside the core. When a request hits the server the debugger pauses at the first breakpoint, letting you examine $this, function arguments and the current output buffer. A trick many veterans miss is the “path mapping” option; point the IDE’s remote path (e.g. /var/www/mediawiki) to the local clone so the editor can find the source files without manual copying.
2.1 Using phpdbg as an Alternative
When Xdebug overhead is too heavy (it can add 30‑40 ms per request), phpdbg offers a lighter weight REPL. Launch it with:
phpdbg -qrr maintenance/run.php
From there you can set breakpoints with break, step through, and even inspect variables with print $myVar. Though not as pretty as a GUI, phpdbg runs inside the same PHP binary used by the web server, guaranteeing identical behaviour.
3. WikimediaDebug – Profiling in Production
Wikimedia runs a fleet of wikis where you can’t just smash the server with a debugger. The WikimediaDebug suite provides a low‑impact way to capture request‑level data:
- debug=profile – adds timing and SQL query counts to the response headers.
- debug=trace – returns a full back‑trace in the HTML comment block.
- debug=memcache – logs cache hits/misses for each request.
To enable it locally you only need to set:
$wgDebugRedirects = true; // required for the query string to work
Then append ?debug=profile to any URL. The tool respects $wgDebugLogFile so you can pipe the output into your regular log for later analysis.
4. Deep Dive into Query Debugging
Most MediaWiki performance woes stem from inefficient database calls. The core offers a query logger that can be toggled with:
$wgShowSQL = true; // prints each query in the HTML comment
$wgSQLShowStats = true; // appends total query count and time
When working on an extension, wrap your custom queries inside $db->startAtomic blocks; the debug log will then show a clear “BEGIN … COMMIT” envelope. To pinpoint the exact query that hurts you, use the "explain" feature:
$dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select( 'page', '*', [ 'page_namespace' => NS_MAIN ], __METHOD__ );
$dbr->explain( $res );
The result prints a MySQL EXPLAIN plan right into the debug log, letting you see if an index is missing or if the optimizer chose a full table scan.
5. Template Debugging – From Wikicode to PHP
Even though templates live in wikitext, the parser turns them into PHP ASTs. When a template misbehaves, activate the parser debug flag:
$wgParserEnableLegacyMediaSearch = false; // unrelated but often paired
$wgDebugLogFile = "/tmp/parser.log";
$wgDebugLogGroups = [ 'Parser' => true ];
Now each #invoke call writes a trace to /tmp/parser.log. You can also sprinkle {{#debug:}} inside a template to have it emit the current variable state directly into the page (wrapped in HTML comments, of course). It feels odd at first, but seeing the actual parameter array after all the TemplateData parsing is a lifesaver.
6. ResourceLoader & JavaScript Debugging
MediaWiki’s frontend assets are served via ResourceLoader. When a JS module fails, the server returns a 500 with a small JSON payload. To see the exact request that caused it, turn on:
$wgDebugRawPage = true; // disables HTML minification
$wgDebugToolbar = true;
Then open the browser console and look for the load event with the “debug=profile” flag – the response header X-ResourceLoader-Modules lists the modules loaded, and any error key will contain the PHP stack trace. Pair this with the debug=profile URL parameter to get a full timing breakdown of each module, which highlights slow network calls or heavy PHP compilation.
7. Automating Reproduction with Maintenance Scripts
When a bug only appears under a certain set of circumstances (e.g., a specific user group or after a page edit), reproducing it manually can be tedious. MediaWiki ships with a suite of maintenance scripts that can be called from the command line. For instance, to simulate a page view as a particular user you can run:
php maintenance/run.php --user=12345 --title="Main:TestPage"
Combine that with --log to capture the debug output:
php maintenance/run.php --user=12345 --title="Main:TestPage" --log=debug
The script respects all the same debugging flags you set in LocalSettings.php, letting you get a clean log without an actual HTTP request.
8. Profiling with the MediaWiki Profiler
The built‑in profiler is lightweight and can be toggled on‑the‑fly. Add this to your config:
$wgProfiler = [
'class' => 'ProfilerSimple',
'sort' => 'total',
'ignore' => [ 'includes' ],
];
Now every request will append a table to the debug toolbar showing the time spent in each function. For deeper insight you can switch to ProfilerMemory (adds memory usage per call) or ProfilerCompat (compatible with XHProf). The profiler data can be exported as JSON with the debug=profiler URL flag, which is handy for feeding into external visualization tools.
9. Edge Cases – PHP Error Handling & Fatal Errors
Sometimes the fatal “out of memory” or “maximum execution time exceeded” errors never make it to the log because PHP aborts before MediaWiki can write. In those cases you need to configure the PHP error log directly:
log_errors = On
error_log = /var/log/php/error.log
And also raise the limits in .htaccess or php.ini temporarily while debugging:
memory_limit = 512M
max_execution_time = 300
Don’t forget to restore the original values once the issue is resolved – production servers rarely need such generous limits.
10. Putting It All Together – A Debugging Workflow
Here’s a quick checklist that many developers follow when a knot appears:
- Enable
$wgDebugToolbarand reproduce the error in a browser. - If the toolbar shows a high total time, turn on the Profiler and note the hottest functions.
- For PHP‑level bugs, fire up Xdebug in the IDE, set a breakpoint at the suspected hook, and step through.
- If the problem is a SQL query, enable
$wgShowSQLand examine the generatedEXPLAINplan. - When dealing with templates, sprinkle
{{#debug:}}to see variable values, and check/tmp/parser.logfor the parser back‑trace. - For production‑only issues, use
?debug=traceor?debug=profileto capture minimal impact data. - Finally, run the relevant
maintenancescript with--logto create a reproducible log file.
Following this loop often leads to the offending line within minutes, even on a large wiki with dozens of extensions installed.
Closing Thoughts
Debugging MediaWiki isn’t about a single “magic” setting; it’s a toolbox where each item shines in a particular situation. Core flags give you quick hints, Xdebug & IDEs let you pause the world, WikimediaDebug offers low‑impact production insight, and the Profiler narrows down hot spots without external services. Mix and match, keep your $wgDebugLogFile clean, and you’ll spend far less time chasing ghosts in the code.