Add "stop on redirect" and "always profile" debugging options
Summary: Currently, it's hard to debug performance issues on POST pages. Add flags to stop redirects and always collect profiles. Also fix an issue with "all" profiles. This feature is mostly just for profiling DarkConsole itself and is rarely used, I think it's been broken for some time. There's no way to get to it with the UI. NOTE: Some JS workflows don't stop on redirect because they use JS/AJAX redirects. Test Plan: Enabled options, browsed, got stopped on redirects and had profiles generated. Disabled options and verified redirects and profiles work normally. Reviewers: vrana, btrahan Reviewed By: vrana CC: aran Differential Revision: https://secure.phabricator.com/D2990
This commit is contained in:
@@ -103,8 +103,8 @@ final class DarkConsoleXHProfPlugin extends DarkConsolePlugin {
|
||||
|
||||
|
||||
public function willShutdown() {
|
||||
if (isset($_REQUEST['__profile__']) &&
|
||||
$_REQUEST['__profile__'] != 'all') {
|
||||
if (DarkConsoleXHProfPluginAPI::isProfilerRequested() &&
|
||||
(DarkConsoleXHProfPluginAPI::isProfilerRequested() !== 'all')) {
|
||||
$this->xhprofID = DarkConsoleXHProfPluginAPI::stopProfiler();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,18 @@ final class DarkConsoleXHProfPluginAPI {
|
||||
return extension_loaded('xhprof');
|
||||
}
|
||||
|
||||
public static function isProfilerRequested() {
|
||||
if (!empty($_REQUEST['__profile__'])) {
|
||||
return $_REQUEST['__profile__'];
|
||||
}
|
||||
|
||||
if (PhabricatorEnv::getEnvConfig('debug.profile-every-request')) {
|
||||
return PhabricatorEnv::getEnvConfig('debug.profile-every-request');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function includeXHProfLib() {
|
||||
// TODO: this is incredibly stupid, but we may not have Phutil metamodule
|
||||
// stuff loaded yet so we can't just phutil_get_library_root() our way
|
||||
@@ -41,8 +53,9 @@ final class DarkConsoleXHProfPluginAPI {
|
||||
require_once $root.'/externals/xhprof/xhprof_lib.php';
|
||||
}
|
||||
|
||||
|
||||
public static function hookProfiler() {
|
||||
if (empty($_REQUEST['__profile__'])) {
|
||||
if (!self::isProfilerRequested()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -71,17 +84,41 @@ final class DarkConsoleXHProfPluginAPI {
|
||||
$data = serialize($data);
|
||||
$file_class = 'PhabricatorFile';
|
||||
|
||||
// Since these happen on GET we can't do guarded writes.
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
// Since these happen on GET we can't do guarded writes. These also
|
||||
// sometimes happen after we've disposed of the write guard; in this
|
||||
// case we need to disable the whole mechanism.
|
||||
|
||||
$file = call_user_func(
|
||||
array($file_class, 'newFromFileData'),
|
||||
$data,
|
||||
array(
|
||||
'mime-type' => 'application/xhprof',
|
||||
'name' => 'profile.xhprof',
|
||||
));
|
||||
return $file->getPHID();
|
||||
$use_scope = AphrontWriteGuard::isGuardActive();
|
||||
if ($use_scope) {
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
} else {
|
||||
AphrontWriteGuard::allowDangerousUnguardedWrites(true);
|
||||
}
|
||||
|
||||
$caught = null;
|
||||
try {
|
||||
$file = call_user_func(
|
||||
array($file_class, 'newFromFileData'),
|
||||
$data,
|
||||
array(
|
||||
'mime-type' => 'application/xhprof',
|
||||
'name' => 'profile.xhprof',
|
||||
));
|
||||
} catch (Exception $ex) {
|
||||
$caught = $ex;
|
||||
}
|
||||
|
||||
if ($use_scope) {
|
||||
unset($unguarded);
|
||||
} else {
|
||||
AphrontWriteGuard::allowDangerousUnguardedWrites(false);
|
||||
}
|
||||
|
||||
if ($caught) {
|
||||
throw $caught;
|
||||
} else {
|
||||
return $file->getPHID();
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -34,15 +34,47 @@ class AphrontRedirectResponse extends AphrontResponse {
|
||||
return (string)$this->uri;
|
||||
}
|
||||
|
||||
public function shouldStopForDebugging() {
|
||||
return PhabricatorEnv::getEnvConfig('debug.stop-on-redirect');
|
||||
}
|
||||
|
||||
public function getHeaders() {
|
||||
$headers = array(
|
||||
array('Location', $this->uri),
|
||||
);
|
||||
$headers = array();
|
||||
if (!$this->shouldStopForDebugging()) {
|
||||
$headers[] = array('Location', $this->uri);
|
||||
}
|
||||
$headers = array_merge(parent::getHeaders(), $headers);
|
||||
return $headers;
|
||||
}
|
||||
|
||||
public function buildResponseString() {
|
||||
if ($this->shouldStopForDebugging()) {
|
||||
$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');
|
||||
|
||||
$link = phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $this->getURI(),
|
||||
),
|
||||
'Continue to: '.phutil_escape_html($this->getURI()));
|
||||
|
||||
$error->appendChild(
|
||||
'<p>You were stopped here because <tt>debug.stop-on-redirect</tt> '.
|
||||
'is set in your configuration.</p>'.
|
||||
'<p>'.$link.'</p>');
|
||||
|
||||
$view->appendChild($error);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +108,17 @@ final class AphrontWriteGuard {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if there is an active write guard.
|
||||
*
|
||||
* @return bool
|
||||
* @task manage
|
||||
*/
|
||||
public static function isGuardActive() {
|
||||
return (bool)self::$instance;
|
||||
}
|
||||
|
||||
|
||||
/* -( Protecting Writes )-------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user