Skip to content

Commit eddae18

Browse files
committed
MDL-79974 core: Add Whoops when debugging
Whoops will only be used under the following conditions: - Not an AJAX request - Not a CLI usage - debugdisplay is set - composer dependencies are installed - Whoops is available - The configuration setting is enabled
1 parent e4d1369 commit eddae18

File tree

5 files changed

+167
-2
lines changed

5 files changed

+167
-2
lines changed

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"symfony/http-client": "^4.4 || ^5.0 || ^6.0",
1515
"symfony/mime": "^4.4 || ^5.0 || ^6.0",
1616
"behat/behat": "3.13.*",
17-
"oleg-andreyev/mink-phpwebdriver": "1.2.*"
17+
"oleg-andreyev/mink-phpwebdriver": "1.2.*",
18+
"filp/whoops": "^2.15"
1819
},
1920
"autoload-dev": {
2021
"psr-0": {

composer.lock

+72-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config-dist.php

+17
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,23 @@
780780
// $CFG->debug = (E_ALL | E_STRICT); // === DEBUG_DEVELOPER - NOT FOR PRODUCTION SERVERS!
781781
// $CFG->debugdisplay = 1; // NOT FOR PRODUCTION SERVERS!
782782
//
783+
// Display exceptions using the 'pretty' Whoops! utility.
784+
// This is only used when the following conditions are met:
785+
// - Composer dependencies are installed
786+
// - $CFG->debug and $CFG->debugdisplay are set
787+
// - the request is not a CLI, or AJAX request
788+
//
789+
// To further control this, the debug_developer_use_pretty_exceptions setting can be set to false.
790+
// $CFG->debug_developer_use_pretty_exceptions = true;
791+
//
792+
// The Whoops! UI can also provide a link to open files in your preferred editor.
793+
// You can set your preferred editor by setting:
794+
// $CFG->debug_developer_editor = 'vscode';
795+
//
796+
// See https://github.com/filp/whoops/blob/master/docs/Open%20Files%20In%20An%20Editor.md for more information on
797+
// supported editors.
798+
// If your editor is not listed you can provide a callback as documented.
799+
//
783800
// You can specify a comma separated list of user ids that that always see
784801
// debug messages, this overrides the debug flag in $CFG->debug and $CFG->debugdisplay
785802
// for these users only.

lib/setup.php

+6
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,12 @@
706706
}
707707
$CFG->debugdeveloper = (($CFG->debug & DEBUG_DEVELOPER) === DEBUG_DEVELOPER);
708708

709+
// Set a default value for whether to show exceptions in a pretty format.
710+
if (!property_exists($CFG, 'debug_developer_use_pretty_exceptions')) {
711+
$CFG->debug_developer_use_pretty_exceptions = true;
712+
713+
}
714+
709715
// Find out if PHP configured to display warnings,
710716
// this is a security problem because some moodle scripts may
711717
// disclose sensitive information.

lib/setuplib.php

+70
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,67 @@ function __construct($debuginfo = NULL) {
343343
}
344344
}
345345

346+
/**
347+
* Get the Whoops! handler.
348+
*
349+
* @return \Whoops\Run|null
350+
*/
351+
function get_whoops(): ?\Whoops\Run {
352+
global $CFG;
353+
354+
if (CLI_SCRIPT || AJAX_SCRIPT) {
355+
return null;
356+
}
357+
358+
if (defined('PHPUNIT_TEST') && PHPUNIT_TEST) {
359+
return null;
360+
}
361+
362+
if (defined('BEHAT_TEST') && BEHAT_TEST) {
363+
return null;
364+
}
365+
366+
if (!$CFG->debugdisplay) {
367+
return null;
368+
}
369+
370+
if (!$CFG->debug_developer_use_pretty_exceptions) {
371+
return null;
372+
}
373+
374+
$composerautoload = "{$CFG->dirroot}/vendor/autoload.php";
375+
if (file_exists($composerautoload)) {
376+
require_once($composerautoload);
377+
}
378+
379+
if (!class_exists(\Whoops\Run::class)) {
380+
return null;
381+
}
382+
383+
// We have Whoops available, use it.
384+
$whoops = new \Whoops\Run();
385+
386+
// Append a custom handler to add some more information to the frames.
387+
$whoops->appendHandler(function ($exception, $inspector, $run) {
388+
// Moodle exceptions often have a link to the Moodle docs pages for them.
389+
// Add that to the first frame in the stack.
390+
$info = get_exception_info($exception);
391+
if ($info->moreinfourl) {
392+
$collection = $inspector->getFrames();
393+
$collection[0]->addComment("{$info->moreinfourl}", 'More info');
394+
}
395+
});
396+
397+
// Add the Pretty page handler. It's the bee's knees.
398+
$handler = new \Whoops\Handler\PrettyPageHandler();
399+
if (isset($CFG->debug_developer_editor)) {
400+
$handler->setEditor($CFG->debug_developer_editor ?: null);
401+
}
402+
$whoops->appendHandler($handler);
403+
404+
return $whoops;
405+
}
406+
346407
/**
347408
* Default exception handler.
348409
*
@@ -366,6 +427,11 @@ function default_exception_handler($ex) {
366427
// should be either empty or the length of the error page.
367428
@header_remove('Content-Length');
368429

430+
if ($whoops = get_whoops()) {
431+
// If whoops is available we will use it. The get_whoops() function checks whether all conditions are met.
432+
$whoops->handleException($ex);
433+
}
434+
369435
if (is_early_init($info->backtrace)) {
370436
echo bootstrap_renderer::early_error($info->message, $info->moreinfourl, $info->link, $info->backtrace, $info->debuginfo, $info->errorcode);
371437
} else {
@@ -422,6 +488,10 @@ function default_exception_handler($ex) {
422488
* @return bool false means use default error handler
423489
*/
424490
function default_error_handler($errno, $errstr, $errfile, $errline) {
491+
if ($whoops = get_whoops()) {
492+
// If whoops is available we will use it. The get_whoops() function checks whether all conditions are met.
493+
$whoops->handleError($errno, $errstr, $errfile, $errline);
494+
}
425495
if ($errno == 4096) {
426496
//fatal catchable error
427497
throw new coding_exception('PHP catchable fatal error', $errstr);

0 commit comments

Comments
 (0)