Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
462 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace Contributte\EventDispatcher\Diagnostics; | ||
|
||
use Psr\Log\LoggerInterface; | ||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
|
||
class DebugDispatcher implements EventDispatcherInterface | ||
{ | ||
|
||
private EventDispatcherInterface $original; | ||
|
||
/** @var LoggerInterface[] */ | ||
private array $loggers = []; | ||
|
||
public function __construct(EventDispatcherInterface $original) | ||
{ | ||
$this->original = $original; | ||
} | ||
|
||
public function addLogger(LoggerInterface $logger): void | ||
{ | ||
$this->loggers[] = $logger; | ||
} | ||
|
||
/** | ||
* @param LoggerInterface[] $loggers | ||
*/ | ||
public function setLoggers(array $loggers = []): void | ||
{ | ||
$this->loggers = $loggers; | ||
} | ||
|
||
/** | ||
* @return LoggerInterface[] | ||
*/ | ||
public function getLoggers(): array | ||
{ | ||
return $this->loggers; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function addListener(string $eventName, callable $listener, int $priority = 0): void | ||
{ | ||
$this->original->addListener($eventName, $listener, $priority); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function addSubscriber(EventSubscriberInterface $subscriber): void | ||
{ | ||
$this->original->addSubscriber($subscriber); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function removeListener(string $eventName, callable $listener): void | ||
{ | ||
$this->original->removeListener($eventName, $listener); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function removeSubscriber(EventSubscriberInterface $subscriber): void | ||
{ | ||
$this->original->removeSubscriber($subscriber); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getListeners(?string $eventName = null): array | ||
{ | ||
return $this->original->getListeners($eventName); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getListenerPriority(string $eventName, callable $listener): ?int | ||
{ | ||
return $this->original->getListenerPriority($eventName, $listener); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function hasListeners(?string $eventName = null): bool | ||
{ | ||
return $this->original->hasListeners($eventName); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function dispatch(object $event, ?string $eventName = null): object | ||
{ | ||
$trace = new EventTrace($event, $eventName); | ||
|
||
// Iterate over all loggers | ||
foreach ($this->loggers as $logger) { | ||
$logger->debug(sprintf('EventDispatcher@%s: event started', $trace->name), ['event' => $trace]); | ||
} | ||
|
||
// Start timer | ||
$start = microtime(true); | ||
|
||
// Dispatch event | ||
$return = $this->original->dispatch($event, $eventName); | ||
|
||
// If event was handled, mark it | ||
if ($this->original->hasListeners($trace->name)) { | ||
$trace->handled = true; | ||
} | ||
|
||
// Calculate duration | ||
$trace->duration = microtime(true) - $start; | ||
|
||
foreach ($this->loggers as $logger) { | ||
$logger->debug(sprintf('EventDispatcher@%s: event dispatched', $trace->name), ['event' => $trace]); | ||
} | ||
|
||
return $return; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace Contributte\EventDispatcher\Diagnostics; | ||
|
||
class EventTrace | ||
{ | ||
|
||
public object $event; | ||
|
||
public string $name; | ||
|
||
public bool $handled = false; | ||
|
||
public float $duration = 0.0; | ||
|
||
public function __construct(object $event, ?string $eventName = null) | ||
{ | ||
$this->event = $event; | ||
$this->name = $eventName ?? $event::class; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace Contributte\EventDispatcher\Diagnostics; | ||
|
||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
|
||
class TracyDispatcher implements EventDispatcherInterface | ||
{ | ||
|
||
private EventDispatcherInterface $original; | ||
|
||
/** @var EventTrace[] */ | ||
private array $events = []; | ||
|
||
public function __construct(EventDispatcherInterface $original) | ||
{ | ||
$this->original = $original; | ||
} | ||
|
||
/** | ||
* @return EventTrace[] | ||
*/ | ||
public function getEvents(): array | ||
{ | ||
return $this->events; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function addListener(string $eventName, callable $listener, int $priority = 0): void | ||
{ | ||
$this->original->addListener($eventName, $listener, $priority); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function addSubscriber(EventSubscriberInterface $subscriber): void | ||
{ | ||
$this->original->addSubscriber($subscriber); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function removeListener(string $eventName, callable $listener): void | ||
{ | ||
$this->original->removeListener($eventName, $listener); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function removeSubscriber(EventSubscriberInterface $subscriber): void | ||
{ | ||
$this->original->removeSubscriber($subscriber); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getListeners(?string $eventName = null): array | ||
{ | ||
return $this->original->getListeners($eventName); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getListenerPriority(string $eventName, callable $listener): ?int | ||
{ | ||
return $this->original->getListenerPriority($eventName, $listener); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function hasListeners(?string $eventName = null): bool | ||
{ | ||
return $this->original->hasListeners($eventName); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function dispatch(object $event, ?string $eventName = null): object | ||
{ | ||
$trace = new EventTrace($event, $eventName); | ||
|
||
// Store trace | ||
$this->events[] = $trace; | ||
|
||
// Start timer | ||
$start = microtime(true); | ||
|
||
// Dispatch event | ||
$return = $this->original->dispatch($event, $eventName); | ||
|
||
// If event was handled, mark it | ||
if ($this->original->hasListeners($trace->name)) { | ||
$trace->handled = true; | ||
} | ||
|
||
// Calculate duration | ||
$trace->duration = microtime(true) - $start; | ||
|
||
return $return; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace Contributte\EventDispatcher\Tracy; | ||
|
||
use Contributte\EventDispatcher\Diagnostics\TracyDispatcher; | ||
use Tracy\IBarPanel; | ||
|
||
class EventPanel implements IBarPanel | ||
{ | ||
|
||
private TracyDispatcher $dispatcher; | ||
|
||
public function __construct(TracyDispatcher $dispatcher) | ||
{ | ||
$this->dispatcher = $dispatcher; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getTab(): string | ||
{ | ||
$totalCount = count($this->dispatcher->getEvents()); // @phpcs:ignore | ||
$handledCount = $this->handledCount(); // @phpcs:ignore | ||
$totalTime = $this->countTotalTime(); // @phpcs:ignore | ||
$totalTime = ($totalTime > 0 ? ' / ' . number_format($totalTime * 1000, 1, '.', ' ') . ' ms' : ''); // @phpcs:ignore | ||
|
||
ob_start(); | ||
require __DIR__ . '/templates/tab.phtml'; | ||
|
||
return (string) ob_get_clean(); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getPanel(): string | ||
{ | ||
$handledCount = $this->handledCount(); // @phpcs:ignore | ||
$totalTime = $this->countTotalTime(); // @phpcs:ignore | ||
$events = $this->dispatcher->getEvents(); // @phpcs:ignore | ||
$listeners = $this->dispatcher->getListeners(); | ||
ksort($listeners); | ||
ob_start(); | ||
require __DIR__ . '/templates/panel.phtml'; | ||
|
||
return (string) ob_get_clean(); | ||
} | ||
|
||
private function countTotalTime(): float | ||
{ | ||
$totalTime = 0; | ||
foreach ($this->dispatcher->getEvents() as $event) { | ||
$totalTime += $event->duration; | ||
} | ||
|
||
return $totalTime; | ||
} | ||
|
||
private function handledCount(): int | ||
{ | ||
$handled = 0; | ||
foreach ($this->dispatcher->getEvents() as $event) { | ||
$handled += $event->handled ? 1 : 0; | ||
} | ||
|
||
return $handled; | ||
} | ||
|
||
} |
Oops, something went wrong.