From 5893eaabf5eaef482e57bdc0e0be0a14efc92f9e Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Mon, 22 Sep 2025 22:20:56 +0800 Subject: [PATCH 01/64] feat(tracing): enhance span management with improved error handling and context propagation --- src/sentry/src/Aspect/CoroutineAspect.php | 3 +- .../src/Tracing/Aspect/CoroutineAspect.php | 39 +++++++++++++----- src/sentry/src/Tracing/SpanStarter.php | 41 +++++++++++++++++++ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/sentry/src/Aspect/CoroutineAspect.php b/src/sentry/src/Aspect/CoroutineAspect.php index 2eb5f76e4..cf0ce7e09 100644 --- a/src/sentry/src/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Aspect/CoroutineAspect.php @@ -25,7 +25,6 @@ class CoroutineAspect extends AbstractAspect ]; protected array $keys = [ - SentrySdk::class, \Psr\Http\Message\ServerRequestInterface::class, ]; @@ -40,7 +39,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $current = Co::getContextFor(); foreach ($keys as $key) { - if (isset($from[$key])) { + if (isset($from[$key]) && ! isset($current[$key])) { $current[$key] = $from[$key]; } } diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index c2b190d95..448f5da6b 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -14,9 +14,9 @@ use FriendsOfHyperf\Sentry\Switcher; use FriendsOfHyperf\Sentry\Tracing\SpanStarter; use FriendsOfHyperf\Sentry\Util\CoroutineBacktraceHelper; -use Hyperf\Coroutine\Coroutine as Co; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; +use Hyperf\Engine\Coroutine as Co; use Sentry\SentrySdk; use Sentry\Tracing\SpanStatus; use Throwable; @@ -27,12 +27,14 @@ class CoroutineAspect extends AbstractAspect { use SpanStarter; - public ?int $priority = PHP_INT_MAX; - public array $classes = [ 'Hyperf\Coroutine\Coroutine::create', ]; + protected array $keys = [ + \Psr\Http\Message\ServerRequestInterface::class, + ]; + public function __construct(protected Switcher $switcher) { } @@ -52,6 +54,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) return $proceedingJoinPoint->process(); } + $keys = $this->keys; $callable = $proceedingJoinPoint->arguments['keys']['callable']; $parent = $this->startSpan( op: 'coroutine.create', @@ -63,9 +66,18 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) return $proceedingJoinPoint->process(); } - $parent->setData(['coroutine.id' => Co::id()]); + $parent->setData(['coroutine.id' => $cid = Co::id()]); + + $proceedingJoinPoint->arguments['keys']['callable'] = function () use ($callable, $parent, $callingOnFunction, $cid, $keys) { + $from = Co::getContextFor($cid); + $current = Co::getContextFor(); + + foreach ($keys as $key) { + if (isset($from[$key]) && ! isset($current[$key])) { + $current[$key] = $from[$key]; + } + } - $proceedingJoinPoint->arguments['keys']['callable'] = function () use ($callable, $parent, $callingOnFunction) { $transaction = $this->startCoroutineTransaction( parent: $parent, name: 'coroutine', @@ -74,7 +86,16 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) origin: 'auto.coroutine', )->setData(['coroutine.id' => Co::id()]); - defer(function () use ($transaction) { + $span = $this->startSpan( + op: 'coroutine.execute.inner', + description: $callingOnFunction, + origin: 'auto.coroutine', + asParent: true + )?->setData(['coroutine.id' => Co::id()]); + + defer(function () use ($transaction, $span) { + $span?->finish(); + SentrySdk::getCurrentHub()->setSpan($transaction); $transaction->finish(); }); @@ -82,7 +103,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) try { $callable(); } catch (Throwable $exception) { - $transaction->setStatus(SpanStatus::internalError()) + $span?->setStatus(SpanStatus::internalError()) ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, @@ -90,14 +111,12 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) 'exception.code' => (string) $exception->getCode(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $transaction->setData([ + $span?->setData([ 'exception.stack_trace' => (string) $exception, ]); } throw $exception; - } finally { - // ... } }; diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index fad2f3398..2d81bf965 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -23,12 +23,49 @@ use Sentry\Tracing\SpanStatus; use Sentry\Tracing\Transaction; use Sentry\Tracing\TransactionSource; +use Throwable; use function Hyperf\Tappable\tap; use function Sentry\continueTrace; +use function Sentry\trace; trait SpanStarter { + /** + * @param callable(null|Span):mixed $callback + */ + protected function trace(callable $callback, SpanContext $spanContext): mixed + { + $parent = SentrySdk::getCurrentHub()->getSpan(); + $span = null; + + if ($parent !== null && $parent->getSampled()) { + $span = $parent->startChild($spanContext); + } + + try { + return $callback($span); + } catch (Throwable $exception) { + $span?->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.message' => $exception->getMessage(), + 'exception.code' => (string) $exception->getCode(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $span?->setData([ + 'exception.stack_trace' => (string) $exception, + ]); + } + throw $exception; + } finally { + $span?->finish(); + + SentrySdk::getCurrentHub()->setSpan($parent); + } + } + protected function startSpan( ?string $op = null, ?string $description = null, @@ -39,6 +76,10 @@ protected function startSpan( return null; } + if ($parent instanceof Transaction && ! $parent->getSampled()) { + return null; + } + $spanContext = SpanContext::make()->setOp($op) ->setDescription($description) ->setOrigin($origin) From 50087a80a3f70d689803f6f3b483ca19e581b4df Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Mon, 22 Sep 2025 22:21:53 +0800 Subject: [PATCH 02/64] refactor(span): update trace method parameter type hint for improved type safety --- src/sentry/src/Tracing/SpanStarter.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index 2d81bf965..054e90bf6 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -32,7 +32,10 @@ trait SpanStarter { /** - * @param callable(null|Span):mixed $callback + * @template T + * + * @param callable(null|Span):T $callback + * @return T */ protected function trace(callable $callback, SpanContext $spanContext): mixed { From fff7472cfce16d373fda2ffcbb8ad92787c166c8 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Mon, 22 Sep 2025 22:28:07 +0800 Subject: [PATCH 03/64] refactor(span): improve trace method to enhance scope handling and error management --- src/sentry/src/Tracing/SpanStarter.php | 60 ++++++++++++++------------ 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index 054e90bf6..02eeb1024 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -18,6 +18,7 @@ use Psr\Http\Message\ServerRequestInterface; use Sentry\SentrySdk; use Sentry\State\HubInterface; +use Sentry\State\Scope; use Sentry\Tracing\Span; use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; @@ -34,39 +35,44 @@ trait SpanStarter /** * @template T * - * @param callable(null|Span):T $callback + * @param callable(Scope):T $trace * @return T */ - protected function trace(callable $callback, SpanContext $spanContext): mixed + protected function trace(callable $trace, SpanContext $context) { - $parent = SentrySdk::getCurrentHub()->getSpan(); - $span = null; + return SentrySdk::getCurrentHub()->withScope(function (Scope $scope) use ($trace, $context) { + $parentSpan = $scope->getSpan(); - if ($parent !== null && $parent->getSampled()) { - $span = $parent->startChild($spanContext); - } - - try { - return $callback($span); - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData([ - 'exception.stack_trace' => (string) $exception, - ]); + if ($parentSpan !== null && $parentSpan->getSampled()) { + $span = $parentSpan->startChild($context); } - throw $exception; - } finally { - $span?->finish(); - SentrySdk::getCurrentHub()->setSpan($parent); - } + try { + return $trace($scope); + } catch (Throwable $exception) { + if (isset($span)) { + $span->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.message' => $exception->getMessage(), + 'exception.code' => (string) $exception->getCode(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $span->setData([ + 'exception.stack_trace' => (string) $exception, + ]); + } + } + throw $exception; + } finally { + if (isset($span)) { + $span->finish(); + + $scope->setSpan($parentSpan); + } + } + }); } protected function startSpan( From aa57540e81868e1c2a30c37a9a6ee03daa178488 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:15:35 +0800 Subject: [PATCH 04/64] fix(listener): ensure all spans are flushed before command exits --- src/sentry/src/Tracing/Listener/EventHandleListener.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index d17541275..687e45ef6 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -432,6 +432,9 @@ private function handleCommandFinished(CommandEvent\AfterExecute $event): void SentrySdk::getCurrentHub()->setSpan($transaction); $transaction->finish(); + + // Make sure all spans are flushed before the command exits + msleep(100); } private function handleRedisCommandExecuted(RedisEvent\CommandExecuted $event): void From c00a83a690c7a0a784f776114940115f37f7c6f5 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:20:58 +0800 Subject: [PATCH 05/64] refactor(listener): remove unnecessary sleep to ensure spans are flushed before command exits --- src/sentry/src/Tracing/Listener/EventHandleListener.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 687e45ef6..d17541275 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -432,9 +432,6 @@ private function handleCommandFinished(CommandEvent\AfterExecute $event): void SentrySdk::getCurrentHub()->setSpan($transaction); $transaction->finish(); - - // Make sure all spans are flushed before the command exits - msleep(100); } private function handleRedisCommandExecuted(RedisEvent\CommandExecuted $event): void From 5b1f685e01dd299269c04bc74fef8388bd7b39b0 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:25:58 +0800 Subject: [PATCH 06/64] refactor(aspect): set priority to PHP_INT_MAX in constructor for improved aspect handling --- src/sentry/src/Aspect/CoroutineAspect.php | 5 +++++ src/sentry/src/Tracing/Aspect/CoroutineAspect.php | 1 + 2 files changed, 6 insertions(+) diff --git a/src/sentry/src/Aspect/CoroutineAspect.php b/src/sentry/src/Aspect/CoroutineAspect.php index cf0ce7e09..d0cdc007f 100644 --- a/src/sentry/src/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Aspect/CoroutineAspect.php @@ -28,6 +28,11 @@ class CoroutineAspect extends AbstractAspect \Psr\Http\Message\ServerRequestInterface::class, ]; + public function __construct() + { + $this->priority = PHP_INT_MAX - 1; + } + public function process(ProceedingJoinPoint $proceedingJoinPoint) { $callable = $proceedingJoinPoint->arguments['keys']['callable']; diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index 448f5da6b..1e02c9e79 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -37,6 +37,7 @@ class CoroutineAspect extends AbstractAspect public function __construct(protected Switcher $switcher) { + $this->priority = PHP_INT_MAX; } public function process(ProceedingJoinPoint $proceedingJoinPoint) From efb335c74568489b7126a9525e31007c96883d77 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:30:00 +0800 Subject: [PATCH 07/64] refactor(coroutine-aspect): remove commented SentrySdk class reference for clarity --- src/sentry/src/Aspect/CoroutineAspect.php | 2 +- src/sentry/src/Tracing/Aspect/CoroutineAspect.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sentry/src/Aspect/CoroutineAspect.php b/src/sentry/src/Aspect/CoroutineAspect.php index d0cdc007f..8aafafc1b 100644 --- a/src/sentry/src/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Aspect/CoroutineAspect.php @@ -15,7 +15,6 @@ use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; use Hyperf\Engine\Coroutine as Co; -use Sentry\SentrySdk; use Throwable; class CoroutineAspect extends AbstractAspect @@ -25,6 +24,7 @@ class CoroutineAspect extends AbstractAspect ]; protected array $keys = [ + // \Sentry\SentrySdk::class, \Psr\Http\Message\ServerRequestInterface::class, ]; diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index 1e02c9e79..b37a37a4c 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -32,6 +32,7 @@ class CoroutineAspect extends AbstractAspect ]; protected array $keys = [ + // \Sentry\SentrySdk::class, \Psr\Http\Message\ServerRequestInterface::class, ]; From db819381f3006e0d8795d2fd9e2f65ba7b7d6202 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:31:37 +0800 Subject: [PATCH 08/64] fix(coroutine-aspect): add missing SentrySdk import for exception handling --- src/sentry/src/Aspect/CoroutineAspect.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sentry/src/Aspect/CoroutineAspect.php b/src/sentry/src/Aspect/CoroutineAspect.php index 8aafafc1b..61d2bfb06 100644 --- a/src/sentry/src/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Aspect/CoroutineAspect.php @@ -15,6 +15,7 @@ use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; use Hyperf\Engine\Coroutine as Co; +use Sentry\SentrySdk; use Throwable; class CoroutineAspect extends AbstractAspect From 367f2d5b029641a0583cd19a947cdc72c5cf0e74 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:35:04 +0800 Subject: [PATCH 09/64] fix(aspect): uncomment SentrySdk class reference in keys array for proper integration --- src/sentry/src/Aspect/CoroutineAspect.php | 2 +- src/sentry/src/Tracing/Aspect/CoroutineAspect.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sentry/src/Aspect/CoroutineAspect.php b/src/sentry/src/Aspect/CoroutineAspect.php index 61d2bfb06..da7c7cc18 100644 --- a/src/sentry/src/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Aspect/CoroutineAspect.php @@ -25,7 +25,7 @@ class CoroutineAspect extends AbstractAspect ]; protected array $keys = [ - // \Sentry\SentrySdk::class, + SentrySdk::class, \Psr\Http\Message\ServerRequestInterface::class, ]; diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index b37a37a4c..cce8d8257 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -32,7 +32,7 @@ class CoroutineAspect extends AbstractAspect ]; protected array $keys = [ - // \Sentry\SentrySdk::class, + SentrySdk::class, \Psr\Http\Message\ServerRequestInterface::class, ]; From 4052232428eb06f200f6f953677c38aac471d6c2 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:58:28 +0800 Subject: [PATCH 10/64] fix(span-starter): reorder parameters in withScope closure for consistency --- src/sentry/src/Tracing/SpanStarter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index 02eeb1024..df93139c1 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -40,7 +40,7 @@ trait SpanStarter */ protected function trace(callable $trace, SpanContext $context) { - return SentrySdk::getCurrentHub()->withScope(function (Scope $scope) use ($trace, $context) { + return SentrySdk::getCurrentHub()->withScope(function (Scope $scope) use ($context, $trace) { $parentSpan = $scope->getSpan(); if ($parentSpan !== null && $parentSpan->getSampled()) { From 0df83f42ae1d494eaeb7205d0a355c861ffafae7 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 11:01:37 +0800 Subject: [PATCH 11/64] fix(span-starter): set current span in scope for child span tracking --- src/sentry/src/Tracing/SpanStarter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index df93139c1..0e1dc71b0 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -45,6 +45,7 @@ protected function trace(callable $trace, SpanContext $context) if ($parentSpan !== null && $parentSpan->getSampled()) { $span = $parentSpan->startChild($context); + $scope->setSpan($span); } try { From 6fe1ad7f7355299a94d7e804acc18b212fd09633 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 11:25:00 +0800 Subject: [PATCH 12/64] fix(event-handle-listener): refactor Redis span handling to use trace method for better context management --- .../src/Tracing/Aspect/FilesystemAspect.php | 54 +++++++------ .../Tracing/Listener/EventHandleListener.php | 81 +++++++++---------- 2 files changed, 69 insertions(+), 66 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/FilesystemAspect.php b/src/sentry/src/Tracing/Aspect/FilesystemAspect.php index af1f673bd..e5b535889 100644 --- a/src/sentry/src/Tracing/Aspect/FilesystemAspect.php +++ b/src/sentry/src/Tracing/Aspect/FilesystemAspect.php @@ -15,6 +15,8 @@ use FriendsOfHyperf\Sentry\Tracing\SpanStarter; use Hyperf\Di\Aop\ProceedingJoinPoint; use Override; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; use Throwable; @@ -31,30 +33,32 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) [$op, $description, $data] = $this->getSentryMetadata($proceedingJoinPoint); - $span = $this->startSpan( - op: $op, - description: $description, - origin: 'auto.filesystem', - )?->setData($data); - - try { - return $proceedingJoinPoint->process(); - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - throw $exception; - } finally { - $span?->finish(); - } + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint) { + $span = $scope->getSpan(); + try { + return $proceedingJoinPoint->process(); + } catch (Throwable $exception) { + $span->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.message' => $exception->getMessage(), + 'exception.code' => (string) $exception->getCode(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $span->setData([ + 'exception.stack_trace' => (string) $exception, + ]); + } + throw $exception; + } + }, + SpanContext::make() + ->setOp($op) + ->setDescription($description) + ->setOrigin('auto.filesystem') + ->setData($data) + ); } } diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index d17541275..3af9f3549 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -42,6 +42,8 @@ use PhpAmqpLib\Wire\AMQPTable; use Psr\Container\ContainerInterface; use Sentry\SentrySdk; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; use Sentry\Tracing\TransactionSource; use Swow\Psr7\Message\ResponsePlusInterface; @@ -444,49 +446,46 @@ private function handleRedisCommandExecuted(RedisEvent\CommandExecuted $event): $config = $this->config->get('redis.' . $event->connectionName, []); $redisStatement = (string) new RedisCommand($event->command, $event->parameters); - $span = $this->startSpan( - op: 'db.redis', - description: $redisStatement, - origin: 'auto.cache.redis', - ); - - if (! $span) { - return; - } + $this->trace( + function (Scope $scope) use ($event) { + $span = $scope->getSpan(); - $span->setData([ - 'coroutine.id' => Coroutine::id(), - 'db.system' => 'redis', - 'db.statement' => $redisStatement, - 'db.redis.connection' => $event->connectionName, - 'db.redis.database_index' => $config['db'] ?? 0, - 'db.redis.parameters' => $event->parameters, - 'db.redis.pool.name' => $event->connectionName, - 'db.redis.pool.max' => $pool->getOption()->getMaxConnections(), - 'db.redis.pool.max_idle_time' => $pool->getOption()->getMaxIdleTime(), - 'db.redis.pool.idle' => $pool->getConnectionsInChannel(), - 'db.redis.pool.using' => $pool->getCurrentConnections(), - 'duration' => $event->time * 1000, - ]); - - if ($this->switcher->isTracingExtraTagEnabled('redis.result')) { - $span->setData(['db.redis.result' => $event->result]); - } - - if ($exception = $event->throwable) { - $span->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span->setData(['exception.stack_trace' => (string) $exception]); - } - } + if ($this->switcher->isTracingExtraTagEnabled('redis.result')) { + $span?->setData(['db.redis.result' => $event->result]); + } - $span->finish(); + if ($exception = $event->throwable) { + $span?->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.message' => $exception->getMessage(), + 'exception.code' => (string) $exception->getCode(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $span?->setData(['exception.stack_trace' => (string) $exception]); + } + } + }, + SpanContext::make() + ->setOp('db.redis') + ->setDescription($redisStatement) + ->setData([ + 'coroutine.id' => Coroutine::id(), + 'db.system' => 'redis', + 'db.statement' => $redisStatement, + 'db.redis.connection' => $event->connectionName, + 'db.redis.database_index' => $config['db'] ?? 0, + 'db.redis.parameters' => $event->parameters, + 'db.redis.pool.name' => $event->connectionName, + 'db.redis.pool.max' => $pool->getOption()->getMaxConnections(), + 'db.redis.pool.max_idle_time' => $pool->getOption()->getMaxIdleTime(), + 'db.redis.pool.idle' => $pool->getConnectionsInChannel(), + 'db.redis.pool.using' => $pool->getCurrentConnections(), + 'duration' => $event->time * 1000, + ]) + ->setStartTimestamp(microtime(true) - $event->time / 1000) + ); } private function handleCrontabTaskStarting(CrontabEvent\BeforeExecute $event): void From 7aebe5159d23a3c3fdad7a1fd11a47fd2152aebc Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 11:29:25 +0800 Subject: [PATCH 13/64] fix(grpc-aspect): refactor tracing logic to use trace method and improve error handling --- src/sentry/src/Tracing/Aspect/GrpcAspect.php | 72 ++++++++------------ 1 file changed, 28 insertions(+), 44 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/GrpcAspect.php b/src/sentry/src/Tracing/Aspect/GrpcAspect.php index 29e5b17f0..42404b977 100644 --- a/src/sentry/src/Tracing/Aspect/GrpcAspect.php +++ b/src/sentry/src/Tracing/Aspect/GrpcAspect.php @@ -18,8 +18,9 @@ use Hyperf\Di\Aop\ProceedingJoinPoint; use Hyperf\GrpcClient\BaseClient; use Sentry\SentrySdk; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; -use Swoole\Http2\Response as Http2Response; use Throwable; class GrpcAspect extends AbstractAspect @@ -65,49 +66,32 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) // Inject tracing headers $proceedingJoinPoint->arguments['keys']['options'] = $options; - // Start gRPC client span - $span = $this->startSpan( - op: 'grpc.client', - description: $method, - origin: 'auto.grpc', - )?->setData($data); - - try { - $result = $proceedingJoinPoint->process(); - - [$message, $code, $response] = $result; - - if ($response instanceof Http2Response) { - $span?->setData([ - 'response.status' => $code, - 'response.reason' => $message, - 'response.headers' => $response->headers, - ]); - if ($this->switcher->isTracingExtraTagEnabled('response.body')) { - $span?->setData([ - 'response.body' => $response->data, - ]); + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint) { + $span = $scope->getSpan(); + try { + return $proceedingJoinPoint->process(); + } catch (Throwable $exception) { + $span->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.message' => $exception->getMessage(), + 'exception.code' => (string) $exception->getCode(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $span->setData([ + 'exception.stack_trace' => (string) $exception, + ]); + } + throw $exception; } - } - - return $result; - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - - throw $exception; - } finally { - $span?->finish(); - } + }, + SpanContext::make() + ->setOp('grpc.client') + ->setDescription($method) + ->setOrigin('auto.grpc') + ->setData($data) + ); } } From 121fbcb87f83095578d0790d6c95bf420956efbd Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 11:34:57 +0800 Subject: [PATCH 14/64] fix(cache-aspect): refactor process method to enhance error handling and tracing context --- src/sentry/src/Tracing/Aspect/CacheAspect.php | 127 ++++++++++-------- 1 file changed, 72 insertions(+), 55 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/CacheAspect.php b/src/sentry/src/Tracing/Aspect/CacheAspect.php index f44eaa449..c6f9adf28 100644 --- a/src/sentry/src/Tracing/Aspect/CacheAspect.php +++ b/src/sentry/src/Tracing/Aspect/CacheAspect.php @@ -15,7 +15,10 @@ use FriendsOfHyperf\Sentry\Tracing\SpanStarter; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; -use Sentry\SentrySdk; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; +use Sentry\Tracing\SpanStatus; +use Throwable; use function Hyperf\Tappable\tap; @@ -47,63 +50,77 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) return $proceedingJoinPoint->process(); } - $parent = SentrySdk::getCurrentHub()->getSpan(); + $method = $proceedingJoinPoint->methodName; + $op = match ($method) { + 'set', 'setMultiple' => 'cache.put', + 'get', 'fetch', 'getMultiple' => 'cache.get', + 'delete', 'deleteMultiple' => 'cache.remove', + 'clear' => 'cache.flush', + default => 'cache', + }; - try { - $method = $proceedingJoinPoint->methodName; - $op = match ($method) { - 'set', 'setMultiple' => 'cache.put', - 'get', 'fetch', 'getMultiple' => 'cache.get', - 'delete', 'deleteMultiple' => 'cache.remove', - 'clear' => 'cache.flush', - default => 'cache', - }; + $arguments = $proceedingJoinPoint->arguments['keys'] ?? []; - $arguments = $proceedingJoinPoint->arguments['keys'] ?? []; + /** @var string[] $keys */ + $keys = match ($method) { + 'set', 'get', 'delete' => [$arguments['key'] ?? 'unknown'], + 'setMultiple' => array_keys($arguments['values'] ?? []), + 'getMultiple', 'deleteMultiple' => $arguments['keys'] ?? [], + default => [], + }; - /** @var string[] $keys */ - $keys = match ($method) { - 'set', 'get', 'delete' => [$arguments['key'] ?? 'unknown'], - 'setMultiple' => array_keys($arguments['values'] ?? []), - 'getMultiple', 'deleteMultiple' => $arguments['keys'] ?? [], - default => [], - }; + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint, $method) { + $span = $scope->getSpan(); - $span = $this->startSpan( - op: $op, - description: implode(', ', $keys), - origin: 'auto.cache', - asParent: true - )?->setData([ - 'cache.key' => $keys, - 'cache.ttl' => $arguments['ttl'] ?? null, - 'item_size' => match (true) { - isset($arguments['value']) => strlen(json_encode($arguments['value'])), - isset($arguments['values']) && is_array($arguments['values']) => strlen(json_encode(array_values($arguments['values']))), - default => 0, - }, - ]); - - return tap($proceedingJoinPoint->process(), function ($result) use ($span, $method) { - $data = match ($method) { - 'get' => [ - 'cache.hit' => ! is_null($result), - 'cache.item_size' => strlen((string) json_encode($result)), - ], - 'fetch' => [ - 'cache.hit' => ($result[0] ?? false) !== false, - 'cache.item_size' => strlen((string) json_encode($result[1] ?? '')), - ], - 'getMultiple' => [ - 'cache.hit' => ! empty($result), - 'cache.item_size' => strlen((string) json_encode(array_values((array) $result))), - ], - default => [], - }; - $span?->setData($data)->finish(); - }); - } finally { - SentrySdk::getCurrentHub()->setSpan($parent); - } + try { + return tap($proceedingJoinPoint->process(), function ($result) use ($span, $method) { + $data = match ($method) { + 'get' => [ + 'cache.hit' => ! is_null($result), + 'cache.item_size' => strlen((string) json_encode($result)), + ], + 'fetch' => [ + 'cache.hit' => ($result[0] ?? false) !== false, + 'cache.item_size' => strlen((string) json_encode($result[1] ?? '')), + ], + 'getMultiple' => [ + 'cache.hit' => ! empty($result), + 'cache.item_size' => strlen((string) json_encode(array_values((array) $result))), + ], + default => [], + }; + $span?->setData($data); + }); + } catch (Throwable $exception) { + $span?->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.message' => $exception->getMessage(), + 'exception.code' => (string) $exception->getCode(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $span?->setData([ + 'exception.stack_trace' => (string) $exception, + ]); + } + throw $exception; + } + }, + SpanContext::make() + ->setOp($op) + ->setDescription(implode(', ', $keys)) + ->setOrigin('auto.cache') + ->setData([ + 'cache.key' => $keys, + 'cache.ttl' => $arguments['ttl'] ?? null, + 'item_size' => match (true) { + isset($arguments['value']) => strlen(json_encode($arguments['value'])), + isset($arguments['values']) && is_array($arguments['values']) => strlen(json_encode(array_values($arguments['values']))), + default => 0, + }, + ]) + ); } } From c40c068a1f7d29fb22f6378d2a7bb1f766057509 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 11:48:56 +0800 Subject: [PATCH 15/64] fix(async-queue-job-message-aspect): refactor process method to improve tracing and error handling --- .../Aspect/AsyncQueueJobMessageAspect.php | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php b/src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php index 5f3e6a5a4..731cdb9ca 100644 --- a/src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php +++ b/src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php @@ -19,6 +19,8 @@ use Hyperf\Context\Context; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; use function Hyperf\Support\with; @@ -73,46 +75,44 @@ public function handlePush(ProceedingJoinPoint $proceedingJoinPoint) { /** @var \Hyperf\AsyncQueue\JobInterface $job */ $job = $proceedingJoinPoint->arguments['keys']['job'] ?? null; - $span = $this->startSpan( - op: 'queue.publish', - description: $job::class, - origin: 'auto.queue' - ); - if (! $span) { - return $proceedingJoinPoint->process(); + /** @var \Hyperf\AsyncQueue\Driver\Driver $driver */ + $driver = $proceedingJoinPoint->getInstance(); + $messageId = method_exists($job, 'getId') ? $job->getId() : uniqid('async_queue_', true); + $destinationName = Context::get('sentry.messaging.destination.name', 'default'); + $bodySize = (fn ($job) => strlen($this->packer->pack($job)))->call($driver, $job); + $data = [ + 'messaging.system' => 'async_queue', + 'messaging.operation' => 'publish', + 'messaging.message.id' => $messageId, + 'messaging.message.body.size' => $bodySize, + 'messaging.destination.name' => $destinationName, + ]; + + if ($driver instanceof RedisDriver) { + $data = array_merge($data, $this->buildSpanDataOfRedisDriver($driver)); } - try { - /** @var \Hyperf\AsyncQueue\Driver\Driver $driver */ - $driver = $proceedingJoinPoint->getInstance(); - $messageId = method_exists($job, 'getId') ? $job->getId() : uniqid('async_queue_', true); - $destinationName = Context::get('sentry.messaging.destination.name', 'default'); - $bodySize = (fn ($job) => strlen($this->packer->pack($job)))->call($driver, $job); - $span->setData([ - 'messaging.system' => 'async_queue', - 'messaging.operation' => 'publish', - 'messaging.message.id' => $messageId, - 'messaging.message.body.size' => $bodySize, - 'messaging.destination.name' => $destinationName, - ]); - if ($driver instanceof RedisDriver) { - $span->setData($this->buildSpanDataOfRedisDriver($driver)); - } - - $carrier = Carrier::fromSpan($span)->with([ - 'publish_time' => microtime(true), - 'message_id' => $messageId, - 'destination_name' => $destinationName, - 'body_size' => $bodySize, - ]); - - Context::set(Constants::TRACE_CARRIER, $carrier); - - return $proceedingJoinPoint->process(); - } finally { - $span->finish(); - } + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint, $messageId, $destinationName, $bodySize) { + $span = $scope->getSpan(); + $carrier = Carrier::fromSpan($span)->with([ + 'publish_time' => microtime(true), + 'message_id' => $messageId, + 'destination_name' => $destinationName, + 'body_size' => $bodySize, + ]); + + Context::set(Constants::TRACE_CARRIER, $carrier); + + return $proceedingJoinPoint->process(); + }, + SpanContext::make() + ->setOp('queue.publish') + ->setDescription($job::class) + ->setOrigin('auto.queue') + ->setData($data) + ); } protected function buildSpanDataOfRedisDriver(RedisDriver $driver): array From 74bee6b2768a2eae6348c3a064be17ae2f4b72fd Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 11:55:41 +0800 Subject: [PATCH 16/64] fix(amqp-producer-aspect): refactor message publishing to enhance tracing and context management --- .../src/Tracing/Aspect/AmqpProducerAspect.php | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php b/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php index 54b8ab647..951c80656 100644 --- a/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php +++ b/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php @@ -21,8 +21,8 @@ use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; use PhpAmqpLib\Wire\AMQPTable; - -use function Hyperf\Tappable\tap; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; /** * @property array{application_headers?:AMQPTable} $properties @@ -60,16 +60,6 @@ protected function handleProduceMessage(ProceedingJoinPoint $proceedingJoinPoint return $proceedingJoinPoint->process(); } - $span = $this->startSpan( - op: 'queue.publish', - description: sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName), - origin: 'auto.amqp' - ); - - if (! $span) { - return $proceedingJoinPoint->process(); - } - $routingKey = $producerMessage->getRoutingKey(); $exchange = $producerMessage->getExchange(); $poolName = $producerMessage->getPoolName(); @@ -87,30 +77,39 @@ protected function handleProduceMessage(ProceedingJoinPoint $proceedingJoinPoint $messageId = uniqid('amqp_', true); $destinationName = implode(', ', (array) $routingKey); $bodySize = strlen($producerMessage->payload()); - $span->setData([ - 'messaging.system' => 'amqp', - 'messaging.operation' => 'publish', - 'messaging.message.id' => $messageId, - 'messaging.message.body.size' => $bodySize, - 'messaging.destination.name' => $destinationName, - // for amqp - 'messaging.amqp.message.type' => $producerMessage->getTypeString(), - 'messaging.amqp.message.routing_key' => $routingKey, - 'messaging.amqp.message.exchange' => $exchange, - 'messaging.amqp.message.pool_name' => $poolName, - ]); - $carrier = Carrier::fromSpan($span)->with([ - 'publish_time' => microtime(true), - 'message_id' => $messageId, - 'destination_name' => $destinationName, - 'body_size' => $bodySize, - ]); - (function () use ($carrier) { - $this->properties['application_headers'] ??= new AMQPTable(); - $this->properties['application_headers']->set(Constants::TRACE_CARRIER, $carrier->toJson()); - })->call($producerMessage); - - return tap($proceedingJoinPoint->process(), fn () => $span->finish()); + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint, $producerMessage, $messageId, $destinationName, $bodySize) { + $span = $scope->getSpan(); + $carrier = Carrier::fromSpan($span)->with([ + 'publish_time' => microtime(true), + 'message_id' => $messageId, + 'destination_name' => $destinationName, + 'body_size' => $bodySize, + ]); + (function () use ($carrier) { + $this->properties['application_headers'] ??= new AMQPTable(); + $this->properties['application_headers']->set(Constants::TRACE_CARRIER, $carrier->toJson()); + })->call($producerMessage); + + return $proceedingJoinPoint->process(); + }, + SpanContext::make() + ->setOp('queue.publish') + ->setDescription(sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName)) + ->setOrigin('auto.amqp') + ->setData([ + 'messaging.system' => 'amqp', + 'messaging.operation' => 'publish', + 'messaging.message.id' => $messageId, + 'messaging.message.body.size' => $bodySize, + 'messaging.destination.name' => $destinationName, + // for amqp + 'messaging.amqp.message.type' => $producerMessage->getTypeString(), + 'messaging.amqp.message.routing_key' => $routingKey, + 'messaging.amqp.message.exchange' => $exchange, + 'messaging.amqp.message.pool_name' => $poolName, + ]) + ); } } From d179312b035d0694ae601bdef2899b7e78087e6d Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:01:47 +0800 Subject: [PATCH 17/64] fix(coordinator-aspect): refactor process method to enhance tracing and error handling --- .../src/Tracing/Aspect/CoordinatorAspect.php | 49 +++++++------------ 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/CoordinatorAspect.php b/src/sentry/src/Tracing/Aspect/CoordinatorAspect.php index 174be3b8c..18de02cab 100644 --- a/src/sentry/src/Tracing/Aspect/CoordinatorAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoordinatorAspect.php @@ -17,10 +17,8 @@ use Hyperf\Coroutine\Coroutine; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; -use Sentry\Tracing\SpanStatus; -use Throwable; - -use function Hyperf\Support\class_basename; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; class CoordinatorAspect extends AbstractAspect { @@ -36,35 +34,22 @@ public function __construct(protected Switcher $switcher) public function process(ProceedingJoinPoint $proceedingJoinPoint) { - $data = [ - 'coroutine.id' => Coroutine::id(), - 'timeout' => $timeout = $proceedingJoinPoint->arguments['keys']['timeout'] ?? -1, - ]; - - $span = $this->startSpan( - op: sprintf('%s.%s', strtolower(class_basename($proceedingJoinPoint->className)), $proceedingJoinPoint->methodName), - description: sprintf('%s::%s(%s)', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName, $timeout), - origin: 'auto.coordinator', - )?->setData($data); - - try { + if (! $this->switcher->isTracingSpanEnabled('coordinator')) { return $proceedingJoinPoint->process(); - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - throw $exception; - } finally { - $span?->finish(); } + + $timeout = $proceedingJoinPoint->arguments['keys']['timeout'] ?? -1; + + return $this->trace( + fn (Scope $scope) => $proceedingJoinPoint->process(), + SpanContext::make() + ->setOp('coordinator.yield') + ->setDescription(sprintf('%s::%s(%s)', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName, $timeout)) + ->setOrigin('auto.coordinator') + ->setData([ + 'coroutine.id' => Coroutine::id(), + 'timeout' => $timeout, + ]) + ); } } From 27f754a3a31719d38209848a33fe2587f5090065 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:03:29 +0800 Subject: [PATCH 18/64] fix(coroutine-aspect): refactor span handling to improve error tracking and transaction management --- src/sentry/src/Tracing/Aspect/CoroutineAspect.php | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index cce8d8257..b25c40349 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -88,16 +88,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) origin: 'auto.coroutine', )->setData(['coroutine.id' => Co::id()]); - $span = $this->startSpan( - op: 'coroutine.execute.inner', - description: $callingOnFunction, - origin: 'auto.coroutine', - asParent: true - )?->setData(['coroutine.id' => Co::id()]); - - defer(function () use ($transaction, $span) { - $span?->finish(); - + defer(function () use ($transaction) { SentrySdk::getCurrentHub()->setSpan($transaction); $transaction->finish(); }); @@ -105,7 +96,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) try { $callable(); } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) + $transaction->setStatus(SpanStatus::internalError()) ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, @@ -113,7 +104,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) 'exception.code' => (string) $exception->getCode(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData([ + $transaction->setData([ 'exception.stack_trace' => (string) $exception, ]); } From fd749a74bdb289271b4df0fb79cccbea3839b89a Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:08:43 +0800 Subject: [PATCH 19/64] fix(db-aspect): refactor process method to enhance tracing and error handling --- src/sentry/src/Tracing/Aspect/DbAspect.php | 71 +++++++++++----------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/DbAspect.php b/src/sentry/src/Tracing/Aspect/DbAspect.php index e1bf16304..d403ecd4f 100644 --- a/src/sentry/src/Tracing/Aspect/DbAspect.php +++ b/src/sentry/src/Tracing/Aspect/DbAspect.php @@ -21,6 +21,8 @@ use Hyperf\Di\Aop\ProceedingJoinPoint; use Psr\Container\ContainerInterface; use Sentry\SentrySdk; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; use Throwable; @@ -70,12 +72,6 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $table = $sqlParse['table']; $operation = $sqlParse['operation']; - $span = $this->startSpan( - op: 'db.sql.query', - description: $sql, - origin: 'auto.db', - ); - $data = [ 'coroutine.id' => Coroutine::id(), 'db.system' => $driver, @@ -98,34 +94,39 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) } } - $span?->setData($data); - - try { - $result = $proceedingJoinPoint->process(); - if ($this->switcher->isTracingExtraTagEnabled('db.result')) { - $span?->setData([ - 'db.result' => json_encode($result, JSON_UNESCAPED_UNICODE), - ]); - } - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - - throw $exception; - } finally { - $span?->finish(); - } - - return $result; + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint) { + $span = $scope->getSpan(); + try { + $result = $proceedingJoinPoint->process(); + if ($this->switcher->isTracingExtraTagEnabled('db.result')) { + $span?->setData([ + 'db.result' => json_encode($result, JSON_UNESCAPED_UNICODE), + ]); + } + return $result; + } catch (Throwable $exception) { + $span?->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.message' => $exception->getMessage(), + 'exception.code' => (string) $exception->getCode(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $span?->setData([ + 'exception.stack_trace' => (string) $exception, + ]); + } + + throw $exception; + } + }, + SpanContext::make() + ->setOp('db.sql.query') + ->setDescription($sql) + ->setOrigin('auto.db') + ->setData($data) + ); } } From 33eb62d6368e9d85cfa4a43ee42f5435576f9f01 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:09:11 +0800 Subject: [PATCH 20/64] fix(db-aspect): remove redundant variable assignment for operation --- src/sentry/src/Tracing/Aspect/DbAspect.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sentry/src/Tracing/Aspect/DbAspect.php b/src/sentry/src/Tracing/Aspect/DbAspect.php index d403ecd4f..1ab64191a 100644 --- a/src/sentry/src/Tracing/Aspect/DbAspect.php +++ b/src/sentry/src/Tracing/Aspect/DbAspect.php @@ -71,7 +71,6 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $sqlParse = SqlParser::parse($sql); $table = $sqlParse['table']; $operation = $sqlParse['operation']; - $data = [ 'coroutine.id' => Coroutine::id(), 'db.system' => $driver, From fb2c661c90a9bf25408dabaeeea7ba3ee9627ab0 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:09:46 +0800 Subject: [PATCH 21/64] fix(db-aspect): remove unused SentrySdk check to streamline process method --- src/sentry/src/Tracing/Aspect/DbAspect.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/DbAspect.php b/src/sentry/src/Tracing/Aspect/DbAspect.php index 1ab64191a..fbe78dd23 100644 --- a/src/sentry/src/Tracing/Aspect/DbAspect.php +++ b/src/sentry/src/Tracing/Aspect/DbAspect.php @@ -20,7 +20,6 @@ use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; use Psr\Container\ContainerInterface; -use Sentry\SentrySdk; use Sentry\State\Scope; use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; @@ -49,10 +48,6 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) return $proceedingJoinPoint->process(); } - if (! SentrySdk::getCurrentHub()->getSpan()) { - return $proceedingJoinPoint->process(); - } - $arguments = $proceedingJoinPoint->arguments['keys']; $poolName = (fn () => $this->poolName)->call($proceedingJoinPoint->getInstance()); /** @var \Hyperf\Pool\Pool $pool */ From e135854b7536eb6d0699e1eaa7546eba48bd2e14 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:14:20 +0800 Subject: [PATCH 22/64] fix(elasticsearch-aspect): refactor process method to improve tracing and error handling --- .../Tracing/Aspect/ElasticsearchAspect.php | 86 ++++++++++--------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php b/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php index d36cf26ad..fb66fd4df 100644 --- a/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php +++ b/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php @@ -16,6 +16,8 @@ use Hyperf\Coroutine\Coroutine; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; use Throwable; @@ -62,47 +64,49 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) return $proceedingJoinPoint->process(); } - $span = $this->startSpan( - op: 'db.elasticsearch', - description: sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName), - origin: 'auto.elasticsearch', - )?->setData([ - 'coroutine.id' => Coroutine::id(), - 'db.system' => 'elasticsearch', - 'db.operation.name' => $proceedingJoinPoint->methodName, - 'http.request.method' => '', // TODO - 'url.full' => '', // TODO - 'server.host' => '', // TODO - 'server.port' => '', // TODO - 'arguments' => json_encode($proceedingJoinPoint->arguments['keys'], JSON_UNESCAPED_UNICODE), - ]); + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint) { + $span = $scope->getSpan(); + try { + $result = $proceedingJoinPoint->process(); + if ($this->switcher->isTracingExtraTagEnabled('elasticsearch.result')) { + $span?->setData([ + 'elasticsearch.result' => json_encode($result, JSON_UNESCAPED_UNICODE), + ]); + } + return $result; + } catch (Throwable $exception) { + $span?->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.message' => $exception->getMessage(), + 'exception.code' => (string) $exception->getCode(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $span?->setData([ + 'exception.stack_trace' => (string) $exception, + ]); + } - try { - $result = $proceedingJoinPoint->process(); - if ($this->switcher->isTracingExtraTagEnabled('elasticsearch.result')) { - $span?->setData([ - 'elasticsearch.result' => json_encode($result, JSON_UNESCAPED_UNICODE), - ]); - } - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - - throw $exception; - } finally { - $span?->finish(); - } - - return $result; + throw $exception; + } + }, + SpanContext::make() + ->setOp('db.elasticsearch') + ->setDescription(sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName)) + ->setOrigin('auto.elasticsearch') + ->setData([ + 'coroutine.id' => Coroutine::id(), + 'db.system' => 'elasticsearch', + 'db.operation.name' => $proceedingJoinPoint->methodName, + 'arguments' => json_encode($proceedingJoinPoint->arguments['keys'], JSON_UNESCAPED_UNICODE), + // TODO + // 'http.request.method' => '', + // 'url.full' => '', + // 'server.host' => '', + // 'server.port' => '', + ]) + ); } } From 34f0dd6fd2e070c2b06938bc389a596c2834c938 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:20:45 +0800 Subject: [PATCH 23/64] fix(aspect): refactor tracing logic to improve error handling and streamline data setting --- src/sentry/src/Tracing/Aspect/CacheAspect.php | 56 ++++++------------- src/sentry/src/Tracing/Aspect/DbAspect.php | 32 ++--------- .../Tracing/Aspect/ElasticsearchAspect.php | 32 ++--------- .../src/Tracing/Aspect/FilesystemAspect.php | 23 +------- src/sentry/src/Tracing/Aspect/GrpcAspect.php | 23 +------- 5 files changed, 32 insertions(+), 134 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/CacheAspect.php b/src/sentry/src/Tracing/Aspect/CacheAspect.php index c6f9adf28..3e583bb64 100644 --- a/src/sentry/src/Tracing/Aspect/CacheAspect.php +++ b/src/sentry/src/Tracing/Aspect/CacheAspect.php @@ -17,8 +17,6 @@ use Hyperf\Di\Aop\ProceedingJoinPoint; use Sentry\State\Scope; use Sentry\Tracing\SpanContext; -use Sentry\Tracing\SpanStatus; -use Throwable; use function Hyperf\Tappable\tap; @@ -71,42 +69,24 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) return $this->trace( function (Scope $scope) use ($proceedingJoinPoint, $method) { - $span = $scope->getSpan(); - - try { - return tap($proceedingJoinPoint->process(), function ($result) use ($span, $method) { - $data = match ($method) { - 'get' => [ - 'cache.hit' => ! is_null($result), - 'cache.item_size' => strlen((string) json_encode($result)), - ], - 'fetch' => [ - 'cache.hit' => ($result[0] ?? false) !== false, - 'cache.item_size' => strlen((string) json_encode($result[1] ?? '')), - ], - 'getMultiple' => [ - 'cache.hit' => ! empty($result), - 'cache.item_size' => strlen((string) json_encode(array_values((array) $result))), - ], - default => [], - }; - $span?->setData($data); - }); - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - throw $exception; - } + return tap($proceedingJoinPoint->process(), function ($result) use ($method, $scope) { + $data = match ($method) { + 'get' => [ + 'cache.hit' => ! is_null($result), + 'cache.item_size' => strlen((string) json_encode($result)), + ], + 'fetch' => [ + 'cache.hit' => ($result[0] ?? false) !== false, + 'cache.item_size' => strlen((string) json_encode($result[1] ?? '')), + ], + 'getMultiple' => [ + 'cache.hit' => ! empty($result), + 'cache.item_size' => strlen((string) json_encode(array_values((array) $result))), + ], + default => [], + }; + $scope->getSpan()?->setData($data); + }); }, SpanContext::make() ->setOp($op) diff --git a/src/sentry/src/Tracing/Aspect/DbAspect.php b/src/sentry/src/Tracing/Aspect/DbAspect.php index fbe78dd23..6730bf168 100644 --- a/src/sentry/src/Tracing/Aspect/DbAspect.php +++ b/src/sentry/src/Tracing/Aspect/DbAspect.php @@ -22,8 +22,6 @@ use Psr\Container\ContainerInterface; use Sentry\State\Scope; use Sentry\Tracing\SpanContext; -use Sentry\Tracing\SpanStatus; -use Throwable; /** * @property string $poolName @@ -90,31 +88,13 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) return $this->trace( function (Scope $scope) use ($proceedingJoinPoint) { - $span = $scope->getSpan(); - try { - $result = $proceedingJoinPoint->process(); - if ($this->switcher->isTracingExtraTagEnabled('db.result')) { - $span?->setData([ - 'db.result' => json_encode($result, JSON_UNESCAPED_UNICODE), - ]); - } - return $result; - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - - throw $exception; + $result = $proceedingJoinPoint->process(); + if ($this->switcher->isTracingExtraTagEnabled('db.result')) { + $scope->getSpan()?->setData([ + 'db.result' => json_encode($result, JSON_UNESCAPED_UNICODE), + ]); } + return $result; }, SpanContext::make() ->setOp('db.sql.query') diff --git a/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php b/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php index fb66fd4df..befe58d8b 100644 --- a/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php +++ b/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php @@ -18,8 +18,6 @@ use Hyperf\Di\Aop\ProceedingJoinPoint; use Sentry\State\Scope; use Sentry\Tracing\SpanContext; -use Sentry\Tracing\SpanStatus; -use Throwable; class ElasticsearchAspect extends AbstractAspect { @@ -66,31 +64,13 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) return $this->trace( function (Scope $scope) use ($proceedingJoinPoint) { - $span = $scope->getSpan(); - try { - $result = $proceedingJoinPoint->process(); - if ($this->switcher->isTracingExtraTagEnabled('elasticsearch.result')) { - $span?->setData([ - 'elasticsearch.result' => json_encode($result, JSON_UNESCAPED_UNICODE), - ]); - } - return $result; - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - - throw $exception; + $result = $proceedingJoinPoint->process(); + if ($this->switcher->isTracingExtraTagEnabled('elasticsearch.result')) { + $scope->getSpan()?->setData([ + 'elasticsearch.result' => json_encode($result, JSON_UNESCAPED_UNICODE), + ]); } + return $result; }, SpanContext::make() ->setOp('db.elasticsearch') diff --git a/src/sentry/src/Tracing/Aspect/FilesystemAspect.php b/src/sentry/src/Tracing/Aspect/FilesystemAspect.php index e5b535889..686a07442 100644 --- a/src/sentry/src/Tracing/Aspect/FilesystemAspect.php +++ b/src/sentry/src/Tracing/Aspect/FilesystemAspect.php @@ -17,8 +17,6 @@ use Override; use Sentry\State\Scope; use Sentry\Tracing\SpanContext; -use Sentry\Tracing\SpanStatus; -use Throwable; class FilesystemAspect extends BaseFilesystemAspect { @@ -34,26 +32,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) [$op, $description, $data] = $this->getSentryMetadata($proceedingJoinPoint); return $this->trace( - function (Scope $scope) use ($proceedingJoinPoint) { - $span = $scope->getSpan(); - try { - return $proceedingJoinPoint->process(); - } catch (Throwable $exception) { - $span->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - throw $exception; - } - }, + fn (Scope $scope) => $proceedingJoinPoint->process(), SpanContext::make() ->setOp($op) ->setDescription($description) diff --git a/src/sentry/src/Tracing/Aspect/GrpcAspect.php b/src/sentry/src/Tracing/Aspect/GrpcAspect.php index 42404b977..1fbac02b9 100644 --- a/src/sentry/src/Tracing/Aspect/GrpcAspect.php +++ b/src/sentry/src/Tracing/Aspect/GrpcAspect.php @@ -20,8 +20,6 @@ use Sentry\SentrySdk; use Sentry\State\Scope; use Sentry\Tracing\SpanContext; -use Sentry\Tracing\SpanStatus; -use Throwable; class GrpcAspect extends AbstractAspect { @@ -67,26 +65,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $proceedingJoinPoint->arguments['keys']['options'] = $options; return $this->trace( - function (Scope $scope) use ($proceedingJoinPoint) { - $span = $scope->getSpan(); - try { - return $proceedingJoinPoint->process(); - } catch (Throwable $exception) { - $span->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - throw $exception; - } - }, + fn (Scope $scope) => $proceedingJoinPoint->process(), SpanContext::make() ->setOp('grpc.client') ->setDescription($method) From ee03a022ffada6ab6cb7c1bc44ab3451ad2eb981 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 13:42:05 +0800 Subject: [PATCH 24/64] fix(redis-aspect): refactor process method to enhance tracing and error handling --- .../Tracing/Aspect/KafkaProducerAspect.php | 119 +++++++++--------- src/sentry/src/Tracing/Aspect/RedisAspect.php | 52 +++----- 2 files changed, 80 insertions(+), 91 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php b/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php index 7538e8139..30b3cd75e 100644 --- a/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php +++ b/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php @@ -19,8 +19,8 @@ use Hyperf\Di\Aop\ProceedingJoinPoint; use longlang\phpkafka\Producer\ProduceMessage; use longlang\phpkafka\Protocol\RecordBatch\RecordHeader; - -use function Hyperf\Tappable\tap; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; /** * @property array $headers @@ -55,71 +55,76 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) protected function sendAsync(ProceedingJoinPoint $proceedingJoinPoint) { - $span = $this->startSpan( - op: 'queue.publish', - description: sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName), - origin: 'auto.kafka' - ); - - if (! $span) { - return $proceedingJoinPoint->process(); - } - $messageId = uniqid('kafka_', true); $destinationName = $proceedingJoinPoint->arguments['keys']['topic'] ?? 'unknown'; $bodySize = strlen($proceedingJoinPoint->arguments['keys']['value'] ?? ''); - $span->setData([ - 'messaging.system' => 'kafka', - 'messaging.operation' => 'publish', - 'messaging.message.id' => $messageId, - 'messaging.message.body.size' => $bodySize, - 'messaging.destination.name' => $destinationName, - ]); - - $carrier = Carrier::fromSpan($span) - ->with([ - 'publish_time' => microtime(true), - 'message_id' => $messageId, - 'destination_name' => $destinationName, - 'body_size' => $bodySize, - ]); - $headers = $proceedingJoinPoint->arguments['keys']['headers'] ?? []; - $headers[] = (new RecordHeader()) - ->setHeaderKey(Constants::TRACE_CARRIER) - ->setValue($carrier->toJson()); - $proceedingJoinPoint->arguments['keys']['headers'] = $headers; - - return tap($proceedingJoinPoint->process(), fn () => $span->finish()); + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint, $messageId, $destinationName, $bodySize) { + $span = $scope->getSpan(); + if ($span) { + $carrier = Carrier::fromSpan($span) + ->with([ + 'publish_time' => microtime(true), + 'message_id' => $messageId, + 'destination_name' => $destinationName, + 'body_size' => $bodySize, + ]); + $headers = $proceedingJoinPoint->arguments['keys']['headers'] ?? []; + $headers[] = (new RecordHeader()) + ->setHeaderKey(Constants::TRACE_CARRIER) + ->setValue($carrier->toJson()); + $proceedingJoinPoint->arguments['keys']['headers'] = $headers; + } + + return $proceedingJoinPoint->process(); + }, + SpanContext::make() + ->setOp('queue.publish') + ->setDescription(sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName)) + ->setOrigin('auto.kafka') + ->setData([ + [ + 'messaging.system' => 'kafka', + 'messaging.operation' => 'publish', + 'messaging.message.id' => $messageId, + 'messaging.message.body.size' => $bodySize, + 'messaging.destination.name' => $destinationName, + ], + ]) + ); } protected function sendBatchAsync(ProceedingJoinPoint $proceedingJoinPoint) { /** @var ProduceMessage[] $messages */ $messages = $proceedingJoinPoint->arguments['keys']['messages'] ?? []; - $span = $this->startSpan( - 'queue.publish', - sprintf('%s::%s', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName), - origin: 'auto.kafka' - ); - - if (! $span) { - return $proceedingJoinPoint->process(); - } - - foreach ($messages as $message) { - (function () use ($span) { - $carrier = Carrier::fromSpan($span) - ->with([ - 'publish_time' => microtime(true), - 'message_id' => uniqid('kafka_', true), - 'destination_name' => $this->getTopic(), - 'body_size' => strlen((string) $this->getValue()), - ]); - $this->headers[] = (new RecordHeader())->setHeaderKey(Constants::TRACE_CARRIER)->setValue($carrier->toJson()); - })->call($message); - } - return tap($proceedingJoinPoint->process(), fn () => $span->finish()); + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint, $messages) { + $span = $scope->getSpan(); + + if ($span) { + foreach ($messages as $message) { + (function () use ($span) { + $carrier = Carrier::fromSpan($span) + ->with([ + 'publish_time' => microtime(true), + 'message_id' => uniqid('kafka_', true), + 'destination_name' => $this->getTopic(), + 'body_size' => strlen((string) $this->getValue()), + ]); + $this->headers[] = (new RecordHeader())->setHeaderKey(Constants::TRACE_CARRIER)->setValue($carrier->toJson()); + })->call($message); + } + } + + return $proceedingJoinPoint->process(); + }, + SpanContext::make() + ->setOp('queue.publish') + ->setDescription(sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName)) + ->setOrigin('auto.kafka') + ); } } diff --git a/src/sentry/src/Tracing/Aspect/RedisAspect.php b/src/sentry/src/Tracing/Aspect/RedisAspect.php index b92b9ec8b..e477b40d1 100644 --- a/src/sentry/src/Tracing/Aspect/RedisAspect.php +++ b/src/sentry/src/Tracing/Aspect/RedisAspect.php @@ -21,8 +21,10 @@ use Hyperf\Redis\Pool\PoolFactory; use Hyperf\Redis\Redis; use Psr\Container\ContainerInterface; -use Sentry\Tracing\SpanStatus; -use Throwable; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; + +use function Hyperf\Tappable\tap; /** * @deprecated since v3.1, will be removed in v3.2. @@ -72,44 +74,26 @@ class_exists(CommandExecuted::class) 'db.redis.pool.using' => $pool->getCurrentConnections(), ]; - // rule: operation db.table - // $op = sprintf('%s %s', $arguments['name'], $arguments['arguments']['key'] ?? ''); - // $description = sprintf('%s::%s()', $proceedingJoinPoint->className, $arguments['name']); $key = $arguments['arguments'][0] ?? ''; $description = sprintf( '%s %s', strtoupper($arguments['name'] ?? ''), is_array($key) ? implode(',', $key) : $key ); - $span = $this->startSpan( - op: 'db.redis', - description: $description, - origin: 'auto.cache.redis', - )?->setData($data); - - try { - $result = $proceedingJoinPoint->process(); - - if ($this->switcher->isTracingExtraTagEnabled('redis.result')) { - $span?->setData(['redis.result' => $result]); - } - return $result; - } catch (Throwable $e) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $e::class, - 'exception.message' => $e->getMessage(), - 'exception.code' => (string) $e->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData(['exception.stack_trace' => (string) $e]); - } - - throw $e; - } finally { - $span?->finish(); - } + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint) { + tap($proceedingJoinPoint->process(), function ($result) use ($scope) { + if ($this->switcher->isTracingExtraTagEnabled('redis.result')) { + $scope->getSpan()?->setData(['redis.result' => $result]); + } + }); + }, + SpanContext::make() + ->setOp('db.redis') + ->setDescription($description) + ->setOrigin('auto.cache.redis') + ->setData($data) + ); } } From 95d5a6b4ed0f69af3c1f0e190e0d98ac5b5c243c Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:00:29 +0800 Subject: [PATCH 25/64] fix(aspect): refactor tracing data structure for Kafka, Redis, and RPC aspects to improve clarity and consistency --- .../Tracing/Aspect/KafkaProducerAspect.php | 12 +- src/sentry/src/Tracing/Aspect/RedisAspect.php | 2 +- src/sentry/src/Tracing/Aspect/RpcAspect.php | 106 ++++++------------ 3 files changed, 43 insertions(+), 77 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php b/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php index 30b3cd75e..d3ba2e5db 100644 --- a/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php +++ b/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php @@ -84,13 +84,11 @@ function (Scope $scope) use ($proceedingJoinPoint, $messageId, $destinationName, ->setDescription(sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName)) ->setOrigin('auto.kafka') ->setData([ - [ - 'messaging.system' => 'kafka', - 'messaging.operation' => 'publish', - 'messaging.message.id' => $messageId, - 'messaging.message.body.size' => $bodySize, - 'messaging.destination.name' => $destinationName, - ], + 'messaging.system' => 'kafka', + 'messaging.operation' => 'publish', + 'messaging.message.id' => $messageId, + 'messaging.message.body.size' => $bodySize, + 'messaging.destination.name' => $destinationName, ]) ); } diff --git a/src/sentry/src/Tracing/Aspect/RedisAspect.php b/src/sentry/src/Tracing/Aspect/RedisAspect.php index e477b40d1..80d5d8a28 100644 --- a/src/sentry/src/Tracing/Aspect/RedisAspect.php +++ b/src/sentry/src/Tracing/Aspect/RedisAspect.php @@ -83,7 +83,7 @@ class_exists(CommandExecuted::class) return $this->trace( function (Scope $scope) use ($proceedingJoinPoint) { - tap($proceedingJoinPoint->process(), function ($result) use ($scope) { + return tap($proceedingJoinPoint->process(), function ($result) use ($scope) { if ($this->switcher->isTracingExtraTagEnabled('redis.result')) { $scope->getSpan()?->setData(['redis.result' => $result]); } diff --git a/src/sentry/src/Tracing/Aspect/RpcAspect.php b/src/sentry/src/Tracing/Aspect/RpcAspect.php index 70932f4c6..c964cd042 100644 --- a/src/sentry/src/Tracing/Aspect/RpcAspect.php +++ b/src/sentry/src/Tracing/Aspect/RpcAspect.php @@ -24,9 +24,11 @@ use Hyperf\RpcClient; use Hyperf\Stringable\Str; use Psr\Container\ContainerInterface; +use Sentry\State\Scope; use Sentry\Tracing\Span; -use Sentry\Tracing\SpanStatus; -use Throwable; +use Sentry\Tracing\SpanContext; + +use function Hyperf\Tappable\tap; /** * @property string $prototype @@ -35,9 +37,11 @@ class RpcAspect extends AbstractAspect { use SpanStarter; - public const SPAN = 'sentry.tracing.rpc.span'; + // public const SPAN = 'sentry.tracing.rpc.span'; + + // protected const DATA = 'sentry.tracing.rpc.data'; - protected const DATA = 'sentry.tracing.rpc.data'; + protected const SPAN_CONTEXT = 'sentry.tracing.rpc.span_context'; public array $classes = [ RpcClient\AbstractServiceClient::class . '::__generateRpcPath', @@ -79,79 +83,43 @@ private function handleGenerateRpcPath(ProceedingJoinPoint $proceedingJoinPoint) default => 'rpc', }; - // $package.$service/$path - $op = sprintf('%s.%s/%s', $package, $service, $path); - $span = $this->startSpan( - op: $op, - description: $path, - origin: 'auto.rpc', - ); - - if (! $span) { - return $path; - } - - $data = [ - 'coroutine.id' => Coroutine::id(), - 'rpc.system' => $system, - 'rpc.method' => $proceedingJoinPoint->arguments['keys']['methodName'] ?? '', - 'rpc.service' => $service, - ]; - - $span->setData($data); - - Context::set(static::DATA, $data); // @deprecated since v3.1, will be removed in v3.2 - Context::set(static::SPAN, $span); - - if ($this->container->has(Rpc\Context::class)) { - $this->container->get(Rpc\Context::class) - ->set(Constants::TRACE_CARRIER, Carrier::fromSpan($span)->toJson()); - } + Context::set(static::SPAN_CONTEXT, SpanContext::make() + ->setOp(sprintf('%s.%s/%s', $package, $service, $path)) + ->setDescription($path) + ->setOrigin('auto.rpc') + ->setData([ + 'coroutine.id' => Coroutine::id(), + 'rpc.system' => $system, + 'rpc.service' => $service, + 'rpc.method' => $proceedingJoinPoint->arguments['keys']['methodName'] ?? '', + ])); return $path; } private function handleSend(ProceedingJoinPoint $proceedingJoinPoint) { - // TODO - // 'server.address' => '', - // 'server.port' => '', - - /** @var null|Span $span */ - $span = Context::get(static::SPAN); - - $span?->setData((array) Context::get(static::DATA, [])); + /** @var null|SpanContext $spanContext */ + $spanContext = Context::get(static::SPAN_CONTEXT); - if ($this->container->has(Rpc\Context::class)) { - $span?->setData(['rpc.context' => $this->container->get(Rpc\Context::class)->getData()]); + if (! $spanContext) { + return $proceedingJoinPoint->process(); } - try { - $result = $proceedingJoinPoint->process(); - - if ($this->switcher->isTracingExtraTagEnabled('rpc.result')) { - $span?->setData(['rpc.result' => $result]); - } - - return $result; - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData(['exception.stack_trace' => (string) $exception]); - } - - throw $exception; - } finally { - $span?->finish(); - - Context::destroy(static::SPAN); - Context::destroy(static::DATA); - } + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint) { + $span = $scope->getSpan(); + if ($span && $this->container->has(Rpc\Context::class)) { + $this->container->get(Rpc\Context::class) + ->set(Constants::TRACE_CARRIER, Carrier::fromSpan($span)->toJson()); + } + return tap($proceedingJoinPoint->process(), function ($result) use ($span) { + if ($this->switcher->isTracingExtraTagEnabled('rpc.result')) { + $span?->setData(['rpc.result' => $result]); + } + }); + }, + $spanContext + ); } } From 0ed7db8d8b61682253c31044d97facb0ee190f49 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:02:03 +0800 Subject: [PATCH 26/64] fix(aspect): update span context reference in GuzzleHttpClientAspect and refactor RpcAspect for consistency --- src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php | 2 +- src/sentry/src/Tracing/Aspect/RpcAspect.php | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php index f75c35627..e1f355fff 100644 --- a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php +++ b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php @@ -47,7 +47,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) { if ( ! $this->switcher->isTracingSpanEnabled('guzzle') - || Context::get(RpcAspect::SPAN) // If the parent span is not exists or the parent span is belongs to rpc, then skip. + || Context::get(RpcAspect::SPAN_CONTEXT) // If the parent span is not exists or the parent span is belongs to rpc, then skip. ) { return $proceedingJoinPoint->process(); } diff --git a/src/sentry/src/Tracing/Aspect/RpcAspect.php b/src/sentry/src/Tracing/Aspect/RpcAspect.php index c964cd042..b93453ada 100644 --- a/src/sentry/src/Tracing/Aspect/RpcAspect.php +++ b/src/sentry/src/Tracing/Aspect/RpcAspect.php @@ -25,7 +25,6 @@ use Hyperf\Stringable\Str; use Psr\Container\ContainerInterface; use Sentry\State\Scope; -use Sentry\Tracing\Span; use Sentry\Tracing\SpanContext; use function Hyperf\Tappable\tap; @@ -37,11 +36,7 @@ class RpcAspect extends AbstractAspect { use SpanStarter; - // public const SPAN = 'sentry.tracing.rpc.span'; - - // protected const DATA = 'sentry.tracing.rpc.data'; - - protected const SPAN_CONTEXT = 'sentry.tracing.rpc.span_context'; + public const SPAN_CONTEXT = 'sentry.tracing.rpc.span_context'; public array $classes = [ RpcClient\AbstractServiceClient::class . '::__generateRpcPath', From 96a9a8cd6d9a89af3cae6730a61b826551413685 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:07:01 +0800 Subject: [PATCH 27/64] fix(aspect): refactor TraceAnnotationAspect to improve span handling and streamline tracing logic --- .../Tracing/Aspect/TraceAnnotationAspect.php | 65 +++++++------------ 1 file changed, 23 insertions(+), 42 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/TraceAnnotationAspect.php b/src/sentry/src/Tracing/Aspect/TraceAnnotationAspect.php index ac367227e..02dd51ad4 100644 --- a/src/sentry/src/Tracing/Aspect/TraceAnnotationAspect.php +++ b/src/sentry/src/Tracing/Aspect/TraceAnnotationAspect.php @@ -17,9 +17,10 @@ use Hyperf\Coroutine\Coroutine; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; -use Sentry\SentrySdk; -use Sentry\Tracing\SpanStatus; -use Throwable; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; + +use function Hyperf\Tappable\tap; class TraceAnnotationAspect extends AbstractAspect { @@ -38,15 +39,14 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $metadata = $proceedingJoinPoint->getAnnotationMetadata(); /** @var null|Trace $annotation */ $annotation = $metadata->method[Trace::class] ?? null; - $parent = SentrySdk::getCurrentHub()->getSpan(); - if (! $annotation || ! $parent || ! $parent->getSampled()) { + if (! $annotation) { return $proceedingJoinPoint->process(); } $data = ['coroutine.id' => Coroutine::id()]; - $methodName = $proceedingJoinPoint->methodName; + if (in_array($methodName, ['__call', '__callStatic'])) { $methodName = $proceedingJoinPoint->arguments['keys']['name'] ?? $proceedingJoinPoint->methodName; $data['annotation.arguments'] = $proceedingJoinPoint->arguments['keys']['arguments'] ?? $proceedingJoinPoint->arguments['keys']; @@ -54,41 +54,22 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $data['annotation.arguments'] = $proceedingJoinPoint->arguments['keys']; } - $span = $this->startSpan( - op: $annotation->op ?? 'method', - description: $annotation->description ?? sprintf( - '%s::%s()', - $proceedingJoinPoint->className, - $methodName - ), - asParent: true - )?->setData($data); - - try { - $result = $proceedingJoinPoint->process(); - - if ($this->switcher->isTracingExtraTagEnabled('annotation.result')) { - $span?->setData(['annotation.result' => $result]); - } - - return $result; - } catch (Throwable $exception) { - $span?->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData(['exception.stack_trace' => (string) $exception]); - } - throw $exception; - } finally { - $span?->finish(); - - // Restore parent span - SentrySdk::getCurrentHub()->setSpan($parent); - } + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint) { + return tap($proceedingJoinPoint->process(), function ($result) use ($scope) { + if ($this->switcher->isTracingExtraTagEnabled('annotation.result')) { + $scope->getSpan()?->setData(['annotation.result' => $result]); + } + }); + }, + SpanContext::make() + ->setOp($annotation->op ?? 'method') + ->setDescription($annotation->description ?? sprintf( + '%s::%s()', + $proceedingJoinPoint->className, + $methodName + )) + ->setData($data) + ); } } From c1d83d3f9ef4a5627e79e969acc2b157334655d4 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:19:36 +0800 Subject: [PATCH 28/64] fix(aspect): refactor EventHandleListener to enhance span handling and streamline tracing logic --- .../Tracing/Listener/EventHandleListener.php | 79 ++++++++++--------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 3af9f3549..771e59168 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -168,9 +168,6 @@ private function handleDbQueryExecuted(DbEvent\QueryExecuted $event): void if (! $this->switcher->isTracingSpanEnabled('sql_queries')) { return; } - if (! SentrySdk::getCurrentHub()->getSpan()) { - return; - } $data = [ 'coroutine.id' => Coroutine::id(), @@ -204,13 +201,16 @@ private function handleDbQueryExecuted(DbEvent\QueryExecuted $event): void $startTimestamp = microtime(true) - $event->time / 1000; - $this->startSpan( - op: 'db.sql.query', - description: $event->sql, - origin: 'auto.db' - )?->setData($data) - ->setStartTimestamp($startTimestamp) - ->finish($startTimestamp + $event->time / 1000); + $this->trace( + fn () => null, + SpanContext::make() + ->setOp('db.sql.query') + ->setDescription($event->sql) + ->setOrigin('auto.db') + ->setStartTimestamp($startTimestamp) + ->setData($data) + ->setEndTimestamp($startTimestamp + $event->time / 1000) + ); } private function handleDbTransactionBeginning(DbEvent\TransactionBeginning $event): void @@ -218,20 +218,21 @@ private function handleDbTransactionBeginning(DbEvent\TransactionBeginning $even if (! $this->switcher->isTracingSpanEnabled('sql_transactions')) { return; } - if (! SentrySdk::getCurrentHub()->getSpan()) { - return; - } - $this->startSpan( - op: 'db.transaction', - description: 'BEGIN', - origin: 'auto.db' - )?->setData([ - 'coroutine.id' => Coroutine::id(), - 'db.system' => $event->connection->getDriverName(), - 'db.name' => $event->connection->getDatabaseName(), - 'db.pool.name' => $event->connectionName, - ]); + $this->trace( + fn () => null, + SpanContext::make() + ->setOp('db.transaction') + ->setDescription('BEGIN') + ->setOrigin('auto.db') + ->setStartTimestamp(microtime(true)) + ->setData([ + 'coroutine.id' => Coroutine::id(), + 'db.system' => $event->connection->getDriverName(), + 'db.name' => $event->connection->getDatabaseName(), + 'db.pool.name' => $event->connectionName, + ]) + ); } private function handleDbTransactionCommitted(DbEvent\TransactionCommitted $event): void @@ -317,12 +318,18 @@ private function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Reques $transaction->setData($data); - $span = $this->startSpan( - op: 'request.received', - description: 'request.received', - origin: 'auto.request.received', - asParent: true - ); + $spanContext = SpanContext::make() + ->setOp('request.received') + ->setDescription('request.received') + ->setData([ + 'coroutine.id' => Coroutine::id(), + ]) + ->setStatus(SpanStatus::ok()) + ->setStartTimestamp(microtime(true)); + + $span = $transaction->startChild($spanContext); + + SentrySdk::getCurrentHub()->setSpan($span); defer(function () use ($transaction, $span) { // Make sure the span is finished after the request is handled @@ -338,12 +345,12 @@ private function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Reques private function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\RequestHandled $event): void { - $transaction = SentrySdk::getCurrentHub()->getTransaction(); + $span = SentrySdk::getCurrentHub()->getSpan(); if ( - ! $transaction - || ! $transaction->getSampled() - || ! $traceId = (string) $transaction->getTraceId() + ! $span + || ! $span->getSampled() + || ! $traceId = (string) $span->getTraceId() ) { return; } @@ -356,10 +363,10 @@ private function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\RequestH $event->response->setHeader('sentry-trace-id', $traceId); } - $transaction->setHttpStatus($event->response->getStatusCode()); + $span->setHttpStatus($event->response->getStatusCode()); if ($exception = $event->getThrowable()) { - $transaction->setStatus(SpanStatus::internalError()) + $span->setStatus(SpanStatus::internalError()) ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, @@ -367,7 +374,7 @@ private function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\RequestH 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $transaction->setData([ + $span->setData([ 'exception.stack_trace' => (string) $exception, ]); } From 30214a62fd76b0c673b883a46a2fcf9eb459e0e7 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:20:43 +0800 Subject: [PATCH 29/64] fix(aspect): ensure span is finished correctly in EventHandleListener --- src/sentry/src/Tracing/Listener/EventHandleListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 771e59168..df5c437e4 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -333,7 +333,7 @@ private function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Reques defer(function () use ($transaction, $span) { // Make sure the span is finished after the request is handled - $span?->finish(); + $span->finish(); // Make sure the transaction is finished after the request is handled SentrySdk::getCurrentHub()->setSpan($transaction); From 3f175aa56ad10f219657534a3825dff8958aaced Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:40:55 +0800 Subject: [PATCH 30/64] fix(aspect): refactor GuzzleHttpClientAspect to improve span handling and trace context injection --- .../Tracing/Aspect/GuzzleHttpClientAspect.php | 207 +++++++++--------- 1 file changed, 105 insertions(+), 102 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php index e1f355fff..442f51222 100644 --- a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php +++ b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php @@ -22,6 +22,8 @@ use Hyperf\Di\Aop\ProceedingJoinPoint; use Psr\Container\ContainerInterface; use Psr\Http\Message\RequestInterface; +use Sentry\State\Scope; +use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; use Throwable; @@ -70,117 +72,118 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) return $proceedingJoinPoint->process(); } - // Inject trace context && Start span - $span = $this->startSpan( - op: 'http.client', - description: $request->getMethod() . ' ' . (string) $request->getUri(), - origin: 'auto.http.client', - ); + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint, $options, $guzzleConfig) { + $span = $scope->getSpan(); - if (! $span) { - return $proceedingJoinPoint->process(); - } + if (! $span) { + return $proceedingJoinPoint->process(); + } - // Inject trace context - $options['headers'] = array_replace($options['headers'] ?? [], [ - 'sentry-trace' => $span->toTraceparent(), - 'baggage' => $span->toBaggage(), - 'traceparent' => $span->toW3CTraceparent(), - ]); - - // Override the headers - $proceedingJoinPoint->arguments['keys']['options']['headers'] = $options['headers']; - $onStats = $options['on_stats'] ?? null; - - // Add or override the on_stats option to record the request duration. - $proceedingJoinPoint->arguments['keys']['options']['on_stats'] = function (TransferStats $stats) use ($options, $guzzleConfig, $onStats, $span) { - $request = $stats->getRequest(); - $uri = $request->getUri(); - $span->setData([ - // See: https://develop.sentry.dev/sdk/performance/span-data-conventions/#http - 'http.query' => $uri->getQuery(), - 'http.fragment' => $uri->getFragment(), - 'http.request.method' => $request->getMethod(), - 'http.request.body.size' => strlen($options['body'] ?? ''), - 'http.request.full_url' => (string) $request->getUri(), - 'http.request.path' => $request->getUri()->getPath(), - 'http.request.scheme' => $request->getUri()->getScheme(), - 'http.request.host' => $request->getUri()->getHost(), - 'http.request.port' => $request->getUri()->getPort(), - 'http.request.user_agent' => $request->getHeaderLine('User-Agent'), // updated key for consistency - 'http.request.headers' => $request->getHeaders(), - // Other - 'coroutine.id' => Coroutine::id(), - 'http.system' => 'guzzle', - 'http.guzzle.config' => $guzzleConfig, - 'http.guzzle.options' => $options ?? [], - 'duration' => $stats->getTransferTime() * 1000, // in milliseconds - ]); - - if ($response = $stats->getResponse()) { - $span->setData([ - 'http.response.status_code' => $response->getStatusCode(), - 'http.response.reason' => $response->getReasonPhrase(), - 'http.response.headers' => $response->getHeaders(), - 'http.response.body.size' => $response->getBody()->getSize() ?? 0, - 'http.response_content_length' => $response->getHeaderLine('Content-Length'), - 'http.decoded_response_content_length' => $response->getHeaderLine('X-Decoded-Content-Length'), - 'http.response_transfer_size' => $response->getHeaderLine('Content-Length'), + // Inject trace context + $options['headers'] = array_replace($options['headers'] ?? [], [ + 'sentry-trace' => $span->toTraceparent(), + 'baggage' => $span->toBaggage(), + 'traceparent' => $span->toW3CTraceparent(), ]); - if ($this->switcher->isTracingExtraTagEnabled('http.response.body.contents')) { - $isTextual = \preg_match( - '/^(text\/|application\/(json|xml|x-www-form-urlencoded))/i', - $response->getHeaderLine('Content-Type') - ) === 1; - $body = $response->getBody(); + // Override the headers + $proceedingJoinPoint->arguments['keys']['options']['headers'] = $options['headers']; + $onStats = $options['on_stats'] ?? null; - if ($isTextual && $body->isSeekable()) { - $pos = $body->tell(); - $span->setData([ - 'http.response.body.contents' => \GuzzleHttp\Psr7\Utils::copyToString($body, 8192), // 8KB 上限 - ]); - $body->seek($pos); - } else { - $span->setData(['http.response.body.contents' => '[binary omitted]']); - } - } - - $span->setStatus(SpanStatus::createFromHttpStatusCode($response->getStatusCode())); - - if ($response->getStatusCode() >= 400 && $response->getStatusCode() < 600) { - $span->setTags([ - 'error' => 'true', - 'http.response.reason' => $response->getReasonPhrase(), - ]); - } - } - - if ($stats->getHandlerErrorData()) { - $exception = $stats->getHandlerErrorData() instanceof Throwable - ? $stats->getHandlerErrorData() - : new Error(); - $span->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.code' => (string) $exception->getCode(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + // Add or override the on_stats option to record the request duration. + $proceedingJoinPoint->arguments['keys']['options']['on_stats'] = function (TransferStats $stats) use ($options, $guzzleConfig, $onStats, $span) { + $request = $stats->getRequest(); + $uri = $request->getUri(); $span->setData([ - 'exception.message' => $exception->getMessage(), - 'exception.stack_trace' => (string) $exception, + // See: https://develop.sentry.dev/sdk/performance/span-data-conventions/#http + 'http.query' => $uri->getQuery(), + 'http.fragment' => $uri->getFragment(), + 'http.request.method' => $request->getMethod(), + 'http.request.body.size' => strlen($options['body'] ?? ''), + 'http.request.full_url' => (string) $request->getUri(), + 'http.request.path' => $request->getUri()->getPath(), + 'http.request.scheme' => $request->getUri()->getScheme(), + 'http.request.host' => $request->getUri()->getHost(), + 'http.request.port' => $request->getUri()->getPort(), + 'http.request.user_agent' => $request->getHeaderLine('User-Agent'), // updated key for consistency + 'http.request.headers' => $request->getHeaders(), + // Other + 'coroutine.id' => Coroutine::id(), + 'http.system' => 'guzzle', + 'http.guzzle.config' => $guzzleConfig, + 'http.guzzle.options' => $options ?? [], + 'duration' => $stats->getTransferTime() * 1000, // in milliseconds ]); - } - } - $span->finish(); + if ($response = $stats->getResponse()) { + $span->setData([ + 'http.response.status_code' => $response->getStatusCode(), + 'http.response.reason' => $response->getReasonPhrase(), + 'http.response.headers' => $response->getHeaders(), + 'http.response.body.size' => $response->getBody()->getSize() ?? 0, + 'http.response_content_length' => $response->getHeaderLine('Content-Length'), + 'http.decoded_response_content_length' => $response->getHeaderLine('X-Decoded-Content-Length'), + 'http.response_transfer_size' => $response->getHeaderLine('Content-Length'), + ]); + + if ($this->switcher->isTracingExtraTagEnabled('http.response.body.contents')) { + $isTextual = \preg_match( + '/^(text\/|application\/(json|xml|x-www-form-urlencoded))/i', + $response->getHeaderLine('Content-Type') + ) === 1; + $body = $response->getBody(); + + if ($isTextual && $body->isSeekable()) { + $pos = $body->tell(); + $span->setData([ + 'http.response.body.contents' => \GuzzleHttp\Psr7\Utils::copyToString($body, 8192), // 8KB 上限 + ]); + $body->seek($pos); + } else { + $span->setData(['http.response.body.contents' => '[binary omitted]']); + } + } + + $span->setStatus(SpanStatus::createFromHttpStatusCode($response->getStatusCode())); + + if ($response->getStatusCode() >= 400 && $response->getStatusCode() < 600) { + $span->setTags([ + 'error' => 'true', + 'http.response.reason' => $response->getReasonPhrase(), + ]); + } + } - if (is_callable($onStats)) { - ($onStats)($stats); - } - }; + if ($stats->getHandlerErrorData()) { + $exception = $stats->getHandlerErrorData() instanceof Throwable + ? $stats->getHandlerErrorData() + : new Error(); + $span->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.code' => (string) $exception->getCode(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $span->setData([ + 'exception.message' => $exception->getMessage(), + 'exception.stack_trace' => (string) $exception, + ]); + } + } - return $proceedingJoinPoint->process(); + if (is_callable($onStats)) { + ($onStats)($stats); + } + }; + + return $proceedingJoinPoint->process(); + }, + SpanContext::make() + ->setOp('http.client') + ->setDescription($request->getMethod() . ' ' . (string) $request->getUri()) + ->setOrigin('auto.http.client') + ); } } From 596eae14182af8ef92ffa49353ecaf5bc8b7a64e Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:46:17 +0800 Subject: [PATCH 31/64] fix(aspect): refactor CoroutineAspect to improve span handling and ensure proper transaction management fix(span): mark startSpan method as deprecated and recommend using trace() instead --- .../src/Tracing/Aspect/CoroutineAspect.php | 33 ++++++++++++------- src/sentry/src/Tracing/SpanStarter.php | 3 ++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index b25c40349..5bed256f3 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -18,6 +18,7 @@ use Hyperf\Di\Aop\ProceedingJoinPoint; use Hyperf\Engine\Coroutine as Co; use Sentry\SentrySdk; +use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; use Throwable; @@ -56,19 +57,24 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) return $proceedingJoinPoint->process(); } - $keys = $this->keys; - $callable = $proceedingJoinPoint->arguments['keys']['callable']; - $parent = $this->startSpan( - op: 'coroutine.create', - description: $callingOnFunction, - origin: 'auto.coroutine', - )?->setOrigin('auto.coroutine'); + $transaction = SentrySdk::getCurrentHub()->getTransaction(); - if (! $parent) { + if (! $transaction || ! $transaction->getSampled()) { return $proceedingJoinPoint->process(); } - $parent->setData(['coroutine.id' => $cid = Co::id()]); + $parent = $transaction->startChild( + SpanContext::make() + ->setOp('coroutine.create') + ->setDescription($callingOnFunction) + ->setOrigin('auto.coroutine') + ->setData(['coroutine.id' => Co::id()]) + ); + SentrySdk::getCurrentHub()->setSpan($parent); + + $cid = Co::id(); + $keys = $this->keys; + $callable = $proceedingJoinPoint->arguments['keys']['callable']; $proceedingJoinPoint->arguments['keys']['callable'] = function () use ($callable, $parent, $callingOnFunction, $cid, $keys) { $from = Co::getContextFor($cid); @@ -113,8 +119,11 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) } }; - $parent->finish(); - - return $proceedingJoinPoint->process(); + try { + return $proceedingJoinPoint->process(); + } finally { + $parent->finish(); + SentrySdk::getCurrentHub()->setSpan($transaction); + } } } diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index 0e1dc71b0..3320f0d34 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -76,6 +76,9 @@ protected function trace(callable $trace, SpanContext $context) }); } + /** + * @deprecated since v3.1, will be removed in v3.2, use trace() instead. + */ protected function startSpan( ?string $op = null, ?string $description = null, From 34ff81f4de271f872dc678f6c636682dd10f13b6 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:51:29 +0800 Subject: [PATCH 32/64] Add comments to clarify coroutine tracing logic Added explanatory comments in CoroutineAspect to clarify the logic for tracing coroutine creation and context transfer. This improves code readability and maintainability. Co-Authored-By: Deeka Wong <8337659+huangdijia@users.noreply.github.com> --- src/sentry/src/Tracing/Aspect/CoroutineAspect.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index 5bed256f3..a6f2a1945 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -53,16 +53,20 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $callingOnFunction = CoroutineBacktraceHelper::foundCallingOnFunction(); + // Only trace the top-level coroutine creation. if (! $callingOnFunction) { return $proceedingJoinPoint->process(); } + // If there's no active transaction, skip tracing. $transaction = SentrySdk::getCurrentHub()->getTransaction(); + // If there's no active transaction, skip tracing. if (! $transaction || ! $transaction->getSampled()) { return $proceedingJoinPoint->process(); } + // Start a span for the coroutine creation. $parent = $transaction->startChild( SpanContext::make() ->setOp('coroutine.create') @@ -76,6 +80,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $keys = $this->keys; $callable = $proceedingJoinPoint->arguments['keys']['callable']; + // Transfer the Sentry context to the new coroutine. $proceedingJoinPoint->arguments['keys']['callable'] = function () use ($callable, $parent, $callingOnFunction, $cid, $keys) { $from = Co::getContextFor($cid); $current = Co::getContextFor(); From 17b07b0ed24f856d5d4acb6b71eec17b01667afc Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:54:09 +0800 Subject: [PATCH 33/64] fix(dependencies): update sentry/sentry to version ^4.16.0 --- composer.json | 2 +- src/sentry/composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 1dd326c0b..38708cb61 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "psr/http-factory-implementation": "*", "psy/psysh": "^0.10.0 || ^0.11.0", "ramsey/uuid": "^4.7", - "sentry/sentry": "^4.15.0", + "sentry/sentry": "^4.16.0", "symfony/console": "^5.3 || ^6.0 || ^7.0", "symfony/http-foundation": "^5.3 || ^6.0 || ^7.0", "symfony/polyfill-php84": "^1.33", diff --git a/src/sentry/composer.json b/src/sentry/composer.json index 0a4fe819f..d797f834c 100644 --- a/src/sentry/composer.json +++ b/src/sentry/composer.json @@ -33,7 +33,7 @@ "hyperf/http-server": "~3.1.0", "hyperf/support": "~3.1.0", "hyperf/tappable": "~3.1.0", - "sentry/sentry": "^4.15.0", + "sentry/sentry": "^4.16.0", "symfony/polyfill-php85": "^1.33" }, "suggest": { From c7e4d8018215f69de787f5faa4bed59416bd68c1 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:01:21 +0800 Subject: [PATCH 34/64] fix(aspect): add null check for span in AmqpProducerAspect to prevent potential errors --- .../src/Tracing/Aspect/AmqpProducerAspect.php | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php b/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php index 951c80656..9dd7ac625 100644 --- a/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php +++ b/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php @@ -81,16 +81,18 @@ protected function handleProduceMessage(ProceedingJoinPoint $proceedingJoinPoint return $this->trace( function (Scope $scope) use ($proceedingJoinPoint, $producerMessage, $messageId, $destinationName, $bodySize) { $span = $scope->getSpan(); - $carrier = Carrier::fromSpan($span)->with([ - 'publish_time' => microtime(true), - 'message_id' => $messageId, - 'destination_name' => $destinationName, - 'body_size' => $bodySize, - ]); - (function () use ($carrier) { - $this->properties['application_headers'] ??= new AMQPTable(); - $this->properties['application_headers']->set(Constants::TRACE_CARRIER, $carrier->toJson()); - })->call($producerMessage); + if ($span) { + $carrier = Carrier::fromSpan($span)->with([ + 'publish_time' => microtime(true), + 'message_id' => $messageId, + 'destination_name' => $destinationName, + 'body_size' => $bodySize, + ]); + (function () use ($carrier) { + $this->properties['application_headers'] ??= new AMQPTable(); + $this->properties['application_headers']->set(Constants::TRACE_CARRIER, $carrier->toJson()); + })->call($producerMessage); + } return $proceedingJoinPoint->process(); }, From 86a056d73699e6c978a0ddea9eabe7b9483598e0 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:03:08 +0800 Subject: [PATCH 35/64] fix(aspect): cast Elasticsearch result to string before setting as span data --- src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php b/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php index befe58d8b..db59bdbb7 100644 --- a/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php +++ b/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php @@ -67,7 +67,7 @@ function (Scope $scope) use ($proceedingJoinPoint) { $result = $proceedingJoinPoint->process(); if ($this->switcher->isTracingExtraTagEnabled('elasticsearch.result')) { $scope->getSpan()?->setData([ - 'elasticsearch.result' => json_encode($result, JSON_UNESCAPED_UNICODE), + 'elasticsearch.result' => (string) json_encode($result, JSON_UNESCAPED_UNICODE), ]); } return $result; From 070aa0d0896b38b86c87338ac2fbc59a17ccafcd Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:04:03 +0800 Subject: [PATCH 36/64] fix(aspect): cast arguments to string in ElasticsearchAspect for proper logging --- src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php b/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php index db59bdbb7..473a529e8 100644 --- a/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php +++ b/src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php @@ -80,7 +80,7 @@ function (Scope $scope) use ($proceedingJoinPoint) { 'coroutine.id' => Coroutine::id(), 'db.system' => 'elasticsearch', 'db.operation.name' => $proceedingJoinPoint->methodName, - 'arguments' => json_encode($proceedingJoinPoint->arguments['keys'], JSON_UNESCAPED_UNICODE), + 'arguments' => (string) json_encode($proceedingJoinPoint->arguments['keys'], JSON_UNESCAPED_UNICODE), // TODO // 'http.request.method' => '', // 'url.full' => '', From 6bbd4b5c466282f5fcb54bd29fb4c6b53f9e2a59 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:09:51 +0800 Subject: [PATCH 37/64] fix(aspect): add error handling and cleanup for RPC tracing in RpcAspect --- src/sentry/src/Tracing/Aspect/RpcAspect.php | 32 ++++++++++++--------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/RpcAspect.php b/src/sentry/src/Tracing/Aspect/RpcAspect.php index b93453ada..27188f722 100644 --- a/src/sentry/src/Tracing/Aspect/RpcAspect.php +++ b/src/sentry/src/Tracing/Aspect/RpcAspect.php @@ -101,20 +101,24 @@ private function handleSend(ProceedingJoinPoint $proceedingJoinPoint) return $proceedingJoinPoint->process(); } - return $this->trace( - function (Scope $scope) use ($proceedingJoinPoint) { - $span = $scope->getSpan(); - if ($span && $this->container->has(Rpc\Context::class)) { - $this->container->get(Rpc\Context::class) - ->set(Constants::TRACE_CARRIER, Carrier::fromSpan($span)->toJson()); - } - return tap($proceedingJoinPoint->process(), function ($result) use ($span) { - if ($this->switcher->isTracingExtraTagEnabled('rpc.result')) { - $span?->setData(['rpc.result' => $result]); + try { + return $this->trace( + function (Scope $scope) use ($proceedingJoinPoint) { + $span = $scope->getSpan(); + if ($span && $this->container->has(Rpc\Context::class)) { + $this->container->get(Rpc\Context::class) + ->set(Constants::TRACE_CARRIER, Carrier::fromSpan($span)->toJson()); } - }); - }, - $spanContext - ); + return tap($proceedingJoinPoint->process(), function ($result) use ($span) { + if ($this->switcher->isTracingExtraTagEnabled('rpc.result')) { + $span?->setData(['rpc.result' => $result]); + } + }); + }, + $spanContext + ); + } finally { + Context::destroy(static::SPAN_CONTEXT); + } } } From 64b1a7cf9facecac6fd54ae18d60b5059a28210a Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:11:02 +0800 Subject: [PATCH 38/64] fix(aspect): simplify tracing span check in GuzzleHttpClientAspect --- src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php index 442f51222..d22f95643 100644 --- a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php +++ b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php @@ -47,10 +47,7 @@ public function __construct( public function process(ProceedingJoinPoint $proceedingJoinPoint) { - if ( - ! $this->switcher->isTracingSpanEnabled('guzzle') - || Context::get(RpcAspect::SPAN_CONTEXT) // If the parent span is not exists or the parent span is belongs to rpc, then skip. - ) { + if (! $this->switcher->isTracingSpanEnabled('guzzle')) { return $proceedingJoinPoint->process(); } From 153a5f4e53015532d9eb64334204afd596338576 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:12:05 +0800 Subject: [PATCH 39/64] fix(aspect): add exception message to span tags in GuzzleHttpClientAspect --- src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php index d22f95643..e6162ce51 100644 --- a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php +++ b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php @@ -160,11 +160,11 @@ function (Scope $scope) use ($proceedingJoinPoint, $options, $guzzleConfig) { ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, + 'exception.message' => $exception->getMessage(), 'exception.code' => (string) $exception->getCode(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { $span->setData([ - 'exception.message' => $exception->getMessage(), 'exception.stack_trace' => (string) $exception, ]); } From 38a04fe92d8fb164ac7ab5038e2a95f9dc679d9e Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:15:11 +0800 Subject: [PATCH 40/64] fix(aspect): refactor HTTP status handling in GuzzleHttpClientAspect and EventHandleListener --- src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php | 4 +++- src/sentry/src/Tracing/Listener/EventHandleListener.php | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php index e6162ce51..27a3e58b2 100644 --- a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php +++ b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php @@ -142,7 +142,9 @@ function (Scope $scope) use ($proceedingJoinPoint, $options, $guzzleConfig) { } } - $span->setStatus(SpanStatus::createFromHttpStatusCode($response->getStatusCode())); + $span->setStatus( + SpanStatus::createFromHttpStatusCode($response->getStatusCode()) + ); if ($response->getStatusCode() >= 400 && $response->getStatusCode() < 600) { $span->setTags([ diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index df5c437e4..fa0b199d1 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -363,7 +363,10 @@ private function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\RequestH $event->response->setHeader('sentry-trace-id', $traceId); } - $span->setHttpStatus($event->response->getStatusCode()); + // $span->setHttpStatus($event->response->getStatusCode()); + $span->setStatus( + SpanStatus::createFromHttpStatusCode($event->response->getStatusCode()) + ); if ($exception = $event->getThrowable()) { $span->setStatus(SpanStatus::internalError()) From 5d3ebb857e93dc03574b1d0a925635f1acb9719c Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:25:34 +0800 Subject: [PATCH 41/64] fix(aspect): inject RPC context data and tracing carrier into span in RpcAspect --- src/sentry/src/Tracing/Aspect/RpcAspect.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sentry/src/Tracing/Aspect/RpcAspect.php b/src/sentry/src/Tracing/Aspect/RpcAspect.php index 27188f722..6349070d1 100644 --- a/src/sentry/src/Tracing/Aspect/RpcAspect.php +++ b/src/sentry/src/Tracing/Aspect/RpcAspect.php @@ -106,6 +106,11 @@ private function handleSend(ProceedingJoinPoint $proceedingJoinPoint) function (Scope $scope) use ($proceedingJoinPoint) { $span = $scope->getSpan(); if ($span && $this->container->has(Rpc\Context::class)) { + // Inject the RPC context data into span. + $span->setData([ + 'rpc.context' => $this->container->get(Rpc\Context::class)->getData(), + ]); + // Inject the tracing carrier into RPC context. $this->container->get(Rpc\Context::class) ->set(Constants::TRACE_CARRIER, Carrier::fromSpan($span)->toJson()); } From 4196333ecfcceaaf33d8762895c9ccc97ec4e6d0 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:26:04 +0800 Subject: [PATCH 42/64] fix(aspect): ensure span is valid before setting RPC result data in RpcAspect --- src/sentry/src/Tracing/Aspect/RpcAspect.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/RpcAspect.php b/src/sentry/src/Tracing/Aspect/RpcAspect.php index 6349070d1..a2526cb2a 100644 --- a/src/sentry/src/Tracing/Aspect/RpcAspect.php +++ b/src/sentry/src/Tracing/Aspect/RpcAspect.php @@ -115,8 +115,8 @@ function (Scope $scope) use ($proceedingJoinPoint) { ->set(Constants::TRACE_CARRIER, Carrier::fromSpan($span)->toJson()); } return tap($proceedingJoinPoint->process(), function ($result) use ($span) { - if ($this->switcher->isTracingExtraTagEnabled('rpc.result')) { - $span?->setData(['rpc.result' => $result]); + if ($span && $this->switcher->isTracingExtraTagEnabled('rpc.result')) { + $span->setData(['rpc.result' => $result]); } }); }, From 2be7de258f8096fc5b8449f2ea740c09344ab2f0 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 17:06:21 +0800 Subject: [PATCH 43/64] fix(aspect): move exception message to span data in CoroutineAspect, GuzzleHttpClientAspect, EventHandleListener, and SpanStarter --- .../src/Tracing/Aspect/CoroutineAspect.php | 4 ++- .../Tracing/Aspect/GuzzleHttpClientAspect.php | 4 ++- .../Tracing/Listener/EventHandleListener.php | 26 ++++++++++++++----- src/sentry/src/Tracing/SpanStarter.php | 4 ++- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index a6f2a1945..9eb6280ac 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -111,8 +111,10 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { $transaction->setData([ diff --git a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php index 27a3e58b2..1b23ff086 100644 --- a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php +++ b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php @@ -162,8 +162,10 @@ function (Scope $scope) use ($proceedingJoinPoint, $options, $guzzleConfig) { ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { $span->setData([ diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index fa0b199d1..258b827be 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -374,6 +374,8 @@ private function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\RequestH 'error' => 'true', 'exception.class' => $exception::class, 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { @@ -427,8 +429,10 @@ private function handleCommandFinished(CommandEvent\AfterExecute $event): void ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { $transaction->setData([ @@ -469,8 +473,10 @@ function (Scope $scope) use ($event) { ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { $span?->setData(['exception.stack_trace' => (string) $exception]); @@ -536,8 +542,10 @@ private function handleCrontabTaskFinished(CrontabEvent\FailToExecute|CrontabEve ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { $transaction->setData(['exception.stack_trace' => (string) $exception]); @@ -614,8 +622,10 @@ private function handleAmqpMessageProcessed(AmqpEvent\AfterConsume|AmqpEvent\Fai ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { $transaction->setData(['exception.stack_trace' => (string) $exception]); @@ -686,8 +696,10 @@ private function handleKafkaMessageProcessed(KafkaEvent\AfterConsume|KafkaEvent\ ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { $transaction->setData(['exception.stack_trace' => (string) $exception]); @@ -745,8 +757,10 @@ private function handleAsyncQueueJobProcessed(AsyncQueueEvent\AfterHandle|AsyncQ ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { $transaction->setData(['exception.stack_trace' => (string) $exception]); diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index 3320f0d34..ef83b8f78 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -56,8 +56,10 @@ protected function trace(callable $trace, SpanContext $context) ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, - 'exception.message' => $exception->getMessage(), 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { $span->setData([ From d066d839aa06214a59d84c4620fdab36bb760b62 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 17:08:20 +0800 Subject: [PATCH 44/64] fix(aspect): rename transaction variable to coTransaction for clarity in CoroutineAspect --- src/sentry/src/Tracing/Aspect/CoroutineAspect.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index 9eb6280ac..779b27330 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -91,7 +91,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) } } - $transaction = $this->startCoroutineTransaction( + $coTransaction = $this->startCoroutineTransaction( parent: $parent, name: 'coroutine', op: 'coroutine.execute', @@ -99,15 +99,15 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) origin: 'auto.coroutine', )->setData(['coroutine.id' => Co::id()]); - defer(function () use ($transaction) { - SentrySdk::getCurrentHub()->setSpan($transaction); - $transaction->finish(); + defer(function () use ($coTransaction) { + SentrySdk::getCurrentHub()->setSpan($coTransaction); + $coTransaction->finish(); }); try { $callable(); } catch (Throwable $exception) { - $transaction->setStatus(SpanStatus::internalError()) + $coTransaction->setStatus(SpanStatus::internalError()) ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, @@ -117,7 +117,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $transaction->setData([ + $coTransaction->setData([ 'exception.stack_trace' => (string) $exception, ]); } From 5ae1159802517b5749fe1037944d210fcb4c7281 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 17:11:28 +0800 Subject: [PATCH 45/64] fix(span): add detailed description for trace method in SpanStarter trait --- src/sentry/src/Tracing/SpanStarter.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index ef83b8f78..da02538c0 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -33,6 +33,9 @@ trait SpanStarter { /** + * Execute the given callable while wrapping it in a span added as a child to the current transaction and active span. + * If there is no transaction active this is a no-op and the scope passed to the trace callable will be unused. + * * @template T * * @param callable(Scope):T $trace From 6abe2ae2181d72d32e5b7278447d56cebe0ac327 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 17:25:45 +0800 Subject: [PATCH 46/64] fix(span): enhance error handling and tracing in trace method of SpanStarter trait --- src/sentry/src/Tracing/SpanStarter.php | 68 ++++++++++++++------------ 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index da02538c0..27631357d 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -12,6 +12,7 @@ namespace FriendsOfHyperf\Sentry\Tracing; use FriendsOfHyperf\Sentry\Constants; +use FriendsOfHyperf\Sentry\Switcher; use FriendsOfHyperf\Sentry\Util\Carrier; use Hyperf\Context\ApplicationContext; use Hyperf\Rpc\Context as RpcContext; @@ -43,42 +44,45 @@ trait SpanStarter */ protected function trace(callable $trace, SpanContext $context) { - return SentrySdk::getCurrentHub()->withScope(function (Scope $scope) use ($context, $trace) { - $parentSpan = $scope->getSpan(); + static $isTracingExtraTagEnabled = null; - if ($parentSpan !== null && $parentSpan->getSampled()) { - $span = $parentSpan->startChild($context); - $scope->setSpan($span); - } + if ($isTracingExtraTagEnabled !== null) { + $isTracingExtraTagEnabled = isset($this->switcher) + && $this->switcher instanceof Switcher + && $this->switcher->isTracingExtraTagEnabled('exception.stack_trace'); + } - try { - return $trace($scope); - } catch (Throwable $exception) { - if (isset($span)) { - $span->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.code' => (string) $exception->getCode(), - ]) - ->setData([ - 'exception.message' => $exception->getMessage(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span->setData([ - 'exception.stack_trace' => (string) $exception, - ]); - } - } - throw $exception; - } finally { - if (isset($span)) { - $span->finish(); + if ($context->getStatus() === null) { + $context->setStatus(SpanStatus::ok()); + } - $scope->setSpan($parentSpan); + return trace( + function (Scope $scope) use ($trace, $isTracingExtraTagEnabled) { + try { + return $trace($scope); + } catch (Throwable $exception) { + $span = $scope->getSpan(); + if ($span !== null) { + $span->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), + ]); + if ($isTracingExtraTagEnabled) { + $span->setData([ + 'exception.stack_trace' => (string) $exception, + ]); + } + } + throw $exception; } - } - }); + }, + $context + ); } /** From 81b4ff8340a1ef2ec1420cded21c45df38527a6a Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 17:27:06 +0800 Subject: [PATCH 47/64] fix(span): set start timestamp in trace method of SpanStarter trait if not already set --- src/sentry/src/Tracing/SpanStarter.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index 27631357d..03a2080cd 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -56,6 +56,10 @@ protected function trace(callable $trace, SpanContext $context) $context->setStatus(SpanStatus::ok()); } + if ($context->getStartTimestamp() === null) { + $context->setStartTimestamp(microtime(true)); + } + return trace( function (Scope $scope) use ($trace, $isTracingExtraTagEnabled) { try { From 143ea0673a32b2cd1e1f045d0a85bd6c045293db Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Tue, 23 Sep 2025 17:32:10 +0800 Subject: [PATCH 48/64] fix(span): correct condition for enabling tracing extra tag in trace method of SpanStarter trait --- src/sentry/src/Tracing/SpanStarter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index 03a2080cd..c905e9987 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -46,7 +46,7 @@ protected function trace(callable $trace, SpanContext $context) { static $isTracingExtraTagEnabled = null; - if ($isTracingExtraTagEnabled !== null) { + if ($isTracingExtraTagEnabled === null) { $isTracingExtraTagEnabled = isset($this->switcher) && $this->switcher instanceof Switcher && $this->switcher->isTracingExtraTagEnabled('exception.stack_trace'); From 29e5df692546ab8f85109ad80d462976c71de91b Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:41:48 +0800 Subject: [PATCH 49/64] fix(span): simplify tracing extra tag condition in trace method of SpanStarter trait --- src/sentry/src/Tracing/SpanStarter.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index c905e9987..419d4f1e5 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -44,13 +44,9 @@ trait SpanStarter */ protected function trace(callable $trace, SpanContext $context) { - static $isTracingExtraTagEnabled = null; - - if ($isTracingExtraTagEnabled === null) { - $isTracingExtraTagEnabled = isset($this->switcher) - && $this->switcher instanceof Switcher - && $this->switcher->isTracingExtraTagEnabled('exception.stack_trace'); - } + $isTracingExtraTagEnabled = isset($this->switcher) + && $this->switcher instanceof Switcher + && $this->switcher->isTracingExtraTagEnabled('exception.stack_trace'); if ($context->getStatus() === null) { $context->setStatus(SpanStatus::ok()); From 403e64c89ebb9cbf38641fbe387b6e1084d11143 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 09:40:39 +0800 Subject: [PATCH 50/64] fix(span): ensure span is valid before setting data and status in EventHandleListener --- .../src/Tracing/Listener/EventHandleListener.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 258b827be..b36d1d438 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -462,14 +462,16 @@ private function handleRedisCommandExecuted(RedisEvent\CommandExecuted $event): $this->trace( function (Scope $scope) use ($event) { - $span = $scope->getSpan(); + if (! $span = $scope->getSpan()) { + return; + } if ($this->switcher->isTracingExtraTagEnabled('redis.result')) { - $span?->setData(['db.redis.result' => $event->result]); + $span->setData(['db.redis.result' => $event->result]); } if ($exception = $event->throwable) { - $span?->setStatus(SpanStatus::internalError()) + $span->setStatus(SpanStatus::internalError()) ->setTags([ 'error' => 'true', 'exception.class' => $exception::class, @@ -479,7 +481,7 @@ function (Scope $scope) use ($event) { 'exception.message' => $exception->getMessage(), ]); if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $span?->setData(['exception.stack_trace' => (string) $exception]); + $span->setData(['exception.stack_trace' => (string) $exception]); } } }, From 4eadf401eee6377d04855b03af7461d011feb66a Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 13:48:27 +0800 Subject: [PATCH 51/64] fix(EventHandleListener): change private methods to protected for better extensibility --- .../Tracing/Listener/EventHandleListener.php | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index b36d1d438..9e25d5f5b 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -163,7 +163,7 @@ public function process(object $event): void }; } - private function handleDbQueryExecuted(DbEvent\QueryExecuted $event): void + protected function handleDbQueryExecuted(DbEvent\QueryExecuted $event): void { if (! $this->switcher->isTracingSpanEnabled('sql_queries')) { return; @@ -213,7 +213,7 @@ private function handleDbQueryExecuted(DbEvent\QueryExecuted $event): void ); } - private function handleDbTransactionBeginning(DbEvent\TransactionBeginning $event): void + protected function handleDbTransactionBeginning(DbEvent\TransactionBeginning $event): void { if (! $this->switcher->isTracingSpanEnabled('sql_transactions')) { return; @@ -235,7 +235,7 @@ private function handleDbTransactionBeginning(DbEvent\TransactionBeginning $even ); } - private function handleDbTransactionCommitted(DbEvent\TransactionCommitted $event): void + protected function handleDbTransactionCommitted(DbEvent\TransactionCommitted $event): void { if (! $this->switcher->isTracingSpanEnabled('sql_transactions')) { return; @@ -249,7 +249,7 @@ private function handleDbTransactionCommitted(DbEvent\TransactionCommitted $even ->finish(); } - private function handleDbTransactionRolledBack(DbEvent\TransactionRolledBack $event): void + protected function handleDbTransactionRolledBack(DbEvent\TransactionRolledBack $event): void { if (! $this->switcher->isTracingSpanEnabled('sql_transactions')) { return; @@ -263,7 +263,7 @@ private function handleDbTransactionRolledBack(DbEvent\TransactionRolledBack $ev ->finish(); } - private function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\RequestReceived $event): void + protected function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\RequestReceived $event): void { if (! $this->switcher->isTracingEnabled('request')) { return; @@ -343,7 +343,7 @@ private function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Reques }); } - private function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\RequestHandled $event): void + protected function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\RequestHandled $event): void { $span = SentrySdk::getCurrentHub()->getSpan(); @@ -386,7 +386,7 @@ private function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\RequestH } } - private function handleCommandStarting(CommandEvent\BeforeHandle $event): void + protected function handleCommandStarting(CommandEvent\BeforeHandle $event): void { if ( ! $this->switcher->isTracingEnabled('command') @@ -406,7 +406,7 @@ private function handleCommandStarting(CommandEvent\BeforeHandle $event): void ); } - private function handleCommandFinished(CommandEvent\AfterExecute $event): void + protected function handleCommandFinished(CommandEvent\AfterExecute $event): void { $transaction = SentrySdk::getCurrentHub()->getTransaction(); @@ -450,7 +450,7 @@ private function handleCommandFinished(CommandEvent\AfterExecute $event): void $transaction->finish(); } - private function handleRedisCommandExecuted(RedisEvent\CommandExecuted $event): void + protected function handleRedisCommandExecuted(RedisEvent\CommandExecuted $event): void { if (! $this->switcher->isTracingSpanEnabled('redis')) { return; @@ -506,7 +506,7 @@ function (Scope $scope) use ($event) { ); } - private function handleCrontabTaskStarting(CrontabEvent\BeforeExecute $event): void + protected function handleCrontabTaskStarting(CrontabEvent\BeforeExecute $event): void { if (! $this->switcher->isTracingEnabled('crontab')) { return; @@ -523,7 +523,7 @@ private function handleCrontabTaskStarting(CrontabEvent\BeforeExecute $event): v ); } - private function handleCrontabTaskFinished(CrontabEvent\FailToExecute|CrontabEvent\AfterExecute $event): void + protected function handleCrontabTaskFinished(CrontabEvent\FailToExecute|CrontabEvent\AfterExecute $event): void { $transaction = SentrySdk::getCurrentHub()->getTransaction(); @@ -559,7 +559,7 @@ private function handleCrontabTaskFinished(CrontabEvent\FailToExecute|CrontabEve $transaction->finish(); } - private function handleAmqpMessageProcessing(AmqpEvent\BeforeConsume $event): void + protected function handleAmqpMessageProcessing(AmqpEvent\BeforeConsume $event): void { if (! $this->switcher->isTracingEnabled('amqp')) { return; @@ -590,7 +590,7 @@ private function handleAmqpMessageProcessing(AmqpEvent\BeforeConsume $event): vo ); } - private function handleAmqpMessageProcessed(AmqpEvent\AfterConsume|AmqpEvent\FailToConsume $event): void + protected function handleAmqpMessageProcessed(AmqpEvent\AfterConsume|AmqpEvent\FailToConsume $event): void { $transaction = SentrySdk::getCurrentHub()->getTransaction(); @@ -639,7 +639,7 @@ private function handleAmqpMessageProcessed(AmqpEvent\AfterConsume|AmqpEvent\Fai $transaction->finish(); } - private function handleKafkaMessageProcessing(KafkaEvent\BeforeConsume $event): void + protected function handleKafkaMessageProcessing(KafkaEvent\BeforeConsume $event): void { if (! $this->switcher->isTracingEnabled('kafka')) { return; @@ -670,7 +670,7 @@ private function handleKafkaMessageProcessing(KafkaEvent\BeforeConsume $event): ); } - private function handleKafkaMessageProcessed(KafkaEvent\AfterConsume|KafkaEvent\FailToConsume $event): void + protected function handleKafkaMessageProcessed(KafkaEvent\AfterConsume|KafkaEvent\FailToConsume $event): void { $transaction = SentrySdk::getCurrentHub()->getTransaction(); @@ -713,7 +713,7 @@ private function handleKafkaMessageProcessed(KafkaEvent\AfterConsume|KafkaEvent\ $transaction->finish(); } - private function handleAsyncQueueJobProcessing(AsyncQueueEvent\BeforeHandle $event): void + protected function handleAsyncQueueJobProcessing(AsyncQueueEvent\BeforeHandle $event): void { if (! $this->switcher->isTracingEnabled('async_queue')) { return; @@ -734,7 +734,7 @@ private function handleAsyncQueueJobProcessing(AsyncQueueEvent\BeforeHandle $eve ); } - private function handleAsyncQueueJobProcessed(AsyncQueueEvent\AfterHandle|AsyncQueueEvent\RetryHandle|AsyncQueueEvent\FailedHandle $event): void + protected function handleAsyncQueueJobProcessed(AsyncQueueEvent\AfterHandle|AsyncQueueEvent\RetryHandle|AsyncQueueEvent\FailedHandle $event): void { $transaction = SentrySdk::getCurrentHub()->getTransaction(); From 0e50466a70962dface89d1ed2b464cd48bb0da93 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 14:25:44 +0800 Subject: [PATCH 52/64] fix(CoroutineAspect, EventHandleListener, SpanStarter): refactor to use startTransaction and continueTrace for better trace handling --- .../src/Tracing/Aspect/CoroutineAspect.php | 16 ++-- .../Tracing/Listener/EventHandleListener.php | 96 ++++++++++--------- src/sentry/src/Tracing/SpanStarter.php | 71 ++++++++++---- 3 files changed, 114 insertions(+), 69 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index 779b27330..1b6219765 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -23,6 +23,7 @@ use Throwable; use function Hyperf\Coroutine\defer; +use function Sentry\continueTrace; class CoroutineAspect extends AbstractAspect { @@ -91,13 +92,14 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) } } - $coTransaction = $this->startCoroutineTransaction( - parent: $parent, - name: 'coroutine', - op: 'coroutine.execute', - description: $callingOnFunction, - origin: 'auto.coroutine', - )->setData(['coroutine.id' => Co::id()]); + $coTransaction = $this->startTransaction( + continueTrace($parent->toTraceparent(), $parent->toBaggage()) + ->setName('coroutine') + ->setOp('coroutine.execute') + ->setDescription($callingOnFunction) + ->setOrigin('auto.coroutine') + ->setData(['coroutine.id' => Co::id()]) + ); defer(function () use ($coTransaction) { SentrySdk::getCurrentHub()->setSpan($coTransaction); diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 9e25d5f5b..9ea1cd63e 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -45,11 +45,13 @@ use Sentry\State\Scope; use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; +use Sentry\Tracing\TransactionContext; use Sentry\Tracing\TransactionSource; use Swow\Psr7\Message\ResponsePlusInterface; use Symfony\Component\Console\Command\Command as SymfonyCommand; use function Hyperf\Coroutine\defer; +use function Sentry\continueTrace; /** * @property int $exitCode @@ -289,13 +291,22 @@ protected function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Requ default => [$route, TransactionSource::route()], }; - $transaction = $this->startRequestTransaction( - request: $request, - name: $name, - op: sprintf('%s.server', $serverName), - description: sprintf('%s %s', $method, $path), - origin: 'auto.request', - source: $source, + // $transaction = $this->startRequestTransaction( + // request: $request, + // name: $name, + // op: sprintf('%s.server', $serverName), + // description: sprintf('%s %s', $method, $path), + // origin: 'auto.request', + // source: $source, + // ); + + $transaction = $this->startTransaction( + continueTrace(...$this->parseSentryTraceAndBaggage($request)) + ->setName($name) + ->setOp(sprintf('%s.server', $serverName)) + ->setDescription(description: sprintf('%s %s', $method, $path)) + ->setOrigin('auto.request') + ->setSource($source) ); if (! $transaction->getSampled()) { @@ -397,12 +408,13 @@ protected function handleCommandStarting(CommandEvent\BeforeHandle $event): void $command = $event->getCommand(); - $this->continueTrace( - name: $command->getName() ?: '', - op: 'console.command', - description: $command->getDescription(), - origin: 'auto.command', - source: TransactionSource::custom() + $this->startTransaction( + TransactionContext::make() + ->setName($command->getName() ?: '') + ->setOp('console.command') + ->setDescription($command->getDescription()) + ->setOrigin('auto.command') + ->setSource(TransactionSource::custom()) ); } @@ -514,12 +526,13 @@ protected function handleCrontabTaskStarting(CrontabEvent\BeforeExecute $event): $crontab = $event->crontab; - $this->continueTrace( - name: $crontab->getName() ?: '', - op: 'crontab.run', - description: $crontab->getMemo(), - origin: 'auto.crontab', - source: TransactionSource::task() + $this->startTransaction( + TransactionContext::make() + ->setName($crontab->getName() ?: '') + ->setOp('crontab.run') + ->setDescription($crontab->getMemo()) + ->setOrigin('auto.crontab') + ->setSource(TransactionSource::task()) ); } @@ -579,14 +592,13 @@ protected function handleAmqpMessageProcessing(AmqpEvent\BeforeConsume $event): } } - $this->continueTrace( - sentryTrace: $carrier?->getSentryTrace() ?? '', - baggage: $carrier?->getBaggage() ?? '', - name: $message::class, - op: 'queue.process', - description: $message::class, - origin: 'auto.amqp', - source: TransactionSource::custom() + $this->startTransaction( + continueTrace($carrier?->getSentryTrace() ?? '', $carrier?->getBaggage() ?? '') + ->setName($message::class) + ->setOp('queue.process') + ->setDescription($message::class) + ->setOrigin('auto.amqp') + ->setSource(TransactionSource::custom()) ); } @@ -659,14 +671,13 @@ protected function handleKafkaMessageProcessing(KafkaEvent\BeforeConsume $event) } } - $this->continueTrace( - sentryTrace: $carrier?->getSentryTrace() ?? '', - baggage: $carrier?->getBaggage() ?? '', - name: $consumer->getTopic() . ' process', - op: 'queue.process', - description: $consumer::class, - origin: 'auto.kafka', - source: TransactionSource::custom() + $this->startTransaction( + continueTrace($carrier?->getSentryTrace() ?? '', $carrier?->getBaggage() ?? '') + ->setName($consumer->getTopic() . ' process') + ->setOp('queue.process') + ->setDescription($consumer::class) + ->setOrigin('auto.kafka') + ->setSource(TransactionSource::custom()) ); } @@ -723,14 +734,13 @@ protected function handleAsyncQueueJobProcessing(AsyncQueueEvent\BeforeHandle $e $carrier = Context::get(Constants::TRACE_CARRIER, null, Coroutine::parentId()); $job = $event->getMessage()->job(); - $this->continueTrace( - sentryTrace: $carrier?->getSentryTrace() ?? '', - baggage: $carrier?->getBaggage() ?? '', - name: $job::class, - op: 'queue.process', - description: 'async_queue: ' . $job::class, - origin: 'auto.async_queue', - source: TransactionSource::custom() + $this->startTransaction( + continueTrace($carrier?->getSentryTrace() ?? '', $carrier?->getBaggage() ?? '') + ->setName($job::class) + ->setOp('queue.process') + ->setDescription('async_queue: ' . $job::class) + ->setOrigin('auto.async_queue') + ->setSource(TransactionSource::custom()) ); } diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index 419d4f1e5..447ade611 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -24,6 +24,7 @@ use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; use Sentry\Tracing\Transaction; +use Sentry\Tracing\TransactionContext; use Sentry\Tracing\TransactionSource; use Throwable; @@ -114,36 +115,27 @@ protected function startSpan( ); } + /** + * @deprecated since v3.1, will be removed in v3.2, use startTransaction() instead. + */ protected function startRequestTransaction(ServerRequestInterface $request, ...$options): Transaction { - // Get sentry-trace and baggage - $sentryTrace = match (true) { - $request->hasHeader('sentry-trace') => $request->getHeaderLine('sentry-trace'), - $request->hasHeader('traceparent') => $request->getHeaderLine('traceparent'), - default => '', - }; - $baggage = $request->getHeaderLine('baggage'); - $container = $this->container ?? ApplicationContext::getContainer(); - - // Rpc Context - if ($container->has(RpcContext::class)) { - $rpcContext = $container->get(RpcContext::class); - /** @var null|string $payload */ - $payload = $rpcContext->get(Constants::TRACE_CARRIER); - if ($payload) { - $carrier = Carrier::fromJson($payload); - [$sentryTrace, $baggage] = [$carrier->getSentryTrace(), $carrier->getBaggage()]; - } - } + [$sentryTrace, $baggage] = $this->parseSentryTraceAndBaggage($request); return $this->continueTrace($sentryTrace, $baggage, ...$options); } + /** + * @deprecated since v3.1, will be removed in v3.2, use startTransaction() instead. + */ protected function startCoroutineTransaction(Span $parent, ...$options): Transaction { return $this->continueTrace($parent->toTraceparent(), $parent->toBaggage(), ...$options); } + /** + * @deprecated since v3.1, will be removed in v3.2, use startTransaction() instead. + */ protected function continueTrace(string $sentryTrace = '', string $baggage = '', ...$options): Transaction { $hub = SentrySdk::setCurrentHub( @@ -174,4 +166,45 @@ protected function continueTrace(string $sentryTrace = '', string $baggage = '', fn ($transaction) => $hub->setSpan($transaction) ); } + + protected function startTransaction(TransactionContext $transactionContext, array $customSamplingContext = []): Transaction + { + $hub = SentrySdk::setCurrentHub( + tap(clone SentrySdk::getCurrentHub(), fn (HubInterface $hub) => $hub->pushScope()) + ); + + $transaction = $hub->startTransaction($transactionContext, $customSamplingContext); + + $hub->setSpan($transaction); + + return $transaction; + } + + /** + * @return array{0: string, 1: string} + */ + protected function parseSentryTraceAndBaggage(ServerRequestInterface $request): array + { + // Get sentry-trace and baggage + $sentryTrace = match (true) { + $request->hasHeader('sentry-trace') => $request->getHeaderLine('sentry-trace'), + $request->hasHeader('traceparent') => $request->getHeaderLine('traceparent'), + default => '', + }; + $baggage = $request->getHeaderLine('baggage'); + $container = $this->container ?? ApplicationContext::getContainer(); + + // Rpc Context + if ($container->has(RpcContext::class)) { + $rpcContext = $container->get(RpcContext::class); + /** @var null|string $payload */ + $payload = $rpcContext->get(Constants::TRACE_CARRIER); + if ($payload) { + $carrier = Carrier::fromJson($payload); + [$sentryTrace, $baggage] = [$carrier->getSentryTrace(), $carrier->getBaggage()]; + } + } + + return [$sentryTrace, $baggage]; + } } From a8c52e188436f1efdd814ce533fcc54c75b0004d Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 14:37:14 +0800 Subject: [PATCH 53/64] feat(Carrier, EventHandleListener, SpanStarter): implement Carrier utility for improved trace handling and refactor transaction methods --- .../Tracing/Listener/EventHandleListener.php | 15 ++------ src/sentry/src/Tracing/SpanStarter.php | 35 ++----------------- src/sentry/src/Util/Carrier.php | 32 +++++++++++++++++ 3 files changed, 36 insertions(+), 46 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 9ea1cd63e..6e7cf7d63 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -282,26 +282,15 @@ protected function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Requ $serverName = $dispatched->serverName ?? 'http'; $path = $request->getUri()->getPath(); $method = strtoupper($request->getMethod()); - [$route, $routeParams, $routeCallback] = $this->parseRoute($dispatched); - [$name, $source] = match (strtolower($this->source)) { 'custom' => [$routeCallback, TransactionSource::custom()], 'url' => [$path, TransactionSource::url()], default => [$route, TransactionSource::route()], }; - - // $transaction = $this->startRequestTransaction( - // request: $request, - // name: $name, - // op: sprintf('%s.server', $serverName), - // description: sprintf('%s %s', $method, $path), - // origin: 'auto.request', - // source: $source, - // ); - + $carrier = Carrier::fromRequest($request); $transaction = $this->startTransaction( - continueTrace(...$this->parseSentryTraceAndBaggage($request)) + continueTrace($carrier->getSentryTrace(), $carrier->getBaggage()) ->setName($name) ->setOp(sprintf('%s.server', $serverName)) ->setDescription(description: sprintf('%s %s', $method, $path)) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index 447ade611..7adccf802 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -11,11 +11,8 @@ namespace FriendsOfHyperf\Sentry\Tracing; -use FriendsOfHyperf\Sentry\Constants; use FriendsOfHyperf\Sentry\Switcher; use FriendsOfHyperf\Sentry\Util\Carrier; -use Hyperf\Context\ApplicationContext; -use Hyperf\Rpc\Context as RpcContext; use Psr\Http\Message\ServerRequestInterface; use Sentry\SentrySdk; use Sentry\State\HubInterface; @@ -120,9 +117,9 @@ protected function startSpan( */ protected function startRequestTransaction(ServerRequestInterface $request, ...$options): Transaction { - [$sentryTrace, $baggage] = $this->parseSentryTraceAndBaggage($request); + $carrier = Carrier::fromRequest($request); - return $this->continueTrace($sentryTrace, $baggage, ...$options); + return $this->continueTrace($carrier->getSentryTrace(), $carrier->getBaggage(), ...$options); } /** @@ -179,32 +176,4 @@ protected function startTransaction(TransactionContext $transactionContext, arra return $transaction; } - - /** - * @return array{0: string, 1: string} - */ - protected function parseSentryTraceAndBaggage(ServerRequestInterface $request): array - { - // Get sentry-trace and baggage - $sentryTrace = match (true) { - $request->hasHeader('sentry-trace') => $request->getHeaderLine('sentry-trace'), - $request->hasHeader('traceparent') => $request->getHeaderLine('traceparent'), - default => '', - }; - $baggage = $request->getHeaderLine('baggage'); - $container = $this->container ?? ApplicationContext::getContainer(); - - // Rpc Context - if ($container->has(RpcContext::class)) { - $rpcContext = $container->get(RpcContext::class); - /** @var null|string $payload */ - $payload = $rpcContext->get(Constants::TRACE_CARRIER); - if ($payload) { - $carrier = Carrier::fromJson($payload); - [$sentryTrace, $baggage] = [$carrier->getSentryTrace(), $carrier->getBaggage()]; - } - } - - return [$sentryTrace, $baggage]; - } } diff --git a/src/sentry/src/Util/Carrier.php b/src/sentry/src/Util/Carrier.php index 3b39c7167..b812755cc 100644 --- a/src/sentry/src/Util/Carrier.php +++ b/src/sentry/src/Util/Carrier.php @@ -11,10 +11,14 @@ namespace FriendsOfHyperf\Sentry\Util; +use FriendsOfHyperf\Sentry\Constants; +use Hyperf\Context\ApplicationContext; use Hyperf\Contract\Arrayable; use Hyperf\Contract\Jsonable; +use Hyperf\Rpc\Context as RpcContext; use JsonException; use JsonSerializable; +use Psr\Http\Message\ServerRequestInterface; use Sentry\Tracing\Span; use Stringable; @@ -58,6 +62,34 @@ public static function fromSpan(Span $span): static ]); } + public static function fromRequest(ServerRequestInterface $request): static + { + // Get sentry-trace and baggage + $sentryTrace = match (true) { + $request->hasHeader('sentry-trace') => $request->getHeaderLine('sentry-trace'), + $request->hasHeader('traceparent') => $request->getHeaderLine('traceparent'), + default => '', + }; + $baggage = $request->getHeaderLine('baggage'); + $container = ApplicationContext::getContainer(); + + // Rpc Context + if ($container->has(RpcContext::class)) { + $rpcContext = $container->get(RpcContext::class); + /** @var null|string $payload */ + $payload = $rpcContext->get(Constants::TRACE_CARRIER); + if ($payload) { + $carrier = Carrier::fromJson($payload); + [$sentryTrace, $baggage] = [$carrier->getSentryTrace(), $carrier->getBaggage()]; + } + } + + return new static([ + 'sentry-trace' => $sentryTrace, + 'baggage' => $baggage, + ]); + } + public function with(array $data): static { $new = clone $this; From f2d735a4955aa73d1fc55fc155209809c67bca6a Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 14:37:47 +0800 Subject: [PATCH 54/64] fix(SpanStarter): remove duplicate startTransaction method implementation --- src/sentry/src/Tracing/SpanStarter.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sentry/src/Tracing/SpanStarter.php b/src/sentry/src/Tracing/SpanStarter.php index 7adccf802..99ef865ca 100644 --- a/src/sentry/src/Tracing/SpanStarter.php +++ b/src/sentry/src/Tracing/SpanStarter.php @@ -31,6 +31,19 @@ trait SpanStarter { + protected function startTransaction(TransactionContext $transactionContext, array $customSamplingContext = []): Transaction + { + $hub = SentrySdk::setCurrentHub( + tap(clone SentrySdk::getCurrentHub(), fn (HubInterface $hub) => $hub->pushScope()) + ); + + $transaction = $hub->startTransaction($transactionContext, $customSamplingContext); + + $hub->setSpan($transaction); + + return $transaction; + } + /** * Execute the given callable while wrapping it in a span added as a child to the current transaction and active span. * If there is no transaction active this is a no-op and the scope passed to the trace callable will be unused. @@ -163,17 +176,4 @@ protected function continueTrace(string $sentryTrace = '', string $baggage = '', fn ($transaction) => $hub->setSpan($transaction) ); } - - protected function startTransaction(TransactionContext $transactionContext, array $customSamplingContext = []): Transaction - { - $hub = SentrySdk::setCurrentHub( - tap(clone SentrySdk::getCurrentHub(), fn (HubInterface $hub) => $hub->pushScope()) - ); - - $transaction = $hub->startTransaction($transactionContext, $customSamplingContext); - - $hub->setSpan($transaction); - - return $transaction; - } } From 147ddce425114efb24095eada28764102a89041e Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:38:59 +0800 Subject: [PATCH 55/64] Remove sampled check from trace ID header logic Simplifies the condition for setting the 'sentry-trace-id' header by removing the check for the span's sampled status. The header is now set whenever a span and trace ID are present. --- src/sentry/src/Tracing/Listener/EventHandleListener.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 6e7cf7d63..8e49c8c69 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -347,11 +347,7 @@ protected function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\Reques { $span = SentrySdk::getCurrentHub()->getSpan(); - if ( - ! $span - || ! $span->getSampled() - || ! $traceId = (string) $span->getTraceId() - ) { + if (! $span || ! $traceId = (string) $span->getTraceId()) { return; } @@ -363,7 +359,6 @@ protected function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\Reques $event->response->setHeader('sentry-trace-id', $traceId); } - // $span->setHttpStatus($event->response->getStatusCode()); $span->setStatus( SpanStatus::createFromHttpStatusCode($event->response->getStatusCode()) ); From efb2f74254a8deb64c8973c1a34947327f198d1a Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:40:50 +0800 Subject: [PATCH 56/64] fix(EventHandleListener): simplify span validation logic and remove commented code --- .../Tracing/Listener/EventHandleListener.php | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 8e49c8c69..e6af929a8 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -288,20 +288,6 @@ protected function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Requ 'url' => [$path, TransactionSource::url()], default => [$route, TransactionSource::route()], }; - $carrier = Carrier::fromRequest($request); - $transaction = $this->startTransaction( - continueTrace($carrier->getSentryTrace(), $carrier->getBaggage()) - ->setName($name) - ->setOp(sprintf('%s.server', $serverName)) - ->setDescription(description: sprintf('%s %s', $method, $path)) - ->setOrigin('auto.request') - ->setSource($source) - ); - - if (! $transaction->getSampled()) { - return; - } - $data = [ 'url.scheme' => $request->getUri()->getScheme(), 'url.path' => $path, @@ -315,8 +301,20 @@ protected function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Requ if ($this->container->has(RpcContext::class)) { $data['rpc.context'] = $this->container->get(RpcContext::class)->getData(); } + $carrier = Carrier::fromRequest($request); + $transaction = $this->startTransaction( + continueTrace($carrier->getSentryTrace(), $carrier->getBaggage()) + ->setName($name) + ->setOp(sprintf('%s.server', $serverName)) + ->setDescription(description: sprintf('%s %s', $method, $path)) + ->setOrigin('auto.request') + ->setSource($source) + ->setData($data) + ); - $transaction->setData($data); + if (! $transaction->getSampled()) { + return; + } $spanContext = SpanContext::make() ->setOp('request.received') From fb9957e691522b0de25d9785ca14a80c05953d87 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:41:30 +0800 Subject: [PATCH 57/64] fix(EventHandleListener): add carrier initialization for improved trace handling --- src/sentry/src/Tracing/Listener/EventHandleListener.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index e6af929a8..46f95a89a 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -301,6 +301,7 @@ protected function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Requ if ($this->container->has(RpcContext::class)) { $data['rpc.context'] = $this->container->get(RpcContext::class)->getData(); } + $carrier = Carrier::fromRequest($request); $transaction = $this->startTransaction( continueTrace($carrier->getSentryTrace(), $carrier->getBaggage()) From 6062168ade631266da95fe6a9ed9e76e984a8d94 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:42:42 +0800 Subject: [PATCH 58/64] fix(EventHandleListener): streamline span creation logic in process method --- .../Tracing/Listener/EventHandleListener.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 46f95a89a..36be5c23a 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -317,16 +317,16 @@ protected function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Requ return; } - $spanContext = SpanContext::make() - ->setOp('request.received') - ->setDescription('request.received') - ->setData([ - 'coroutine.id' => Coroutine::id(), - ]) - ->setStatus(SpanStatus::ok()) - ->setStartTimestamp(microtime(true)); - - $span = $transaction->startChild($spanContext); + $span = $transaction->startChild( + SpanContext::make() + ->setOp('request.received') + ->setDescription('request.received') + ->setData([ + 'coroutine.id' => Coroutine::id(), + ]) + ->setStatus(SpanStatus::ok()) + ->setStartTimestamp(microtime(true)) + ); SentrySdk::getCurrentHub()->setSpan($span); From 08ec1dd0ec2c6d048cbb26048cd559f75367216b Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:49:48 +0800 Subject: [PATCH 59/64] fix(EventHandleListener): refactor error handling and transaction management in process method --- .../Tracing/Listener/EventHandleListener.php | 312 +++++++++--------- 1 file changed, 161 insertions(+), 151 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 36be5c23a..d04b4859f 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -409,40 +409,42 @@ protected function handleCommandFinished(CommandEvent\AfterExecute $event): void return; } - $command = $event->getCommand(); - $exitCode = (fn () => $this->exitCode ?? SymfonyCommand::SUCCESS)->call($command); - - $transaction->setData([ - 'command.arguments' => (fn () => $this->input->getArguments())->call($command), - 'command.options' => (fn () => $this->input->getOptions())->call($command), - ])->setTags([ - 'command.exit_code' => (string) $exitCode, - ]); - - if (method_exists($event, 'getThrowable') && $exception = $event->getThrowable()) { - $transaction->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.code' => (string) $exception->getCode(), - ]) - ->setData([ - 'exception.message' => $exception->getMessage(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $transaction->setData([ - 'exception.stack_trace' => (string) $exception, - ]); + try { + $command = $event->getCommand(); + $exitCode = (fn () => $this->exitCode ?? SymfonyCommand::SUCCESS)->call($command); + + $transaction->setData([ + 'command.arguments' => (fn () => $this->input->getArguments())->call($command), + 'command.options' => (fn () => $this->input->getOptions())->call($command), + ])->setTags([ + 'command.exit_code' => (string) $exitCode, + ]); + + if (method_exists($event, 'getThrowable') && $exception = $event->getThrowable()) { + $transaction->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $transaction->setData([ + 'exception.stack_trace' => (string) $exception, + ]); + } } - } - - $transaction->setStatus( - $exitCode == SymfonyCommand::SUCCESS ? SpanStatus::ok() : SpanStatus::internalError() - ); - SentrySdk::getCurrentHub()->setSpan($transaction); + $transaction->setStatus( + $exitCode == SymfonyCommand::SUCCESS ? SpanStatus::ok() : SpanStatus::internalError() + ); + } finally { + SentrySdk::getCurrentHub()->setSpan($transaction); - $transaction->finish(); + $transaction->finish(); + } } protected function handleRedisCommandExecuted(RedisEvent\CommandExecuted $event): void @@ -527,32 +529,34 @@ protected function handleCrontabTaskFinished(CrontabEvent\FailToExecute|CrontabE return; } - $crontab = $event->crontab; - $transaction->setTags([ - 'crontab.rule' => $crontab->getRule(), - 'crontab.type' => $crontab->getType(), - 'crontab.options.is_single' => $crontab->isSingleton(), - 'crontab.options.is_on_one_server' => $crontab->isOnOneServer(), - ]); - - if (method_exists($event, 'getThrowable') && $exception = $event->getThrowable()) { - $transaction->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.code' => (string) $exception->getCode(), - ]) - ->setData([ - 'exception.message' => $exception->getMessage(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $transaction->setData(['exception.stack_trace' => (string) $exception]); + try { + $crontab = $event->crontab; + $transaction->setTags([ + 'crontab.rule' => $crontab->getRule(), + 'crontab.type' => $crontab->getType(), + 'crontab.options.is_single' => $crontab->isSingleton(), + 'crontab.options.is_on_one_server' => $crontab->isOnOneServer(), + ]); + + if (method_exists($event, 'getThrowable') && $exception = $event->getThrowable()) { + $transaction->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $transaction->setData(['exception.stack_trace' => (string) $exception]); + } } - } - - SentrySdk::getCurrentHub()->setSpan($transaction); + } finally { + SentrySdk::getCurrentHub()->setSpan($transaction); - $transaction->finish(); + $transaction->finish(); + } } protected function handleAmqpMessageProcessing(AmqpEvent\BeforeConsume $event): void @@ -593,45 +597,47 @@ protected function handleAmqpMessageProcessed(AmqpEvent\AfterConsume|AmqpEvent\F return; } - /** @var null|Carrier $carrier */ - $carrier = Context::get(Constants::TRACE_CARRIER); - - /** @var ConsumerMessage $message */ - $message = $event->getMessage(); - $transaction->setData([ - 'messaging.system' => 'amqp', - 'messaging.operation' => 'process', - 'messaging.message.id' => $carrier?->get('message_id'), - 'messaging.message.body.size' => $carrier?->get('body_size'), - 'messaging.message.receive.latency' => $carrier?->has('publish_time') ? (microtime(true) - $carrier->get('publish_time')) : null, - 'messaging.message.retry.count' => 0, - 'messaging.destination.name' => $carrier?->get('destination_name') ?: implode(', ', (array) $message->getRoutingKey()), - 'messaging.amqp.message.type' => $message->getTypeString(), - 'messaging.amqp.message.routing_key' => $message->getRoutingKey(), - 'messaging.amqp.message.exchange' => $message->getExchange(), - 'messaging.amqp.message.queue' => $message->getQueue(), - 'messaging.amqp.message.pool_name' => $message->getPoolName(), - 'messaging.amqp.message.result' => $event instanceof AmqpEvent\AfterConsume ? $event->getResult()->value : 'fail', - ]); - - if (method_exists($event, 'getThrowable') && $exception = $event->getThrowable()) { - $transaction->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.code' => (string) $exception->getCode(), - ]) - ->setData([ - 'exception.message' => $exception->getMessage(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $transaction->setData(['exception.stack_trace' => (string) $exception]); + try { + /** @var null|Carrier $carrier */ + $carrier = Context::get(Constants::TRACE_CARRIER); + + /** @var ConsumerMessage $message */ + $message = $event->getMessage(); + $transaction->setData([ + 'messaging.system' => 'amqp', + 'messaging.operation' => 'process', + 'messaging.message.id' => $carrier?->get('message_id'), + 'messaging.message.body.size' => $carrier?->get('body_size'), + 'messaging.message.receive.latency' => $carrier?->has('publish_time') ? (microtime(true) - $carrier->get('publish_time')) : null, + 'messaging.message.retry.count' => 0, + 'messaging.destination.name' => $carrier?->get('destination_name') ?: implode(', ', (array) $message->getRoutingKey()), + 'messaging.amqp.message.type' => $message->getTypeString(), + 'messaging.amqp.message.routing_key' => $message->getRoutingKey(), + 'messaging.amqp.message.exchange' => $message->getExchange(), + 'messaging.amqp.message.queue' => $message->getQueue(), + 'messaging.amqp.message.pool_name' => $message->getPoolName(), + 'messaging.amqp.message.result' => $event instanceof AmqpEvent\AfterConsume ? $event->getResult()->value : 'fail', + ]); + + if (method_exists($event, 'getThrowable') && $exception = $event->getThrowable()) { + $transaction->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $transaction->setData(['exception.stack_trace' => (string) $exception]); + } } - } - - SentrySdk::getCurrentHub()->setSpan($transaction); + } finally { + SentrySdk::getCurrentHub()->setSpan($transaction); - $transaction->finish(); + $transaction->finish(); + } } protected function handleKafkaMessageProcessing(KafkaEvent\BeforeConsume $event): void @@ -672,39 +678,41 @@ protected function handleKafkaMessageProcessed(KafkaEvent\AfterConsume|KafkaEven return; } - /** @var null|Carrier $carrier */ - $carrier = Context::get(Constants::TRACE_CARRIER); - $consumer = $event->getConsumer(); - $transaction->setData([ - 'messaging.system' => 'kafka', - 'messaging.operation' => 'process', - 'messaging.message.id' => $carrier?->get('message_id'), - 'messaging.message.body.size' => $carrier?->get('body_size'), - 'messaging.message.receive.latency' => $carrier?->has('publish_time') ? (microtime(true) - $carrier->get('publish_time')) : null, - 'messaging.message.retry.count' => 0, - 'messaging.destination.name' => $carrier?->get('destination_name') ?: (is_array($consumer->getTopic()) ? implode(',', $consumer->getTopic()) : $consumer->getTopic()), - 'messaging.kafka.consumer.group' => $consumer->getGroupId(), - 'messaging.kafka.consumer.pool' => $consumer->getPool(), - ]); - - if (method_exists($event, 'getThrowable') && $exception = $event->getThrowable()) { - $transaction->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.code' => (string) $exception->getCode(), - ]) - ->setData([ - 'exception.message' => $exception->getMessage(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $transaction->setData(['exception.stack_trace' => (string) $exception]); + try { + /** @var null|Carrier $carrier */ + $carrier = Context::get(Constants::TRACE_CARRIER); + $consumer = $event->getConsumer(); + $transaction->setData([ + 'messaging.system' => 'kafka', + 'messaging.operation' => 'process', + 'messaging.message.id' => $carrier?->get('message_id'), + 'messaging.message.body.size' => $carrier?->get('body_size'), + 'messaging.message.receive.latency' => $carrier?->has('publish_time') ? (microtime(true) - $carrier->get('publish_time')) : null, + 'messaging.message.retry.count' => 0, + 'messaging.destination.name' => $carrier?->get('destination_name') ?: (is_array($consumer->getTopic()) ? implode(',', $consumer->getTopic()) : $consumer->getTopic()), + 'messaging.kafka.consumer.group' => $consumer->getGroupId(), + 'messaging.kafka.consumer.pool' => $consumer->getPool(), + ]); + + if (method_exists($event, 'getThrowable') && $exception = $event->getThrowable()) { + $transaction->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $transaction->setData(['exception.stack_trace' => (string) $exception]); + } } - } - - SentrySdk::getCurrentHub()->setSpan($transaction); + } finally { + SentrySdk::getCurrentHub()->setSpan($transaction); - $transaction->finish(); + $transaction->finish(); + } } protected function handleAsyncQueueJobProcessing(AsyncQueueEvent\BeforeHandle $event): void @@ -735,36 +743,38 @@ protected function handleAsyncQueueJobProcessed(AsyncQueueEvent\AfterHandle|Asyn return; } - /** @var null|Carrier $carrier */ - $carrier = Context::get(Constants::TRACE_CARRIER, null, Coroutine::parentId()); - $transaction->setData([ - 'messaging.system' => 'async_queue', - 'messaging.operation' => 'process', - 'messaging.message.id' => $carrier?->get('message_id'), - 'messaging.message.body.size' => $carrier?->get('body_size'), - 'messaging.message.receive.latency' => $carrier?->has('publish_time') ? (microtime(true) - $carrier->get('publish_time')) : null, - 'messaging.message.retry.count' => $event->getMessage()->getAttempts(), - 'messaging.destination.name' => $carrier?->get('destination_name') ?: 'unknown queue', - ]); - - if (method_exists($event, 'getThrowable') && $exception = $event->getThrowable()) { - $transaction->setStatus(SpanStatus::internalError()) - ->setTags([ - 'error' => 'true', - 'exception.class' => $exception::class, - 'exception.code' => (string) $exception->getCode(), - ]) - ->setData([ - 'exception.message' => $exception->getMessage(), - ]); - if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { - $transaction->setData(['exception.stack_trace' => (string) $exception]); + try { + /** @var null|Carrier $carrier */ + $carrier = Context::get(Constants::TRACE_CARRIER, null, Coroutine::parentId()); + $transaction->setData([ + 'messaging.system' => 'async_queue', + 'messaging.operation' => 'process', + 'messaging.message.id' => $carrier?->get('message_id'), + 'messaging.message.body.size' => $carrier?->get('body_size'), + 'messaging.message.receive.latency' => $carrier?->has('publish_time') ? (microtime(true) - $carrier->get('publish_time')) : null, + 'messaging.message.retry.count' => $event->getMessage()->getAttempts(), + 'messaging.destination.name' => $carrier?->get('destination_name') ?: 'unknown queue', + ]); + + if (method_exists($event, 'getThrowable') && $exception = $event->getThrowable()) { + $transaction->setStatus(SpanStatus::internalError()) + ->setTags([ + 'error' => 'true', + 'exception.class' => $exception::class, + 'exception.code' => (string) $exception->getCode(), + ]) + ->setData([ + 'exception.message' => $exception->getMessage(), + ]); + if ($this->switcher->isTracingExtraTagEnabled('exception.stack_trace')) { + $transaction->setData(['exception.stack_trace' => (string) $exception]); + } } - } - - SentrySdk::getCurrentHub()->setSpan($transaction); + } finally { + SentrySdk::getCurrentHub()->setSpan($transaction); - $transaction->finish(); + $transaction->finish(); + } } private function parseRoute(Dispatched $dispatched): array From 0660dc82e85fc7ef526540ce9b381cc94e7dda7d Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:51:00 +0800 Subject: [PATCH 60/64] fix(EventHandleListener): add return type annotation for parseRoute method --- src/sentry/src/Tracing/Listener/EventHandleListener.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index d04b4859f..030aeae1b 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -777,6 +777,9 @@ protected function handleAsyncQueueJobProcessed(AsyncQueueEvent\AfterHandle|Asyn } } + /** + * @return array{0:string,1:array,2:string} + */ private function parseRoute(Dispatched $dispatched): array { $route = ''; From 56ca181ee3c876b92f4e2d9d53b3b8bad9f174a2 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:53:09 +0800 Subject: [PATCH 61/64] fix(EventHandleListener): optimize span data setting and simplify trace ID handling logic --- .../Tracing/Listener/EventHandleListener.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 030aeae1b..812a8be6a 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -321,9 +321,7 @@ protected function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Requ SpanContext::make() ->setOp('request.received') ->setDescription('request.received') - ->setData([ - 'coroutine.id' => Coroutine::id(), - ]) + ->setData(['coroutine.id' => Coroutine::id()]) ->setStatus(SpanStatus::ok()) ->setStartTimestamp(microtime(true)) ); @@ -346,16 +344,18 @@ protected function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\Reques { $span = SentrySdk::getCurrentHub()->getSpan(); - if (! $span || ! $traceId = (string) $span->getTraceId()) { + if (! $span) { return; } - if ($event instanceof RpcEvent\RequestHandled) { - if ($this->container->has(RpcContext::class)) { - $this->container->get(RpcContext::class)->set('sentry-trace-id', $traceId); + if ($traceId = $span->getTraceId()) { + if ($event instanceof RpcEvent\RequestHandled) { + if ($this->container->has(RpcContext::class)) { + $this->container->get(RpcContext::class)->set('sentry-trace-id', $traceId); + } + } elseif ($event->response instanceof ResponsePlusInterface) { + $event->response->setHeader('sentry-trace-id', $traceId); } - } elseif ($event->response instanceof ResponsePlusInterface) { - $event->response->setHeader('sentry-trace-id', $traceId); } $span->setStatus( From 38c248d16df248970c243e1c3c577284b8636ff8 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:56:59 +0800 Subject: [PATCH 62/64] Refactor trace ID handling in EventHandleListener Simplifies the logic for setting the 'sentry-trace-id' by always casting the trace ID to string and removing redundant conditional checks. This improves code clarity and ensures consistent trace ID handling for both RPC and HTTP responses. --- .../src/Tracing/Listener/EventHandleListener.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 812a8be6a..1d3936c03 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -348,14 +348,13 @@ protected function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\Reques return; } - if ($traceId = $span->getTraceId()) { - if ($event instanceof RpcEvent\RequestHandled) { - if ($this->container->has(RpcContext::class)) { - $this->container->get(RpcContext::class)->set('sentry-trace-id', $traceId); - } - } elseif ($event->response instanceof ResponsePlusInterface) { - $event->response->setHeader('sentry-trace-id', $traceId); + $traceId = (string) $span->getTraceId(); + if ($event instanceof RpcEvent\RequestHandled) { + if ($this->container->has(RpcContext::class)) { + $this->container->get(RpcContext::class)->set('sentry-trace-id', $traceId); } + } elseif ($event->response instanceof ResponsePlusInterface) { + $event->response->setHeader('sentry-trace-id', $traceId); } $span->setStatus( From fcecc1757c1dfe086b4c0dfb8f650afa35e7740a Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:59:02 +0800 Subject: [PATCH 63/64] fix(EventHandleListener): simplify trace ID handling in process method --- src/sentry/src/Tracing/Listener/EventHandleListener.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 1d3936c03..3e119231b 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -349,10 +349,8 @@ protected function handleRequestHandled(HttpEvent\RequestHandled|RpcEvent\Reques } $traceId = (string) $span->getTraceId(); - if ($event instanceof RpcEvent\RequestHandled) { - if ($this->container->has(RpcContext::class)) { - $this->container->get(RpcContext::class)->set('sentry-trace-id', $traceId); - } + if ($event instanceof RpcEvent\RequestHandled && $this->container->has(RpcContext::class)) { + $this->container->get(RpcContext::class)->set('sentry-trace-id', $traceId); } elseif ($event->response instanceof ResponsePlusInterface) { $event->response->setHeader('sentry-trace-id', $traceId); } From ffaae4b04935f0840da49d73defc78f81e3eecde Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Wed, 24 Sep 2025 16:08:55 +0800 Subject: [PATCH 64/64] fix(EventHandleListener, AmqpProducerAspect, AsyncQueueJobMessageAspect, CacheAspect, FilesystemAspect, GrpcAspect, GuzzleHttpClientAspect, KafkaProducerAspect): add coroutine ID to tracing data --- src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php | 2 ++ .../src/Tracing/Aspect/AsyncQueueJobMessageAspect.php | 2 ++ src/sentry/src/Tracing/Aspect/CacheAspect.php | 2 ++ src/sentry/src/Tracing/Aspect/FilesystemAspect.php | 3 ++- src/sentry/src/Tracing/Aspect/GrpcAspect.php | 2 +- src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php | 1 + src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php | 3 +++ src/sentry/src/Tracing/Listener/EventHandleListener.php | 6 ++++++ 8 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php b/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php index 9dd7ac625..213162740 100644 --- a/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php +++ b/src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php @@ -17,6 +17,7 @@ use FriendsOfHyperf\Sentry\Util\Carrier; use Hyperf\Amqp\Annotation\Producer; use Hyperf\Amqp\Message\ProducerMessage; +use Hyperf\Coroutine\Coroutine; use Hyperf\Di\Annotation\AnnotationCollector; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; @@ -101,6 +102,7 @@ function (Scope $scope) use ($proceedingJoinPoint, $producerMessage, $messageId, ->setDescription(sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName)) ->setOrigin('auto.amqp') ->setData([ + 'coroutine.id' => Coroutine::id(), 'messaging.system' => 'amqp', 'messaging.operation' => 'publish', 'messaging.message.id' => $messageId, diff --git a/src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php b/src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php index 731cdb9ca..7b38fcf1c 100644 --- a/src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php +++ b/src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php @@ -17,6 +17,7 @@ use FriendsOfHyperf\Sentry\Util\Carrier; use Hyperf\AsyncQueue\Driver\RedisDriver; use Hyperf\Context\Context; +use Hyperf\Coroutine\Coroutine; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; use Sentry\State\Scope; @@ -82,6 +83,7 @@ public function handlePush(ProceedingJoinPoint $proceedingJoinPoint) $destinationName = Context::get('sentry.messaging.destination.name', 'default'); $bodySize = (fn ($job) => strlen($this->packer->pack($job)))->call($driver, $job); $data = [ + 'coroutine.id' => Coroutine::id(), 'messaging.system' => 'async_queue', 'messaging.operation' => 'publish', 'messaging.message.id' => $messageId, diff --git a/src/sentry/src/Tracing/Aspect/CacheAspect.php b/src/sentry/src/Tracing/Aspect/CacheAspect.php index 3e583bb64..217b266af 100644 --- a/src/sentry/src/Tracing/Aspect/CacheAspect.php +++ b/src/sentry/src/Tracing/Aspect/CacheAspect.php @@ -13,6 +13,7 @@ use FriendsOfHyperf\Sentry\Switcher; use FriendsOfHyperf\Sentry\Tracing\SpanStarter; +use Hyperf\Coroutine\Coroutine; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; use Sentry\State\Scope; @@ -93,6 +94,7 @@ function (Scope $scope) use ($proceedingJoinPoint, $method) { ->setDescription(implode(', ', $keys)) ->setOrigin('auto.cache') ->setData([ + 'coroutine.id' => Coroutine::id(), 'cache.key' => $keys, 'cache.ttl' => $arguments['ttl'] ?? null, 'item_size' => match (true) { diff --git a/src/sentry/src/Tracing/Aspect/FilesystemAspect.php b/src/sentry/src/Tracing/Aspect/FilesystemAspect.php index 686a07442..8975553c8 100644 --- a/src/sentry/src/Tracing/Aspect/FilesystemAspect.php +++ b/src/sentry/src/Tracing/Aspect/FilesystemAspect.php @@ -13,6 +13,7 @@ use FriendsOfHyperf\Sentry\Aspect\FilesystemAspect as BaseFilesystemAspect; use FriendsOfHyperf\Sentry\Tracing\SpanStarter; +use Hyperf\Coroutine\Coroutine; use Hyperf\Di\Aop\ProceedingJoinPoint; use Override; use Sentry\State\Scope; @@ -37,7 +38,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) ->setOp($op) ->setDescription($description) ->setOrigin('auto.filesystem') - ->setData($data) + ->setData(['coroutine.id' => Coroutine::id()] + $data) ); } } diff --git a/src/sentry/src/Tracing/Aspect/GrpcAspect.php b/src/sentry/src/Tracing/Aspect/GrpcAspect.php index 1fbac02b9..ca00fd5a2 100644 --- a/src/sentry/src/Tracing/Aspect/GrpcAspect.php +++ b/src/sentry/src/Tracing/Aspect/GrpcAspect.php @@ -42,9 +42,9 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $method = $proceedingJoinPoint->arguments['keys']['method']; $options = $proceedingJoinPoint->arguments['keys']['options']; $data = [ + 'coroutine.id' => Coroutine::id(), 'grpc.method' => $method, 'grpc.options' => $options, - 'coroutine.id' => Coroutine::id(), ]; $parent = SentrySdk::getCurrentHub()->getSpan(); diff --git a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php index 1b23ff086..6787cd672 100644 --- a/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php +++ b/src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php @@ -185,6 +185,7 @@ function (Scope $scope) use ($proceedingJoinPoint, $options, $guzzleConfig) { ->setOp('http.client') ->setDescription($request->getMethod() . ' ' . (string) $request->getUri()) ->setOrigin('auto.http.client') + ->setData(['coroutine.id' => Coroutine::id()]) ); } } diff --git a/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php b/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php index d3ba2e5db..7f573b451 100644 --- a/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php +++ b/src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php @@ -15,6 +15,7 @@ use FriendsOfHyperf\Sentry\Switcher; use FriendsOfHyperf\Sentry\Tracing\SpanStarter; use FriendsOfHyperf\Sentry\Util\Carrier; +use Hyperf\Coroutine\Coroutine; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; use longlang\phpkafka\Producer\ProduceMessage; @@ -84,6 +85,7 @@ function (Scope $scope) use ($proceedingJoinPoint, $messageId, $destinationName, ->setDescription(sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName)) ->setOrigin('auto.kafka') ->setData([ + 'coroutine.id' => Coroutine::id(), 'messaging.system' => 'kafka', 'messaging.operation' => 'publish', 'messaging.message.id' => $messageId, @@ -123,6 +125,7 @@ function (Scope $scope) use ($proceedingJoinPoint, $messages) { ->setOp('queue.publish') ->setDescription(sprintf('%s::%s()', $proceedingJoinPoint->className, $proceedingJoinPoint->methodName)) ->setOrigin('auto.kafka') + ->setData(['coroutine.id' => Coroutine::id()]) ); } } diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 3e119231b..1d138063f 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -289,6 +289,7 @@ protected function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Requ default => [$route, TransactionSource::route()], }; $data = [ + 'coroutine.id' => Coroutine::id(), 'url.scheme' => $request->getUri()->getScheme(), 'url.path' => $path, 'http.request.method' => $method, @@ -395,6 +396,7 @@ protected function handleCommandStarting(CommandEvent\BeforeHandle $event): void ->setDescription($command->getDescription()) ->setOrigin('auto.command') ->setSource(TransactionSource::custom()) + ->setData(['coroutine.id' => Coroutine::id()]) ); } @@ -515,6 +517,7 @@ protected function handleCrontabTaskStarting(CrontabEvent\BeforeExecute $event): ->setDescription($crontab->getMemo()) ->setOrigin('auto.crontab') ->setSource(TransactionSource::task()) + ->setData(['coroutine.id' => Coroutine::id()]) ); } @@ -583,6 +586,7 @@ protected function handleAmqpMessageProcessing(AmqpEvent\BeforeConsume $event): ->setDescription($message::class) ->setOrigin('auto.amqp') ->setSource(TransactionSource::custom()) + ->setData(['coroutine.id' => Coroutine::id()]) ); } @@ -664,6 +668,7 @@ protected function handleKafkaMessageProcessing(KafkaEvent\BeforeConsume $event) ->setDescription($consumer::class) ->setOrigin('auto.kafka') ->setSource(TransactionSource::custom()) + ->setData(['coroutine.id' => Coroutine::id()]) ); } @@ -729,6 +734,7 @@ protected function handleAsyncQueueJobProcessing(AsyncQueueEvent\BeforeHandle $e ->setDescription('async_queue: ' . $job::class) ->setOrigin('auto.async_queue') ->setSource(TransactionSource::custom()) + ->setData(['coroutine.id' => Coroutine::id()]) ); }