mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 00:32:42 +01:00
Improve unhandled exception dialogs
Summary: Make the unhandled exception dialogs slightly more useful: - Make them easier to read. - Link to files from Phabricator libraries. - Don't show traces by default. - Show traces in development mode. - Rename button from "Cancel" to "Close" and only show it for Ajax. Test Plan: Rigged DirectoryHomeController to throw, loaded home page. Changed stack trace setting in config. Clicked some files in the trace. Reviewed By: aran Reviewers: aran, jungejason, tuomaspelkonen, codeblock CC: aran, epriestley Differential Revision: 823
This commit is contained in:
parent
b291ad9807
commit
966778c2bd
5 changed files with 132 additions and 10 deletions
|
@ -360,6 +360,10 @@ return array(
|
||||||
// behalf, silencing the warning.
|
// behalf, silencing the warning.
|
||||||
'phabricator.timezone' => null,
|
'phabricator.timezone' => null,
|
||||||
|
|
||||||
|
// When unhandled exceptions occur, stack traces are hidden by default.
|
||||||
|
// You can enable traces for development to make it easier to debug problems.
|
||||||
|
'phabricator.show-stack-traces' => false,
|
||||||
|
|
||||||
|
|
||||||
// -- Files ----------------------------------------------------------------- //
|
// -- Files ----------------------------------------------------------------- //
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
|
||||||
'darkconsole.enabled' => true,
|
'darkconsole.enabled' => true,
|
||||||
'celerity.force-disk-reads' => true,
|
'celerity.force-disk-reads' => true,
|
||||||
|
'phabricator.show-stack-traces' => true,
|
||||||
|
|
||||||
) + phabricator_read_config_file('default');
|
) + phabricator_read_config_file('default');
|
||||||
|
|
|
@ -389,14 +389,16 @@ class AphrontDefaultApplicationConfiguration
|
||||||
$class = phutil_escape_html(get_class($ex));
|
$class = phutil_escape_html(get_class($ex));
|
||||||
$message = phutil_escape_html($ex->getMessage());
|
$message = phutil_escape_html($ex->getMessage());
|
||||||
|
|
||||||
$string = (string)$ex;
|
if (PhabricatorEnv::getEnvConfig('phabricator.show-stack-traces')) {
|
||||||
$string = phutil_escape_html($string);
|
$trace = $this->renderStackTrace($ex->getTrace());
|
||||||
$string = str_replace("\n", '<br />', $string);
|
} else {
|
||||||
|
$trace = null;
|
||||||
|
}
|
||||||
|
|
||||||
$content =
|
$content =
|
||||||
'<div class="aphront-unhandled-exception">'.
|
'<div class="aphront-unhandled-exception">'.
|
||||||
'<h1>Unhandled Exception "'.$class.'": '.$message.'</h1>'.
|
'<div class="exception-message">'.$message.'</div>'.
|
||||||
'<code>'.$string.'</code>'.
|
$trace.
|
||||||
'</div>';
|
'</div>';
|
||||||
|
|
||||||
$user = $this->getRequest()->getUser();
|
$user = $this->getRequest()->getUser();
|
||||||
|
@ -407,11 +409,14 @@ class AphrontDefaultApplicationConfiguration
|
||||||
|
|
||||||
$dialog = new AphrontDialogView();
|
$dialog = new AphrontDialogView();
|
||||||
$dialog
|
$dialog
|
||||||
->setTitle('Exception!')
|
->setTitle('Unhandled Exception ("'.$class.'")')
|
||||||
->setClass('aphront-exception-dialog')
|
->setClass('aphront-exception-dialog')
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->appendChild($content)
|
->appendChild($content);
|
||||||
->addCancelButton('/');
|
|
||||||
|
if ($this->getRequest()->isAjax()) {
|
||||||
|
$dialog->addCancelButton('/', 'Close');
|
||||||
|
}
|
||||||
|
|
||||||
$response = new AphrontDialogResponse();
|
$response = new AphrontDialogResponse();
|
||||||
$response->setDialog($dialog);
|
$response->setDialog($dialog);
|
||||||
|
@ -480,4 +485,93 @@ class AphrontDefaultApplicationConfiguration
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function renderStackTrace($trace) {
|
||||||
|
|
||||||
|
$libraries = PhutilBootloader::getInstance()->getAllLibraries();
|
||||||
|
|
||||||
|
// TODO: Make this configurable?
|
||||||
|
$host = 'https://secure.phabricator.com';
|
||||||
|
|
||||||
|
$browse = array(
|
||||||
|
'arcanist' =>
|
||||||
|
$host.'/diffusion/ARC/browse/origin:master/src/',
|
||||||
|
'phutil' =>
|
||||||
|
$host.'/diffusion/PHU/browse/origin:master/src/',
|
||||||
|
'phabricator' =>
|
||||||
|
$host.'/diffusion/P/browse/origin:master/src/',
|
||||||
|
);
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
$depth = count($trace);
|
||||||
|
foreach ($trace as $part) {
|
||||||
|
$lib = null;
|
||||||
|
$file = $part['file'];
|
||||||
|
$relative = $file;
|
||||||
|
foreach ($libraries as $library) {
|
||||||
|
$root = phutil_get_library_root($library);
|
||||||
|
if (Filesystem::isDescendant($file, $root)) {
|
||||||
|
$lib = $library;
|
||||||
|
$relative = Filesystem::readablePath($file, $root);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$where = '';
|
||||||
|
if (isset($part['class'])) {
|
||||||
|
$where .= $part['class'].'::';
|
||||||
|
}
|
||||||
|
if (isset($part['function'])) {
|
||||||
|
$where .= $part['function'].'()';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($browse[$lib])) {
|
||||||
|
$file_name = phutil_render_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => $browse[$lib].$relative.'$'.$part['line'],
|
||||||
|
'title' => $file,
|
||||||
|
'target' => '_blank',
|
||||||
|
),
|
||||||
|
phutil_escape_html($relative));
|
||||||
|
} else {
|
||||||
|
$file_name = phutil_render_tag(
|
||||||
|
'span',
|
||||||
|
array(
|
||||||
|
'title' => $file,
|
||||||
|
),
|
||||||
|
phutil_escape_html($relative));
|
||||||
|
}
|
||||||
|
$file_name = $file_name.' : '.(int)$part['line'];
|
||||||
|
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
$depth--,
|
||||||
|
phutil_escape_html($lib),
|
||||||
|
$file_name,
|
||||||
|
phutil_escape_html($where),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$table = new AphrontTableView($rows);
|
||||||
|
$table->setHeaders(
|
||||||
|
array(
|
||||||
|
'Depth',
|
||||||
|
'Library',
|
||||||
|
'File',
|
||||||
|
'Where',
|
||||||
|
));
|
||||||
|
$table->setColumnClasses(
|
||||||
|
array(
|
||||||
|
'n',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'wide',
|
||||||
|
));
|
||||||
|
|
||||||
|
return
|
||||||
|
'<div class="exception-trace">'.
|
||||||
|
'<div class="exception-trace-header">Stack Trace</div>'.
|
||||||
|
$table->render().
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,16 @@ phutil_require_module('phabricator', 'aphront/response/webpage');
|
||||||
phutil_require_module('phabricator', 'applications/base/controller/404');
|
phutil_require_module('phabricator', 'applications/base/controller/404');
|
||||||
phutil_require_module('phabricator', 'applications/base/controller/redirect');
|
phutil_require_module('phabricator', 'applications/base/controller/redirect');
|
||||||
phutil_require_module('phabricator', 'applications/people/storage/user');
|
phutil_require_module('phabricator', 'applications/people/storage/user');
|
||||||
|
phutil_require_module('phabricator', 'infrastructure/env');
|
||||||
|
phutil_require_module('phabricator', 'view/control/table');
|
||||||
phutil_require_module('phabricator', 'view/dialog');
|
phutil_require_module('phabricator', 'view/dialog');
|
||||||
phutil_require_module('phabricator', 'view/page/failure');
|
phutil_require_module('phabricator', 'view/page/failure');
|
||||||
phutil_require_module('phabricator', 'view/page/standard');
|
phutil_require_module('phabricator', 'view/page/standard');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'error');
|
phutil_require_module('phutil', 'error');
|
||||||
|
phutil_require_module('phutil', 'filesystem');
|
||||||
phutil_require_module('phutil', 'markup');
|
phutil_require_module('phutil', 'markup');
|
||||||
|
phutil_require_module('phutil', 'moduleutils');
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,3 +69,22 @@
|
||||||
.aphront-exception-dialog .aphront-dialog-head {
|
.aphront-exception-dialog .aphront-dialog-head {
|
||||||
background: #aa0000;
|
background: #aa0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.aphront-exception-dialog .exception-message {
|
||||||
|
font-size: 14px;
|
||||||
|
background: #efefef;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aphront-exception-dialog .exception-trace {
|
||||||
|
margin-top: 1em;
|
||||||
|
padding: .5em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aphront-exception-dialog .exception-trace-header {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #666666;
|
||||||
|
border-bottom: 1px solid #aaaaaa;
|
||||||
|
padding-bottom: .5em;
|
||||||
|
margin-bottom: .5em;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue