mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-03 19:31:02 +01:00
Improve Daemon console UI
Summary: Makes various fixes to the Daemon console UI: - Removes timeline, timeline cursors, and timeline-related controllers. This abstraction is all but dead and just waiting on an eventual cleanup effort with Facebook (see T2003). There's no need to inspect or debug it anymore. - Instead of showing the 15 most recently launched non-exited daemons, show all the running daemons. With the old rule, "dead" daemons tended to build up at the bottom of the list -- e.g., secure.phabricator.com shows the 7 active daemons, then 8 dead daemons from as far back as Aug 2012. Showing running daemons is far more useful. - Simplify the two "Running Daemons" and "All Daemons" subviews into one "All Daemons" subview. The main console now has "running daemons", effectively. - Create a "Recently completed tasks" view, which shows how many tasks of each task class have completed in the last 15 minutes and how long they took on average. Understanding how quickly tasks are completing is one of the most common uses of the daemon console, and it's currently almost useless for that. Now that we archive tasks, we can show this information in an easily digestable form. - Partially modernize all of the remaining views. Test Plan: Looked at daemon console. Reviewers: btrahan, chad, vrana Reviewed By: btrahan CC: aran Maniphest Tasks: T2372, T2003 Differential Revision: https://secure.phabricator.com/D4573
This commit is contained in:
parent
e948073107
commit
beaf0bb898
8 changed files with 68 additions and 183 deletions
|
@ -757,8 +757,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDaemonLogListView' => 'applications/daemon/view/PhabricatorDaemonLogListView.php',
|
||||
'PhabricatorDaemonLogViewController' => 'applications/daemon/controller/PhabricatorDaemonLogViewController.php',
|
||||
'PhabricatorDaemonReference' => 'infrastructure/daemon/control/PhabricatorDaemonReference.php',
|
||||
'PhabricatorDaemonTimelineConsoleController' => 'applications/daemon/controller/PhabricatorDaemonTimelineConsoleController.php',
|
||||
'PhabricatorDaemonTimelineEventController' => 'applications/daemon/controller/PhabricatorDaemonTimelineEventController.php',
|
||||
'PhabricatorDefaultFileStorageEngineSelector' => 'applications/files/engineselector/PhabricatorDefaultFileStorageEngineSelector.php',
|
||||
'PhabricatorDefaultSearchEngineSelector' => 'applications/search/selector/PhabricatorDefaultSearchEngineSelector.php',
|
||||
'PhabricatorDeveloperConfigOptions' => 'applications/config/option/PhabricatorDeveloperConfigOptions.php',
|
||||
|
@ -2159,8 +2157,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDaemonLogListController' => 'PhabricatorDaemonController',
|
||||
'PhabricatorDaemonLogListView' => 'AphrontView',
|
||||
'PhabricatorDaemonLogViewController' => 'PhabricatorDaemonController',
|
||||
'PhabricatorDaemonTimelineConsoleController' => 'PhabricatorDaemonController',
|
||||
'PhabricatorDaemonTimelineEventController' => 'PhabricatorDaemonController',
|
||||
'PhabricatorDefaultFileStorageEngineSelector' => 'PhabricatorFileStorageEngineSelector',
|
||||
'PhabricatorDefaultSearchEngineSelector' => 'PhabricatorSearchEngineSelector',
|
||||
'PhabricatorDeveloperConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
|
|
|
@ -29,18 +29,15 @@ final class PhabricatorApplicationDaemons extends PhabricatorApplication {
|
|||
public function getRoutes() {
|
||||
return array(
|
||||
'/daemon/' => array(
|
||||
'' => 'PhabricatorDaemonConsoleController',
|
||||
'task/(?P<id>[1-9]\d*)/' => 'PhabricatorWorkerTaskDetailController',
|
||||
'task/(?P<id>[1-9]\d*)/(?P<action>[^/]+)/'
|
||||
=> 'PhabricatorWorkerTaskUpdateController',
|
||||
'log/' => array(
|
||||
'(?P<running>running/)?' => 'PhabricatorDaemonLogListController',
|
||||
'' => 'PhabricatorDaemonLogListController',
|
||||
'combined/' => 'PhabricatorDaemonCombinedLogController',
|
||||
'(?P<id>[1-9]\d*)/' => 'PhabricatorDaemonLogViewController',
|
||||
),
|
||||
'timeline/' => 'PhabricatorDaemonTimelineConsoleController',
|
||||
'timeline/(?P<id>[1-9]\d*)/'
|
||||
=> 'PhabricatorDaemonTimelineEventController',
|
||||
'' => 'PhabricatorDaemonConsoleController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ final class PhabricatorDaemonCombinedLogController
|
|||
$log_panel->setHeader('Combined Daemon Logs');
|
||||
$log_panel->appendChild($event_view);
|
||||
$log_panel->appendChild($pager);
|
||||
$log_panel->setNoBackground();
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->selectFilter('log/combined');
|
||||
|
|
|
@ -4,19 +4,71 @@ final class PhabricatorDaemonConsoleController
|
|||
extends PhabricatorDaemonController {
|
||||
|
||||
public function processRequest() {
|
||||
$logs = id(new PhabricatorDaemonLog())->loadAllWhere(
|
||||
'`status` != %s ORDER BY id DESC LIMIT 15', 'exit');
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$completed = id(new PhabricatorWorkerArchiveTask())->loadAllWhere(
|
||||
'dateModified > %d',
|
||||
time() - (60 * 15));
|
||||
|
||||
$completed_info = array();
|
||||
foreach ($completed as $completed_task) {
|
||||
$class = $completed_task->getTaskClass();
|
||||
if (empty($completed_info[$class])) {
|
||||
$completed_info[$class] = array(
|
||||
'n' => 0,
|
||||
'duration' => 0,
|
||||
);
|
||||
}
|
||||
$completed_info[$class]['n']++;
|
||||
$duration = $completed_task->getDuration();
|
||||
$completed_info[$class]['duration'] += $duration;
|
||||
}
|
||||
|
||||
$completed_info = isort($completed_info, 'n');
|
||||
|
||||
$rows = array();
|
||||
foreach ($completed_info as $class => $info) {
|
||||
$rows[] = array(
|
||||
phutil_escape_html($class),
|
||||
number_format($info['n']),
|
||||
number_format((int)($info['duration'] / $info['n'])).' us',
|
||||
);
|
||||
}
|
||||
|
||||
$completed_table = new AphrontTableView($rows);
|
||||
$completed_table->setNoDataString(
|
||||
pht('No tasks have completed in the last 15 minutes.'));
|
||||
$completed_table->setHeaders(
|
||||
array(
|
||||
pht('Class'),
|
||||
pht('Count'),
|
||||
pht('Avg'),
|
||||
));
|
||||
$completed_table->setColumnClasses(
|
||||
array(
|
||||
'wide',
|
||||
'n',
|
||||
'n',
|
||||
));
|
||||
|
||||
$completed_panel = new AphrontPanelView();
|
||||
$completed_panel->setHeader(pht('Recently Completed Tasks (15m)'));
|
||||
$completed_panel->appendChild($completed_table);
|
||||
$completed_panel->setNoBackground();
|
||||
|
||||
$logs = id(new PhabricatorDaemonLog())->loadAllWhere(
|
||||
'`status` = %s ORDER BY id DESC',
|
||||
'run');
|
||||
|
||||
$daemon_table = new PhabricatorDaemonLogListView();
|
||||
$daemon_table->setUser($user);
|
||||
$daemon_table->setDaemonLogs($logs);
|
||||
|
||||
$daemon_panel = new AphrontPanelView();
|
||||
$daemon_panel->setHeader('Recently Launched Daemons');
|
||||
$daemon_panel->setHeader('Active Daemons');
|
||||
$daemon_panel->appendChild($daemon_table);
|
||||
$daemon_panel->setNoBackground();
|
||||
|
||||
$tasks = id(new PhabricatorWorkerActiveTask())->loadAllWhere(
|
||||
'leaseOwner IS NOT NULL');
|
||||
|
@ -63,6 +115,7 @@ final class PhabricatorDaemonConsoleController
|
|||
$leased_panel = new AphrontPanelView();
|
||||
$leased_panel->setHeader('Leased Tasks');
|
||||
$leased_panel->appendChild($leased_table);
|
||||
$leased_panel->setNoBackground();
|
||||
|
||||
$task_table = new PhabricatorWorkerActiveTask();
|
||||
$queued = queryfx_all(
|
||||
|
@ -95,41 +148,14 @@ final class PhabricatorDaemonConsoleController
|
|||
$queued_panel = new AphrontPanelView();
|
||||
$queued_panel->setHeader('Queued Tasks');
|
||||
$queued_panel->appendChild($queued_table);
|
||||
|
||||
$cursors = id(new PhabricatorTimelineCursor())
|
||||
->loadAll();
|
||||
|
||||
$rows = array();
|
||||
foreach ($cursors as $cursor) {
|
||||
$rows[] = array(
|
||||
phutil_escape_html($cursor->getName()),
|
||||
number_format($cursor->getPosition()),
|
||||
);
|
||||
}
|
||||
|
||||
$cursor_table = new AphrontTableView($rows);
|
||||
$cursor_table->setHeaders(
|
||||
array(
|
||||
'Name',
|
||||
'Position',
|
||||
));
|
||||
$cursor_table->setColumnClasses(
|
||||
array(
|
||||
'wide',
|
||||
'n',
|
||||
));
|
||||
$cursor_table->setNoDataString('No timeline cursors exist.');
|
||||
|
||||
$cursor_panel = new AphrontPanelView();
|
||||
$cursor_panel->setHeader('Timeline Cursors');
|
||||
$cursor_panel->appendChild($cursor_table);
|
||||
$queued_panel->setNoBackground();
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->selectFilter('');
|
||||
$nav->selectFilter('/');
|
||||
$nav->appendChild(
|
||||
array(
|
||||
$completed_panel,
|
||||
$daemon_panel,
|
||||
$cursor_panel,
|
||||
$queued_panel,
|
||||
$leased_panel,
|
||||
));
|
||||
|
|
|
@ -7,14 +7,10 @@ abstract class PhabricatorDaemonController extends PhabricatorController {
|
|||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||
|
||||
$nav->addLabel('Daemons');
|
||||
$nav->addFilter('', 'Console', $this->getApplicationURI());
|
||||
$nav->addFilter('log/running', 'Running Daemons');
|
||||
$nav->addFilter('/', 'Console');
|
||||
$nav->addFilter('log', 'All Daemons');
|
||||
$nav->addFilter('log/combined', 'Combined Log');
|
||||
|
||||
$nav->addLabel('Event Timeline');
|
||||
$nav->addFilter('timeline', 'Timeline');
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,6 @@
|
|||
final class PhabricatorDaemonLogListController
|
||||
extends PhabricatorDaemonController {
|
||||
|
||||
private $running;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->running = !empty($data['running']);
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
|
||||
|
@ -16,9 +10,6 @@ final class PhabricatorDaemonLogListController
|
|||
$pager->setOffset($request->getInt('page'));
|
||||
|
||||
$clause = '1 = 1';
|
||||
if ($this->running) {
|
||||
$clause = "`status` != 'exit'";
|
||||
}
|
||||
|
||||
$logs = id(new PhabricatorDaemonLog())->loadAllWhere(
|
||||
'%Q ORDER BY id DESC LIMIT %d, %d',
|
||||
|
@ -34,18 +25,19 @@ final class PhabricatorDaemonLogListController
|
|||
$daemon_table->setDaemonLogs($logs);
|
||||
|
||||
$daemon_panel = new AphrontPanelView();
|
||||
$daemon_panel->setHeader('Launched Daemons');
|
||||
$daemon_panel->setHeader('All Daemons');
|
||||
$daemon_panel->appendChild($daemon_table);
|
||||
$daemon_panel->appendChild($pager);
|
||||
$daemon_panel->setNoBackground();
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->selectFilter($this->running ? 'log/running' : 'log');
|
||||
$nav->selectFilter('log');
|
||||
$nav->appendChild($daemon_panel);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$nav,
|
||||
array(
|
||||
'title' => $this->running ? 'Running Daemons' : 'All Daemons',
|
||||
'title' => 'All Daemons',
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorDaemonTimelineConsoleController
|
||||
extends PhabricatorDaemonController {
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$timeline_table = new PhabricatorTimelineEvent('NULL');
|
||||
|
||||
$events = queryfx_all(
|
||||
$timeline_table->establishConnection('r'),
|
||||
'SELECT id, type FROM %T ORDER BY id DESC LIMIT 100',
|
||||
$timeline_table->getTableName());
|
||||
|
||||
$rows = array();
|
||||
foreach ($events as $event) {
|
||||
$rows[] = array(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/daemon/timeline/'.$event['id'].'/',
|
||||
),
|
||||
$event['id']),
|
||||
phutil_escape_html($event['type']),
|
||||
);
|
||||
}
|
||||
|
||||
$event_table = new AphrontTableView($rows);
|
||||
$event_table->setHeaders(
|
||||
array(
|
||||
'ID',
|
||||
'Type',
|
||||
));
|
||||
$event_table->setColumnClasses(
|
||||
array(
|
||||
null,
|
||||
'wide',
|
||||
));
|
||||
|
||||
$event_panel = new AphrontPanelView();
|
||||
$event_panel->setHeader('Timeline Events');
|
||||
$event_panel->appendChild($event_table);
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->selectFilter('timeline');
|
||||
$nav->appendChild($event_panel);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$nav,
|
||||
array(
|
||||
'title' => 'Timeline',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorDaemonTimelineEventController
|
||||
extends PhabricatorDaemonController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$event = id(new PhabricatorTimelineEvent('NULL'))->load($this->id);
|
||||
if (!$event) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
if ($event->getDataID()) {
|
||||
$data = id(new PhabricatorTimelineEventData())->load(
|
||||
$event->getDataID());
|
||||
}
|
||||
|
||||
if ($data) {
|
||||
$data = json_encode($data->getEventData());
|
||||
} else {
|
||||
$data = 'null';
|
||||
}
|
||||
|
||||
$form = new AphrontFormView();
|
||||
$form
|
||||
->setUser($user)
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel('ID')
|
||||
->setValue($event->getID()))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel('Type')
|
||||
->setValue($event->getType()))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setDisabled(true)
|
||||
->setLabel('Data')
|
||||
->setValue($data))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->addCancelButton('/daemon/timeline/'));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Event');
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
||||
$panel->appendChild($form);
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->selectFilter('timeline');
|
||||
$nav->appendChild($panel);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$nav,
|
||||
array(
|
||||
'title' => 'Timeline Event',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue