diff --git a/src/sentry/src/Tracing/Aspect/RedisConnectionAspect.php b/src/sentry/src/Tracing/Aspect/RedisConnectionAspect.php index 9763e67fa..11ce2b435 100644 --- a/src/sentry/src/Tracing/Aspect/RedisConnectionAspect.php +++ b/src/sentry/src/Tracing/Aspect/RedisConnectionAspect.php @@ -17,6 +17,7 @@ use Hyperf\Di\Aop\ProceedingJoinPoint; use Redis; use RedisCluster; +use WeakMap; use function Hyperf\Tappable\tap; @@ -26,6 +27,13 @@ class RedisConnectionAspect extends AbstractAspect 'Hyperf\Redis\RedisConnection::__call', ]; + private WeakMap $slotNodeCache; + + public function __construct() + { + $this->slotNodeCache = new WeakMap(); + } + public function process(ProceedingJoinPoint $proceedingJoinPoint) { return tap($proceedingJoinPoint->process(), function ($result) use ($proceedingJoinPoint) { @@ -38,8 +46,36 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) } if ($connection instanceof RedisCluster) { // RedisCluster - // TODO: support RedisCluster + $arguments = $proceedingJoinPoint->arguments['keys']['arguments'] ?? []; + $key = $arguments[0] ?? null; + if (is_string($key)) { + $node = $this->getClusterNodeBySlot($connection, $key); + if ($node !== null) { + Context::set(Constants::TRACE_REDIS_SERVER_ADDRESS, $node['host']); + Context::set(Constants::TRACE_REDIS_SERVER_PORT, $node['port']); + } + } } }); } + + private function getClusterNodeBySlot(RedisCluster $rc, string $key) + { + $slot = $rc->cluster('CLUSTER', 'KEYSLOT', $key); + $slots = ($this->slotNodeCache[$rc] ??= $rc->cluster('CLUSTER', 'SLOTS')); // @phpstan-ignore-line + + foreach ($slots as $range) { + [$start, $end, $master] = $range; + if ($slot >= $start && $slot <= $end) { + // $master = [host, port, nodeId] + return [ + 'host' => $master[0], + 'port' => $master[1], + 'nodeId' => $master[2] ?? null, + ]; + } + } + + return null; + } }