Skip to content

Commit

Permalink
feat: Add RedisCommandExecutedListener (#833)
Browse files Browse the repository at this point in the history
* feat: Add RedisCommandExecutedListener

* fix: 更新事件处理逻辑以支持多种事件类型

* fix: 修复 CronEventListener 中的默认输出逻辑

* fix: 优化 RedisCommandExecutedListener 中的事件启用逻辑

---------

Co-authored-by: Deeka Wong <[email protected]>
  • Loading branch information
huangdijia and huangdijia authored Feb 7, 2025
1 parent c861049 commit 3e9c2ed
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 16 deletions.
4 changes: 3 additions & 1 deletion src/telescope/src/Aspect/RedisAspect.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use function Hyperf\Tappable\tap;

/**
* @deprecated since v3.1, will remove in v3.2
* @property string $poolName
* @property PackerInterface $packer
*/
Expand All @@ -49,7 +50,8 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint)
$startTime = microtime(true);
return tap($proceedingJoinPoint->process(), function ($result) use ($proceedingJoinPoint, $startTime) {
if (
! $this->telescopeConfig->isEnable('redis')
class_exists('Hyperf\Redis\Event\CommandExecuted')
|| ! $this->telescopeConfig->isEnable('redis')
|| ! TelescopeContext::getBatchId()
) {
return;
Expand Down
3 changes: 2 additions & 1 deletion src/telescope/src/ConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ public function __invoke(): array
Contract\PrunableRepository::class => fn ($container) => $container->get(Contract\EntriesRepository::class),
],
'listeners' => [
Listener\CronEventListener::class,
Listener\CommandListener::class,
Listener\CronEventListener::class,
Listener\DbQueryListener::class,
Listener\ExceptionHandlerListener::class,
Listener\FetchRecordingOnBootListener::class,
Listener\RedisCommandExecutedListener::class,
Listener\RegisterRoutesListener::class => -1,
],
'publish' => [
Expand Down
7 changes: 5 additions & 2 deletions src/telescope/src/Listener/CommandListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@ public function listen(): array
}

/**
* @param AfterExecute $event
* @param AfterExecute|object $event
*/
public function process(object $event): void
{
if (! $this->telescopeConfig->isEnable('command')) {
if (
! $event instanceof AfterExecute
|| ! $this->telescopeConfig->isEnable('command')
) {
return;
}

Expand Down
6 changes: 4 additions & 2 deletions src/telescope/src/Listener/CronEventListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ public function listen(): array
*/
public function process(object $event): void
{
if (! $this->telescopeConfig->isEnable('schedule')) {
if (
! ($event instanceof Event\AfterExecute || $event instanceof Event\FailToExecute)
|| ! $this->telescopeConfig->isEnable('schedule')
) {
return;
}

Expand All @@ -47,7 +50,6 @@ public function process(object $event): void
$output = match (true) {
$event instanceof Event\AfterExecute => 'success',
$event instanceof Event\FailToExecute => '[fail]' . (string) $event->getThrowable(),
default => '',
};

Telescope::recordSchedule(IncomingEntry::make([
Expand Down
5 changes: 3 additions & 2 deletions src/telescope/src/Listener/DbQueryListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ public function listen(): array
}

/**
* @param QueryExecuted $event
* @param object|QueryExecuted $event
*/
public function process(object $event): void
{
if (
! $this->telescopeConfig->isEnable('db')
! $event instanceof QueryExecuted
|| ! $this->telescopeConfig->isEnable('db')
|| ! TelescopeContext::getBatchId()
) {
return;
Expand Down
20 changes: 12 additions & 8 deletions src/telescope/src/Listener/ExceptionHandlerListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\HttpServer\Event;
use Hyperf\Stringable\Str;
use Throwable;

class ExceptionHandlerListener implements ListenerInterface
{
Expand All @@ -35,12 +36,13 @@ public function listen(): array
}

/**
* @param Event\RequestTerminated $event
* @param Event\RequestTerminated|object $event
*/
public function process(object $event): void
{
if (
! $this->telescopeConfig->isEnable('exception')
! $event instanceof Event\RequestTerminated
|| ! $this->telescopeConfig->isEnable('exception')
|| ! TelescopeContext::getBatchId()
) {
return;
Expand All @@ -50,9 +52,9 @@ public function process(object $event): void
return;
}

$trace = (new Collection($exception->getTrace()))->map(function ($item) {
return Arr::only($item, ['file', 'line']);
})->toArray();
$trace = (new Collection($exception->getTrace()))
->map(fn ($item) => Arr::only($item, ['file', 'line']))
->toArray();

Telescope::recordException(IncomingEntry::make([
'class' => get_class($exception),
Expand All @@ -65,6 +67,9 @@ public function process(object $event): void
]));
}

/**
* @param Throwable $exception
*/
protected function getContext($exception): array
{
if (Str::contains($exception->getFile(), "eval()'d code")) {
Expand All @@ -75,8 +80,7 @@ protected function getContext($exception): array

return (new Collection(explode("\n", file_get_contents($exception->getFile()))))
->slice($exception->getLine() - 10, 20)
->mapWithKeys(function ($value, $key) {
return [$key + 1 => $value];
})->all();
->mapWithKeys(fn ($value, $key) => [$key + 1 => $value])
->all();
}
}
117 changes: 117 additions & 0 deletions src/telescope/src/Listener/RedisCommandExecutedListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

declare(strict_types=1);
/**
* This file is part of friendsofhyperf/components.
*
* @link https://github.com/friendsofhyperf/components
* @document https://github.com/friendsofhyperf/components/blob/main/README.md
* @contact [email protected]
*/

namespace FriendsOfHyperf\Telescope\Listener;

use FriendsOfHyperf\Telescope\IncomingEntry;
use FriendsOfHyperf\Telescope\Telescope;
use FriendsOfHyperf\Telescope\TelescopeConfig;
use FriendsOfHyperf\Telescope\TelescopeContext;
use Hyperf\Collection\Collection;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Contract\PackerInterface;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Redis\Event\CommandExecuted;
use Psr\Container\ContainerInterface;
use Throwable;

class RedisCommandExecutedListener implements ListenerInterface
{
public function __construct(
private ContainerInterface $container,
private ConfigInterface $config,
private TelescopeConfig $telescopeConfig,
) {
$this->telescopeConfig->isEnable('redis') && $this->setRedisEventEnable();
}

public function listen(): array
{
return [
CommandExecuted::class,
];
}

/**
* @param object|CommandExecuted $event
*/
public function process(object $event): void
{
if (
! $event instanceof CommandExecuted
|| ! $this->telescopeConfig->isEnable('redis')
|| ! TelescopeContext::getBatchId()
) {
return;
}

$command = $this->formatCommand($event->command, $event->parameters);

if (str_contains($command, 'telescope')) {
return;
}

Telescope::recordRedis(IncomingEntry::make([
'connection' => $event->connection,
'command' => $command,
'time' => number_format($event->time * 1000, 2, '.', ''),
]));
}

private function formatCommand(string $command, array $parameters): string
{
$parameters = (new Collection($parameters))
->map(function ($parameter, $key) use ($command) {
if (is_array($parameter)) {
return (new Collection($parameter))
->map(function ($value, $key) {
if (is_array($value)) {
return json_encode($value);
}

return is_int($key) ? $value : "{$key} {$value}";
})
->implode(' ');
}
if (
$command == 'set'
&& $key == 1
&& $driver = TelescopeContext::getCacheDriver()
) {
$packerClass = $this->config->get('cache.' . $driver . '.packer', '');
$packer = $this->container->has($packerClass) ? $this->container->get($packerClass) : null;
if ($packer && $packer instanceof PackerInterface) {
try {
$unpacked = $packer->unpack((string) $parameter);
$parameter = match (true) {
is_null($unpacked) => 'null',
is_array($unpacked) => json_encode($unpacked),
default => $unpacked,
};
} catch (Throwable $e) {
}
}
}

return $parameter;
})
->implode(' ');

return "{$command} {$parameters}";
}

private function setRedisEventEnable()
{
foreach ((array) $this->config->get('redis', []) as $connection => $_) {
$this->config->set('redis.' . $connection . '.event.enable', true);
}
}
}

0 comments on commit 3e9c2ed

Please sign in to comment.