diff --git a/src/sentry/src/Tracing/Aspect/RedisAspect.php b/src/sentry/src/Tracing/Aspect/RedisAspect.php index a619b78a7..d23098914 100644 --- a/src/sentry/src/Tracing/Aspect/RedisAspect.php +++ b/src/sentry/src/Tracing/Aspect/RedisAspect.php @@ -13,6 +13,7 @@ use FriendsOfHyperf\Sentry\Switcher; use FriendsOfHyperf\Sentry\Tracing\SpanStarter; +use FriendsOfHyperf\Sentry\Util\RedisCommand; use Hyperf\Coroutine\Coroutine; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; @@ -65,7 +66,7 @@ class_exists(CommandExecuted::class) 'db.redis.connection' => $poolName, 'db.redis.database_index' => $config['db'] ?? 0, 'db.redis.parameters' => $arguments['arguments'], - // 'db.statement' => strtoupper($arguments['name']) . implode(' ', $arguments['arguments']), + 'db.statement' => (new RedisCommand($arguments['name'], $arguments['arguments']))->__toString(), 'db.redis.pool.name' => $poolName, 'db.redis.pool.max' => $pool->getOption()->getMaxConnections(), 'db.redis.pool.max_idle_time' => $pool->getOption()->getMaxIdleTime(), diff --git a/src/sentry/src/Tracing/Listener/TracingRedisListener.php b/src/sentry/src/Tracing/Listener/TracingRedisListener.php index e19b7a6bb..cc4d3cd84 100644 --- a/src/sentry/src/Tracing/Listener/TracingRedisListener.php +++ b/src/sentry/src/Tracing/Listener/TracingRedisListener.php @@ -13,6 +13,7 @@ use FriendsOfHyperf\Sentry\Switcher; use FriendsOfHyperf\Sentry\Tracing\SpanStarter; +use FriendsOfHyperf\Sentry\Util\RedisCommand; use Hyperf\Contract\ConfigInterface; use Hyperf\Coroutine\Coroutine; use Hyperf\Event\Contract\ListenerInterface; @@ -58,7 +59,7 @@ public function process(object $event): void 'db.redis.connection' => $event->connectionName, 'db.redis.database_index' => $config['db'] ?? 0, 'db.redis.parameters' => $event->parameters, - 'db.statement' => implode(' ', [$event->parameters[0] ?? '', $event->parameters[1] ?? '']), // @todo optimize + 'db.statement' => (new RedisCommand($event->command, $event->parameters))->__toString(), 'db.redis.pool.name' => $event->connectionName, 'db.redis.pool.max' => $pool->getOption()->getMaxConnections(), 'db.redis.pool.max_idle_time' => $pool->getOption()->getMaxIdleTime(), diff --git a/src/sentry/src/Util/RedisCommand.php b/src/sentry/src/Util/RedisCommand.php new file mode 100644 index 000000000..e46c92bcf --- /dev/null +++ b/src/sentry/src/Util/RedisCommand.php @@ -0,0 +1,47 @@ +formatCommand($this->command, $this->parameters); + } + + protected function formatCommand(string $command, array $parameters): string + { + $parameters = collect($parameters)->map(function ($parameter) { + if (is_array($parameter)) { + return collect($parameter)->map(function ($value, $key) { + if (is_array($value)) { + return sprintf('%s %s', $key, json_encode($value)); + } + + return is_int($key) ? $value : sprintf('%s %s', $key, $value); + })->implode(' '); + } + + return $parameter; + })->implode(' '); + + return sprintf('%s %s', $command, $parameters); + } +} diff --git a/tests/Sentry/RedisCommandTest.php b/tests/Sentry/RedisCommandTest.php new file mode 100644 index 000000000..d5a6f764c --- /dev/null +++ b/tests/Sentry/RedisCommandTest.php @@ -0,0 +1,68 @@ +toBe('GET key'); +}); + +test('redis command with multiple simple parameters', function () { + $command = new RedisCommand('MGET', ['key1', 'key2', 'key3']); + + expect((string) $command)->toBe('MGET key1 key2 key3'); +}); + +test('redis command with array parameter', function () { + $command = new RedisCommand('HMSET', ['user:1', ['name' => 'John', 'email' => 'john@example.com']]); + + expect((string) $command)->toBe('HMSET user:1 name John email john@example.com'); +}); + +test('redis command with nested array parameter', function () { + $command = new RedisCommand('HMSET', ['user:1', ['name' => 'John', 'data' => ['age' => 30, 'active' => true]]]); + + expect((string) $command)->toBe('HMSET user:1 name John data {"age":30,"active":true}'); +}); + +test('redis command with indexed array parameter', function () { + $command = new RedisCommand('LPUSH', ['list', ['item1', 'item2', 'item3']]); + + expect((string) $command)->toBe('LPUSH list item1 item2 item3'); +}); + +test('redis command with empty parameters', function () { + $command = new RedisCommand('PING'); + + expect((string) $command)->toBe('PING '); +}); + +test('redis command with mixed parameters', function () { + $command = new RedisCommand('ZADD', ['scores', 1, 'value1', 2, 'value2', ['extra' => 'data']]); + + expect((string) $command)->toBe('ZADD scores 1 value1 2 value2 extra data'); +}); + +test('redis command with SET NX option', function () { + $command = new RedisCommand('SET', ['key', 'value', 'NX']); + + expect((string) $command)->toBe('SET key value NX'); +}); + +test('redis command with SET EX option', function () { + $command = new RedisCommand('SET', ['key', 'value', 'EX', 60]); + + expect((string) $command)->toBe('SET key value EX 60'); +});