Skip to content

Commit

Permalink
MDL-79974 core: Add Whoops when debugging
Browse files Browse the repository at this point in the history
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
  • Loading branch information
andrewnicols committed Nov 5, 2023
1 parent e4d1369 commit eddae18
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 2 deletions.
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -14,7 +14,8 @@
"symfony/http-client": "^4.4 || ^5.0 || ^6.0",
"symfony/mime": "^4.4 || ^5.0 || ^6.0",
"behat/behat": "3.13.*",
"oleg-andreyev/mink-phpwebdriver": "1.2.*"
"oleg-andreyev/mink-phpwebdriver": "1.2.*",
"filp/whoops": "^2.15"
},
"autoload-dev": {
"psr-0": {
Expand Down
73 changes: 72 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions config-dist.php
Expand Up @@ -780,6 +780,23 @@
// $CFG->debug = (E_ALL | E_STRICT); // === DEBUG_DEVELOPER - NOT FOR PRODUCTION SERVERS!
// $CFG->debugdisplay = 1; // NOT FOR PRODUCTION SERVERS!
//
// Display exceptions using the 'pretty' Whoops! utility.
// This is only used when the following conditions are met:
// - Composer dependencies are installed
// - $CFG->debug and $CFG->debugdisplay are set
// - the request is not a CLI, or AJAX request
//
// To further control this, the debug_developer_use_pretty_exceptions setting can be set to false.
// $CFG->debug_developer_use_pretty_exceptions = true;
//
// The Whoops! UI can also provide a link to open files in your preferred editor.
// You can set your preferred editor by setting:
// $CFG->debug_developer_editor = 'vscode';
//
// See https://github.com/filp/whoops/blob/master/docs/Open%20Files%20In%20An%20Editor.md for more information on
// supported editors.
// If your editor is not listed you can provide a callback as documented.
//
// You can specify a comma separated list of user ids that that always see
// debug messages, this overrides the debug flag in $CFG->debug and $CFG->debugdisplay
// for these users only.
Expand Down
6 changes: 6 additions & 0 deletions lib/setup.php
Expand Up @@ -706,6 +706,12 @@
}
$CFG->debugdeveloper = (($CFG->debug & DEBUG_DEVELOPER) === DEBUG_DEVELOPER);

// Set a default value for whether to show exceptions in a pretty format.
if (!property_exists($CFG, 'debug_developer_use_pretty_exceptions')) {
$CFG->debug_developer_use_pretty_exceptions = true;

}

// Find out if PHP configured to display warnings,
// this is a security problem because some moodle scripts may
// disclose sensitive information.
Expand Down
70 changes: 70 additions & 0 deletions lib/setuplib.php
Expand Up @@ -343,6 +343,67 @@ function __construct($debuginfo = NULL) {
}
}

/**
* Get the Whoops! handler.
*
* @return \Whoops\Run|null
*/
function get_whoops(): ?\Whoops\Run {
global $CFG;

if (CLI_SCRIPT || AJAX_SCRIPT) {
return null;
}

if (defined('PHPUNIT_TEST') && PHPUNIT_TEST) {
return null;
}

if (defined('BEHAT_TEST') && BEHAT_TEST) {
return null;
}

if (!$CFG->debugdisplay) {
return null;
}

if (!$CFG->debug_developer_use_pretty_exceptions) {
return null;
}

$composerautoload = "{$CFG->dirroot}/vendor/autoload.php";
if (file_exists($composerautoload)) {
require_once($composerautoload);
}

if (!class_exists(\Whoops\Run::class)) {
return null;
}

// We have Whoops available, use it.
$whoops = new \Whoops\Run();

// Append a custom handler to add some more information to the frames.
$whoops->appendHandler(function ($exception, $inspector, $run) {
// Moodle exceptions often have a link to the Moodle docs pages for them.
// Add that to the first frame in the stack.
$info = get_exception_info($exception);
if ($info->moreinfourl) {
$collection = $inspector->getFrames();
$collection[0]->addComment("{$info->moreinfourl}", 'More info');
}
});

// Add the Pretty page handler. It's the bee's knees.
$handler = new \Whoops\Handler\PrettyPageHandler();
if (isset($CFG->debug_developer_editor)) {
$handler->setEditor($CFG->debug_developer_editor ?: null);
}
$whoops->appendHandler($handler);

return $whoops;
}

/**
* Default exception handler.
*
Expand All @@ -366,6 +427,11 @@ function default_exception_handler($ex) {
// should be either empty or the length of the error page.
@header_remove('Content-Length');

if ($whoops = get_whoops()) {
// If whoops is available we will use it. The get_whoops() function checks whether all conditions are met.
$whoops->handleException($ex);
}

if (is_early_init($info->backtrace)) {
echo bootstrap_renderer::early_error($info->message, $info->moreinfourl, $info->link, $info->backtrace, $info->debuginfo, $info->errorcode);
} else {
Expand Down Expand Up @@ -422,6 +488,10 @@ function default_exception_handler($ex) {
* @return bool false means use default error handler
*/
function default_error_handler($errno, $errstr, $errfile, $errline) {
if ($whoops = get_whoops()) {
// If whoops is available we will use it. The get_whoops() function checks whether all conditions are met.
$whoops->handleError($errno, $errstr, $errfile, $errline);
}
if ($errno == 4096) {
//fatal catchable error
throw new coding_exception('PHP catchable fatal error', $errstr);
Expand Down

0 comments on commit eddae18

Please sign in to comment.