mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 23:02:42 +01:00
When stopping on redirect, show a full stack trace
Summary: Ref T4140. Provide more debugging information so we can figure out what's going on with redirect loops. Test Plan: {F83868} Reviewers: chad, btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T4140 Differential Revision: https://secure.phabricator.com/D7620
This commit is contained in:
parent
a518626a85
commit
13275860b1
4 changed files with 162 additions and 123 deletions
|
@ -81,6 +81,7 @@ phutil_register_library_map(array(
|
|||
'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php',
|
||||
'AphrontResponse' => 'aphront/response/AphrontResponse.php',
|
||||
'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php',
|
||||
'AphrontStackTraceView' => 'view/widget/AphrontStackTraceView.php',
|
||||
'AphrontTableView' => 'view/control/AphrontTableView.php',
|
||||
'AphrontTagView' => 'view/AphrontTagView.php',
|
||||
'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php',
|
||||
|
@ -2401,6 +2402,7 @@ phutil_register_library_map(array(
|
|||
'AphrontRequestFailureView' => 'AphrontView',
|
||||
'AphrontRequestTestCase' => 'PhabricatorTestCase',
|
||||
'AphrontSideNavFilterView' => 'AphrontView',
|
||||
'AphrontStackTraceView' => 'AphrontView',
|
||||
'AphrontTableView' => 'AphrontView',
|
||||
'AphrontTagView' => 'AphrontView',
|
||||
'AphrontTokenizerTemplateView' => 'AphrontView',
|
||||
|
|
|
@ -243,7 +243,9 @@ class AphrontDefaultApplicationConfiguration
|
|||
}
|
||||
|
||||
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
|
||||
$trace = $this->renderStackTrace($ex->getTrace(), $user);
|
||||
$trace = id(new AphrontStackTraceView())
|
||||
->setUser($user)
|
||||
->setTrace($ex->getTrace());
|
||||
} else {
|
||||
$trace = null;
|
||||
}
|
||||
|
@ -290,110 +292,4 @@ class AphrontDefaultApplicationConfiguration
|
|||
));
|
||||
}
|
||||
|
||||
private function renderStackTrace($trace, PhabricatorUser $user) {
|
||||
|
||||
$libraries = PhutilBootloader::getInstance()->getAllLibraries();
|
||||
|
||||
// TODO: Make this configurable?
|
||||
$path = 'https://secure.phabricator.com/diffusion/%s/browse/master/src/';
|
||||
|
||||
$callsigns = array(
|
||||
'arcanist' => 'ARC',
|
||||
'phutil' => 'PHU',
|
||||
'phabricator' => 'P',
|
||||
);
|
||||
|
||||
$rows = array();
|
||||
$depth = count($trace);
|
||||
foreach ($trace as $part) {
|
||||
$lib = null;
|
||||
$file = idx($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 ($file) {
|
||||
if (isset($callsigns[$lib])) {
|
||||
$attrs = array('title' => $file);
|
||||
try {
|
||||
$attrs['href'] = $user->loadEditorLink(
|
||||
'/src/'.$relative,
|
||||
$part['line'],
|
||||
$callsigns[$lib]);
|
||||
} catch (Exception $ex) {
|
||||
// The database can be inaccessible.
|
||||
}
|
||||
if (empty($attrs['href'])) {
|
||||
$attrs['href'] = sprintf($path, $callsigns[$lib]).
|
||||
str_replace(DIRECTORY_SEPARATOR, '/', $relative).
|
||||
'$'.$part['line'];
|
||||
$attrs['target'] = '_blank';
|
||||
}
|
||||
$file_name = phutil_tag(
|
||||
'a',
|
||||
$attrs,
|
||||
$relative);
|
||||
} else {
|
||||
$file_name = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'title' => $file,
|
||||
),
|
||||
$relative);
|
||||
}
|
||||
$file_name = hsprintf('%s : %d', $file_name, $part['line']);
|
||||
} else {
|
||||
$file_name = phutil_tag('em', array(), '(Internal)');
|
||||
}
|
||||
|
||||
|
||||
$rows[] = array(
|
||||
$depth--,
|
||||
$lib,
|
||||
$file_name,
|
||||
$where,
|
||||
);
|
||||
}
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'Depth',
|
||||
'Library',
|
||||
'File',
|
||||
'Where',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'n',
|
||||
'',
|
||||
'',
|
||||
'wide',
|
||||
));
|
||||
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array('class' => 'exception-trace'),
|
||||
array(
|
||||
phutil_tag(
|
||||
'div',
|
||||
array('class' => 'exception-trace-header'),
|
||||
pht('Stack Trace')),
|
||||
$table->render(),
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,14 @@
|
|||
class AphrontRedirectResponse extends AphrontResponse {
|
||||
|
||||
private $uri;
|
||||
private $stackWhenCreated;
|
||||
|
||||
public function __construct() {
|
||||
if ($this->shouldStopForDebugging()) {
|
||||
// If we're going to stop, capture the stack so we can print it out.
|
||||
$this->stackWhenCreated = id(new Exception())->getTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public function setURI($uri) {
|
||||
$this->uri = $uri;
|
||||
|
@ -33,31 +41,44 @@ class AphrontRedirectResponse extends AphrontResponse {
|
|||
|
||||
public function buildResponseString() {
|
||||
if ($this->shouldStopForDebugging()) {
|
||||
$user = new PhabricatorUser();
|
||||
|
||||
$view = new PhabricatorStandardPageView();
|
||||
$view->setRequest($this->getRequest());
|
||||
$view->setApplicationName('Debug');
|
||||
$view->setTitle('Stopped on Redirect');
|
||||
|
||||
$error = new AphrontErrorView();
|
||||
$error->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
||||
$error->setTitle('Stopped on Redirect');
|
||||
$dialog = new AphrontDialogView();
|
||||
$dialog->setUser($user);
|
||||
$dialog->setTitle('Stopped on Redirect');
|
||||
|
||||
$error->appendChild(phutil_tag('p', array(), pht(
|
||||
'You were stopped here because %s is set in your configuration.',
|
||||
phutil_tag('tt', array(), 'debug.stop-on-redirect'))));
|
||||
$dialog->appendParagraph(
|
||||
pht(
|
||||
'You were stopped here because %s is set in your configuration.',
|
||||
phutil_tag('tt', array(), 'debug.stop-on-redirect')));
|
||||
|
||||
$link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $this->getURI(),
|
||||
),
|
||||
$this->getURI());
|
||||
$dialog->appendParagraph(
|
||||
pht(
|
||||
'You are being redirected to: %s',
|
||||
phutil_tag('tt', array(), $this->getURI())));
|
||||
|
||||
$error->appendChild(phutil_tag('p', array(), pht(
|
||||
'Continue to: %s',
|
||||
$link)));
|
||||
$dialog->addCancelButton($this->getURI(), pht('Continue'));
|
||||
|
||||
$view->appendChild($error);
|
||||
$dialog->appendChild(phutil_tag('br'));
|
||||
|
||||
$dialog->appendChild(
|
||||
id(new AphrontStackTraceView())
|
||||
->setUser($user)
|
||||
->setTrace($this->stackWhenCreated));
|
||||
|
||||
$dialog->setIsStandalone(true);
|
||||
$dialog->setWidth(AphrontDialogView::WIDTH_FULL);
|
||||
|
||||
$box = id(new PHUIBoxView())
|
||||
->addMargin(PHUI::MARGIN_LARGE)
|
||||
->appendChild($dialog);
|
||||
|
||||
$view->appendChild($box);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
|
120
src/view/widget/AphrontStackTraceView.php
Normal file
120
src/view/widget/AphrontStackTraceView.php
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
final class AphrontStackTraceView extends AphrontView {
|
||||
|
||||
private $trace;
|
||||
|
||||
public function setTrace($trace) {
|
||||
$this->trace = $trace;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$user = $this->getUser();
|
||||
$trace = $this->trace;
|
||||
|
||||
$libraries = PhutilBootloader::getInstance()->getAllLibraries();
|
||||
|
||||
// TODO: Make this configurable?
|
||||
$path = 'https://secure.phabricator.com/diffusion/%s/browse/master/src/';
|
||||
|
||||
$callsigns = array(
|
||||
'arcanist' => 'ARC',
|
||||
'phutil' => 'PHU',
|
||||
'phabricator' => 'P',
|
||||
);
|
||||
|
||||
$rows = array();
|
||||
$depth = count($trace);
|
||||
foreach ($trace as $part) {
|
||||
$lib = null;
|
||||
$file = idx($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 ($file) {
|
||||
if (isset($callsigns[$lib])) {
|
||||
$attrs = array('title' => $file);
|
||||
try {
|
||||
$attrs['href'] = $user->loadEditorLink(
|
||||
'/src/'.$relative,
|
||||
$part['line'],
|
||||
$callsigns[$lib]);
|
||||
} catch (Exception $ex) {
|
||||
// The database can be inaccessible.
|
||||
}
|
||||
if (empty($attrs['href'])) {
|
||||
$attrs['href'] = sprintf($path, $callsigns[$lib]).
|
||||
str_replace(DIRECTORY_SEPARATOR, '/', $relative).
|
||||
'$'.$part['line'];
|
||||
$attrs['target'] = '_blank';
|
||||
}
|
||||
$file_name = phutil_tag(
|
||||
'a',
|
||||
$attrs,
|
||||
$relative);
|
||||
} else {
|
||||
$file_name = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'title' => $file,
|
||||
),
|
||||
$relative);
|
||||
}
|
||||
$file_name = hsprintf('%s : %d', $file_name, $part['line']);
|
||||
} else {
|
||||
$file_name = phutil_tag('em', array(), '(Internal)');
|
||||
}
|
||||
|
||||
|
||||
$rows[] = array(
|
||||
$depth--,
|
||||
$lib,
|
||||
$file_name,
|
||||
$where,
|
||||
);
|
||||
}
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'Depth',
|
||||
'Library',
|
||||
'File',
|
||||
'Where',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'n',
|
||||
'',
|
||||
'',
|
||||
'wide',
|
||||
));
|
||||
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array('class' => 'exception-trace'),
|
||||
array(
|
||||
phutil_tag(
|
||||
'div',
|
||||
array('class' => 'exception-trace-header'),
|
||||
pht('Stack Trace')),
|
||||
$table->render(),
|
||||
));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue