mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 08:52:39 +01:00
Add an "Event" plugin to DarkConsole for event inspection
Summary: Shows events which a page dispatched, plus all the registered listeners. Test Plan: Pretty basic for now, but works OK: https://secure.phabricator.com/file/view/PHID-FILE-49fcd23081ce55cf9369/ (I also made it dispatch some dummy events to verify they show up.) Reviewers: aran Reviewed By: aran CC: aran Differential Revision: 973
This commit is contained in:
parent
fc5cc180ab
commit
1b8562467c
12 changed files with 250 additions and 0 deletions
|
@ -140,6 +140,8 @@ phutil_register_library_map(array(
|
|||
'DarkConsoleCore' => 'aphront/console/core',
|
||||
'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog',
|
||||
'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/api',
|
||||
'DarkConsoleEventPlugin' => 'aphront/console/plugin/event',
|
||||
'DarkConsoleEventPluginAPI' => 'aphront/console/plugin/event/api',
|
||||
'DarkConsolePlugin' => 'aphront/console/plugin/base',
|
||||
'DarkConsoleRequestPlugin' => 'aphront/console/plugin/request',
|
||||
'DarkConsoleServicesPlugin' => 'aphront/console/plugin/services',
|
||||
|
@ -851,6 +853,8 @@ phutil_register_library_map(array(
|
|||
'DarkConsoleConfigPlugin' => 'DarkConsolePlugin',
|
||||
'DarkConsoleController' => 'PhabricatorController',
|
||||
'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
|
||||
'DarkConsoleEventPlugin' => 'DarkConsolePlugin',
|
||||
'DarkConsoleEventPluginAPI' => 'PhabricatorEventListener',
|
||||
'DarkConsoleRequestPlugin' => 'DarkConsolePlugin',
|
||||
'DarkConsoleServicesPlugin' => 'DarkConsolePlugin',
|
||||
'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin',
|
||||
|
|
|
@ -23,6 +23,7 @@ final class DarkConsoleCore {
|
|||
|
||||
const PLUGIN_ERRORLOG = 'ErrorLog';
|
||||
const PLUGIN_SERVICES = 'Services';
|
||||
const PLUGIN_EVENT = 'Event';
|
||||
const PLUGIN_XHPROF = 'XHProf';
|
||||
const PLUGIN_REQUEST = 'Request';
|
||||
const PLUGIN_CONFIG = 'Config';
|
||||
|
@ -32,6 +33,7 @@ final class DarkConsoleCore {
|
|||
self::PLUGIN_ERRORLOG,
|
||||
self::PLUGIN_REQUEST,
|
||||
self::PLUGIN_SERVICES,
|
||||
self::PLUGIN_EVENT,
|
||||
self::PLUGIN_XHPROF,
|
||||
self::PLUGIN_CONFIG,
|
||||
);
|
||||
|
|
117
src/aphront/console/plugin/event/DarkConsoleEventPlugin.php
Normal file
117
src/aphront/console/plugin/event/DarkConsoleEventPlugin.php
Normal file
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @group console
|
||||
*/
|
||||
class DarkConsoleEventPlugin extends DarkConsolePlugin {
|
||||
|
||||
public function getName() {
|
||||
return 'Events';
|
||||
}
|
||||
|
||||
public function getDescription() {
|
||||
return 'Information about Phabricator events and event listeners.';
|
||||
}
|
||||
|
||||
public function generateData() {
|
||||
|
||||
$listeners = PhabricatorEventEngine::getInstance()->getAllListeners();
|
||||
foreach ($listeners as $key => $listener) {
|
||||
$listeners[$key] = array(
|
||||
'id' => $listener->getListenerID(),
|
||||
'class' => get_class($listener),
|
||||
);
|
||||
}
|
||||
|
||||
$events = DarkConsoleEventPluginAPI::getEvents();
|
||||
foreach ($events as $key => $event) {
|
||||
$events[$key] = array(
|
||||
'type' => $event->getType(),
|
||||
'stopped' => $event->isStopped(),
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'listeners' => $listeners,
|
||||
'events' => $events,
|
||||
);
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$data = $this->getData();
|
||||
|
||||
$out = array();
|
||||
|
||||
$out[] =
|
||||
'<div class="dark-console-panel-header">'.
|
||||
'<h1>Registered Event Listeners</h1>'.
|
||||
'</div>';
|
||||
|
||||
$rows = array();
|
||||
foreach ($data['listeners'] as $listener) {
|
||||
$rows[] = array(
|
||||
phutil_escape_html($listener['id']),
|
||||
phutil_escape_html($listener['class']),
|
||||
);
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'Internal ID',
|
||||
'Listener Class',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'wide',
|
||||
));
|
||||
|
||||
$out[] = $table->render();
|
||||
|
||||
$out[] =
|
||||
'<div class="dark-console-panel-header">'.
|
||||
'<h1>Event Log</h1>'.
|
||||
'</div>';
|
||||
|
||||
$rows = array();
|
||||
foreach ($data['events'] as $event) {
|
||||
$rows[] = array(
|
||||
phutil_escape_html($event['type']),
|
||||
$event['stopped'] ? 'STOPPED' : null,
|
||||
);
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'wide',
|
||||
));
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'Event Type',
|
||||
'Stopped',
|
||||
));
|
||||
|
||||
$out[] = $table->render();
|
||||
|
||||
|
||||
return implode("\n", $out);
|
||||
}
|
||||
}
|
17
src/aphront/console/plugin/event/__init__.php
Normal file
17
src/aphront/console/plugin/event/__init__.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/console/plugin/base');
|
||||
phutil_require_module('phabricator', 'aphront/console/plugin/event/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/events/engine');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
|
||||
|
||||
phutil_require_source('DarkConsoleEventPlugin.php');
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @group console
|
||||
*/
|
||||
class DarkConsoleEventPluginAPI extends PhabricatorEventListener {
|
||||
|
||||
private static $events = array();
|
||||
private static $discardMode = false;
|
||||
|
||||
public static function enableDiscardMode() {
|
||||
self::$discardMode = true;
|
||||
}
|
||||
|
||||
public static function getEvents() {
|
||||
return self::$events;
|
||||
}
|
||||
|
||||
public function register() {
|
||||
$this->listen(PhabricatorEventType::TYPE_ALL);
|
||||
}
|
||||
|
||||
public function handleEvent(PhabricatorEvent $event) {
|
||||
if (self::$discardMode) {
|
||||
return;
|
||||
}
|
||||
self::$events[] = $event;
|
||||
}
|
||||
|
||||
}
|
||||
|
13
src/aphront/console/plugin/event/api/__init__.php
Normal file
13
src/aphront/console/plugin/event/api/__init__.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'infrastructure/events/constant/type');
|
||||
phutil_require_module('phabricator', 'infrastructure/events/listener');
|
||||
|
||||
|
||||
phutil_require_source('DarkConsoleEventPluginAPI.php');
|
|
@ -25,6 +25,9 @@ abstract class PhabricatorDaemon extends PhutilDaemon {
|
|||
// that daemons do not require unbounded amounts of memory.
|
||||
DarkConsoleErrorLogPluginAPI::enableDiscardMode();
|
||||
|
||||
// Also accumulates potentially unlimited amounts of data.
|
||||
DarkConsoleEventPluginAPI::enableDiscardMode();
|
||||
|
||||
$phabricator = phutil_get_library_root('phabricator');
|
||||
$root = dirname($phabricator);
|
||||
require_once $root.'/scripts/__init_env__.php';
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/console/plugin/errorlog/api');
|
||||
phutil_require_module('phabricator', 'aphront/console/plugin/event/api');
|
||||
phutil_require_module('phabricator', 'aphront/writeguard');
|
||||
|
||||
phutil_require_module('phutil', 'daemon/base');
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
final class PhabricatorEventType extends PhabricatorEventConstants {
|
||||
|
||||
const TYPE_ALL = '*';
|
||||
const TYPE_MANIPHEST_WILLEDITTASK = 'maniphest.willEditTask';
|
||||
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ class PhabricatorEventEngine {
|
|||
public static function initialize() {
|
||||
self::$instance = new PhabricatorEventEngine();
|
||||
|
||||
// Register the DarkConosole event logger.
|
||||
id(new DarkConsoleEventPluginAPI())->register();
|
||||
|
||||
// Instantiate and register custom event listeners so they can react to
|
||||
// events.
|
||||
$listeners = PhabricatorEnv::getEnvConfig('events.listeners');
|
||||
|
@ -51,10 +54,30 @@ class PhabricatorEventEngine {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the objects currently listening to any event.
|
||||
*/
|
||||
public function getAllListeners() {
|
||||
$listeners = array_mergev($this->listeners);
|
||||
$listeners = mpull($listeners, null, 'getListenerID');
|
||||
return $listeners;
|
||||
}
|
||||
|
||||
public static function dispatchEvent(PhabricatorEvent $event) {
|
||||
$instance = self::getInstance();
|
||||
|
||||
$listeners = idx($instance->listeners, $event->getType(), array());
|
||||
$global_listeners = idx(
|
||||
$instance->listeners,
|
||||
PhabricatorEventType::TYPE_ALL,
|
||||
array());
|
||||
|
||||
// Merge and deduplicate listeners (we want to send the event to each
|
||||
// listener only once, even if it satisfies multiple criteria for the
|
||||
// event).
|
||||
$listeners = array_merge($listeners, $global_listeners);
|
||||
$listeners = mpull($listeners, null, 'getListenerID');
|
||||
|
||||
foreach ($listeners as $listener) {
|
||||
if ($event->isStopped()) {
|
||||
// Do this first so if someone tries to dispatch a stopped event it
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/console/plugin/event/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
phutil_require_module('phabricator', 'infrastructure/events/constant/type');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
abstract class PhabricatorEventListener {
|
||||
|
||||
private $listenerID;
|
||||
private static $nextListenerID = 1;
|
||||
|
||||
final public function __construct() {
|
||||
// <empty>
|
||||
}
|
||||
|
@ -30,4 +33,21 @@ abstract class PhabricatorEventListener {
|
|||
$engine->addListener($this, $type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a scalar ID unique to this listener. This is used to deduplicate
|
||||
* listeners which match events on multiple rules, so they are invoked only
|
||||
* once.
|
||||
*
|
||||
* @return int A scalar unique to this object instance.
|
||||
*/
|
||||
final public function getListenerID() {
|
||||
if (!$this->listenerID) {
|
||||
$this->listenerID = self::$nextListenerID;
|
||||
self::$nextListenerID++;
|
||||
}
|
||||
return $this->listenerID;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue