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
This commit is contained in:
Andrew Nicols
2023-11-05 21:23:18 +08:00
parent e4d1369475
commit eddae1808b
5 changed files with 167 additions and 2 deletions
+2 -1
View File
@@ -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": {
Generated
+72 -1
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "3a0d2ff60a75e1c5c42b16fd989bbe24",
"content-hash": "f298c4dad62459604043ad01fb821207",
"packages": [],
"packages-dev": [
{
@@ -405,6 +405,77 @@
],
"time": "2022-12-30T00:15:36+00:00"
},
{
"name": "filp/whoops",
"version": "2.15.4",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/a139776fa3f5985a50b509f2a02ff0f709d2a546",
"reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546",
"shasum": ""
},
"require": {
"php": "^5.5.9 || ^7.0 || ^8.0",
"psr/log": "^1.0.1 || ^2.0 || ^3.0"
},
"require-dev": {
"mockery/mockery": "^0.9 || ^1.0",
"phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3",
"symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0"
},
"suggest": {
"symfony/var-dumper": "Pretty print complex values better with var-dumper available",
"whoops/soap": "Formats errors as SOAP responses"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"Whoops\\": "src/Whoops/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Filipe Dobreira",
"homepage": "https://github.com/filp",
"role": "Developer"
}
],
"description": "php error handling for cool kids",
"homepage": "https://filp.github.io/whoops/",
"keywords": [
"error",
"exception",
"handling",
"library",
"throwable",
"whoops"
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.15.4"
},
"funding": [
{
"url": "https://github.com/denis-sokolov",
"type": "github"
}
],
"time": "2023-11-03T12:00:00+00:00"
},
{
"name": "friends-of-behat/mink-extension",
"version": "v2.7.2",
+17
View File
@@ -780,6 +780,23 @@ $CFG->admin = 'admin';
// $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.
+6
View File
@@ -706,6 +706,12 @@ if (isset($CFG->debug)) {
}
$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.
+70
View File
@@ -343,6 +343,67 @@ class file_serving_exception extends moodle_exception {
}
}
/**
* 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.
*
@@ -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 {
@@ -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);