Skip to content

refactor(sentry): replace SpanStarter trait with global functions#920

Merged
huangdijia merged 6 commits into
mainfrom
refactor/sentry-replace-spanstarter-trait-with-global-functions
Sep 25, 2025
Merged

refactor(sentry): replace SpanStarter trait with global functions#920
huangdijia merged 6 commits into
mainfrom
refactor/sentry-replace-spanstarter-trait-with-global-functions

Conversation

@huangdijia
Copy link
Copy Markdown
Contributor

@huangdijia huangdijia commented Sep 25, 2025

Summary

This PR refactors the Sentry integration by replacing the SpanStarter trait with global function calls, improving code consistency and preparing for deprecation cleanup.

Changes Made

  • New Function.php file: Added global trace() and startTransaction() functions
  • Removed trait dependencies: Replaced SpanStarter trait usage across all aspect classes and listeners:
    • AmqpProducerAspect
    • AsyncQueueJobMessageAspect
    • CacheAspect
    • CoordinatorAspect
    • CoroutineAspect
    • DbAspect
    • ElasticsearchAspect
    • FilesystemAspect
    • GrpcAspect
    • GuzzleHttpClientAspect
    • KafkaProducerAspect
    • RedisAspect
    • RpcAspect
    • TraceAnnotationAspect
    • EventHandleListener
  • Updated autoloading: Added Function.php to autoload configuration in both main and sentry-specific composer.json
  • Deprecated SpanStarter: Marked the trait as deprecated with removal notice for v3.2

Benefits

  • Cleaner API: Global functions provide a more straightforward interface
  • Reduced dependencies: Eliminates trait usage across the codebase
  • Better consistency: Unified approach to span creation and tracing
  • Backward compatibility: Existing trait methods remain functional with deprecation warnings
  • Future maintenance: Prepares for clean removal of deprecated trait in v3.2

Migration Path

  • Existing code using the trait will continue to work but will receive deprecation warnings
  • New code should use the global functions: FriendsOfHyperf\Sentry\trace() and FriendsOfHyperf\Sentry\startTransaction()
  • The trait will be removed in v3.2

Test Plan

  • All existing Sentry tracing functionality continues to work
  • Global functions properly create spans and transactions
  • Aspect-based tracing operates correctly across all supported integrations
  • Deprecation warnings are shown when using the trait methods
  • No breaking changes to public API

Summary by CodeRabbit

  • 新功能
    • 新增并自动加载全局的 startTransaction/trace 辅助方法,支持更便捷的一键开启事务与追踪。
  • 重构
    • 多处组件从 trait 驱动切换为函数式追踪调用,统一追踪入口,降低耦合并提升一致性与稳定性。
  • 弃用
    • 旧的基于 trait 的追踪工具被标记为弃用,后续版本将移除,建议迁移至新的全局方法。

- Create new Function.php with global trace() and startTransaction() functions
- Replace SpanStarter trait usage with global function calls across all aspects
- Add Function.php to autoload configuration in composer.json files
- Mark SpanStarter trait as deprecated with removal notice
- Improve code consistency and prepare for trait removal in v3.2

This change provides a cleaner API and reduces trait dependencies while
maintaining backward compatibility through deprecation warnings.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 25, 2025

Warning

Rate limit exceeded

@huangdijia has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 2 minutes and 50 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 4343221 and 14eeed6.

📒 Files selected for processing (3)
  • src/sentry/src/Function.php (1 hunks)
  • src/sentry/src/Tracing/SpanStarter.php (2 hunks)
  • src/sentry/src/Tracing/Tracer.php (1 hunks)

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

将原本由 SpanStarter trait 提供的 tracing/transaction 启动能力迁移为全局函数(startTransactiontrace),新增 src/sentry/src/Function.php 并通过 composer autoload files 自动加载;大量 Aspect 与 Listener 改为调用全局函数;新增标注废弃的 SpanStarter trait 以保持兼容。

Changes

Cohort / File(s) Summary
Autoload 配置
composer.json, src/sentry/composer.json
在 autoload.files 中加入 src/sentry/src/Function.php,使全局函数自动加载,保留原有 PSR-4 映射。
全局函数实现
src/sentry/src/Function.php
新增命名空间函数 startTransaction(TransactionContext, array)trace(callable, SpanContext),封装 Hub/Scope 操作、采样上下文与异常标注逻辑。
兼容性 trait(已弃用)
src/sentry/src/Tracing/SpanStarter.php
新增 SpanStarter trait(带 deprecation 注释),提供受保护的 startTransactiontrace 方法以兼容旧用法。
Aspect 批量切换为函数式调用
src/sentry/src/Tracing/Aspect/*
.../AmqpProducerAspect.php, .../AsyncQueueJobMessageAspect.php, .../CacheAspect.php, .../CoordinatorAspect.php, .../CoroutineAspect.php, .../DbAspect.php, .../ElasticsearchAspect.php, .../FilesystemAspect.php, .../GrpcAspect.php, .../GuzzleHttpClientAspect.php, .../KafkaProducerAspect.php, .../RedisAspect.php, .../RpcAspect.php, .../TraceAnnotationAspect.php
统一移除 SpanStarter trait 与相关导入;新增 use function FriendsOfHyperf\Sentry\trace(并在需要处引入 startTransaction);将 $this->trace(...) / $this->startTransaction(...) 替换为全局函数调用,逻辑保持不变。
事件监听切换为函数式调用
src/sentry/src/Tracing/Listener/EventHandleListener.php
移除 trait;在多处事件处理逻辑中改为使用全局 trace(...)startTransaction(...),调整导入与调用点。

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor A as 调用方(Aspect/Listener)
    participant T as trace(callable, SpanContext)
    participant H as Sentry Hub/Scope
    participant C as 被包装回调

    A->>T: trace(callable, SpanContext)
    T->>H: 获取并克隆 Hub,pushScope,设置当前 Span
    T->>C: 执行回调
    alt 正常返回
        C-->>T: result
        T->>H: 完成/更新 Span 状态
        T-->>A: 返回 result
    else 抛出异常
        C-->>T: exception
        T->>H: 标注 error、记录异常类/码/消息(可选堆栈)
        T-->>A: 重新抛出异常
    end
Loading
sequenceDiagram
    autonumber
    actor A as 调用方(Aspect/Listener)
    participant S as startTransaction(TransactionContext, SamplingCtx)
    participant H as Sentry Hub/Scope

    A->>S: startTransaction(ctx, samplingCtx)
    S->>H: 获取并克隆 Hub,pushScope
    S->>H: 开启 Transaction 并将其设为 current span
    S-->>A: 返回 Transaction
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • xuanyanwow
  • zds-s

Poem

小兔敲键跳三步,
旧 trait 悄然归仓库;
全局函数轻轻呼,
事务追踪稳如初。
=(^•ܫ•^)= 日志入库,欢喜舞。

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 该标题以 conventional commit 形式简洁地概括了主要改动,即将 SpanStarter trait 替换为全局函数,准确反映了 PR 的核心重构内容,有助于团队快速了解变更重点。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@huangdijia huangdijia requested a review from Copilot September 25, 2025 13:20
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (8)
src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php (1)

71-189: 可能泄露敏感信息:完整请求/响应头部与正文片段上报

setData 中包含 http.request.headers、http.response.headers,且响应正文在某些情况下会上传。Headers 常包含 Authorization/Cookie/Set-Cookie/X-API-Key 等敏感信息;正文也可能含 PII。建议最少进行头部白/黑名单过滤,并用开关控制是否上报。

可以局部修正 on_stats 里的 setData 构造,示例(仅示意关键点):

-                $span->setData([
+                // 构造脱敏后的请求头
+                $reqHeaders = $request->getHeaders();
+                $sanitizedReqHeaders = [];
+                foreach ($reqHeaders as $k => $v) {
+                    $lk = strtolower($k);
+                    if (in_array($lk, ['authorization','cookie','proxy-authorization','x-api-key'], true)) {
+                        continue;
+                    }
+                    $sanitizedReqHeaders[$k] = $v;
+                }
+
+                $data = [
                   // 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'),
-                  'http.request.headers' => $request->getHeaders(),
+                  // 仅在开关开启时上报请求头,且使用脱敏版本
+                  'http.request.headers' => $this->switcher->isTracingExtraTagEnabled('http.request.headers') ? $sanitizedReqHeaders : null,
                   // Other
                   'coroutine.id' => Coroutine::id(),
                   'http.system' => 'guzzle',
                   'http.guzzle.config' => $guzzleConfig,
                   'http.guzzle.options' => $options ?? [],
                   'duration' => $stats->getTransferTime() * 1000, // in milliseconds
-                ]);
+                ];
+                // 去除为 null 的键,避免污染数据
+                $span->setData(array_filter($data, static fn($v) => $v !== null));
@@
-                        $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'),
-                        ]);
+                        // 脱敏响应头,仅在开关开启时上报
+                        $respHeaders = $response->getHeaders();
+                        $sanitizedRespHeaders = [];
+                        foreach ($respHeaders as $k => $v) {
+                            if (in_array(strtolower($k), ['set-cookie'], true)) {
+                                continue;
+                            }
+                            $sanitizedRespHeaders[$k] = $v;
+                        }
+                        $respData = [
+                            'http.response.status_code' => $response->getStatusCode(),
+                            'http.response.reason' => $response->getReasonPhrase(),
+                            'http.response.headers' => $this->switcher->isTracingExtraTagEnabled('http.response.headers') ? $sanitizedRespHeaders : null,
+                            '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'),
+                        ];
+                        $span->setData(array_filter($respData, static fn($v) => $v !== null));

说明:

  • 对敏感头部做黑名单过滤,并以开关控制是否上报 headers。
  • 保持已有的 http.response.body.contents 行为受开关控制。
src/sentry/src/Tracing/Aspect/CacheAspect.php (1)

98-102: 修复 strlen(json_encode(...)) 在失败时的类型错误风险
json_encode 失败会返回 false,传入 strlen 会触发 TypeError(PHP 8.1+)。为安全应转为字符串。

建议修改为:

-                    '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,
-                    },
+                    'item_size' => match (true) {
+                        isset($arguments['value']) => strlen((string) json_encode($arguments['value'])),
+                        isset($arguments['values']) && is_array($arguments['values']) => strlen((string) json_encode(array_values($arguments['values']))),
+                        default => 0,
+                    },
src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php (1)

96-115: 可能的空 Span 导致 Carrier 构建报错
这里未判断 $scope->getSpan() 结果;若无当前 span,Carrier::fromSpan($span) 可能报错。建议与 AMQP 处一致增加空值保护。

建议修改为:

-            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);
+            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,
+                    ]);
+                    Context::set(Constants::TRACE_CARRIER, $carrier);
+                }
 
                 return $proceedingJoinPoint->process();
             },
src/sentry/src/Tracing/Aspect/DbAspect.php (1)

81-86: 安全遍历绑定参数,避免 foreach(null) 警告
当未提供 bindings 时,foreach 目标可能为 null,存在运行时警告风险。

建议改为:

-        if ($this->switcher->isTracingExtraTagEnabled('db.sql.bindings', true)) {
-            $data['db.sql.bindings'] = $arguments['arguments']['bindings'] ?? [];
-            foreach ($arguments['arguments']['bindings'] as $key => $value) {
-                $data['db.parameter.' . $key] = $value;
-            }
-        }
+        if ($this->switcher->isTracingExtraTagEnabled('db.sql.bindings', true)) {
+            $bindings = (array) ($arguments['arguments']['bindings'] ?? []);
+            $data['db.sql.bindings'] = $bindings;
+            foreach ($bindings as $key => $value) {
+                $data['db.parameter.' . $key] = $value;
+            }
+        }
src/sentry/src/Tracing/Listener/EventHandleListener.php (4)

223-236: 事务 BEGIN 跨度被立即结束,后续 COMMIT/ROLLBACK 结束了错误的 span(严重问题)。

这里使用 trace() 会在回调返回后立刻 finish 事务 span;随后的 COMMIT/ROLLBACK 调用 getCurrentHub()->getSpan() 取到的很可能是请求的活动 span(例如 request.received),导致错误的 span 被 finish。

建议显式创建 child span、设置为当前活动 span,并存入 Context 以便后续提交/回滚时准确结束:

-        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,
-                ])
-        );
+        $transaction = SentrySdk::getCurrentHub()->getTransaction();
+        if ($transaction) {
+            $span = $transaction->startChild(
+                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,
+                    ])
+            );
+            SentrySdk::getCurrentHub()->setSpan($span);
+            Context::set('sentry.db.transaction.span.' . $event->connectionName, $span);
+        }

239-251: COMMIT 结束了当前活动 span 而非事务 span(严重问题)。

应取回 BEGIN 时存入 Context 的事务 span 并结束,避免误伤 request.received 等其他 span。

-        if (! $span = SentrySdk::getCurrentHub()->getSpan()) {
-            return;
-        }
-
-        $span->setStatus(SpanStatus::ok())
-            ->setDescription('COMMIT')
-            ->finish();
+        $span = Context::get('sentry.db.transaction.span.' . $event->connectionName);
+        if (! $span) {
+            return;
+        }
+        $span->setStatus(SpanStatus::ok())
+            ->setDescription('COMMIT')
+            ->finish();
+        Context::set('sentry.db.transaction.span.' . $event->connectionName, null);
+        SentrySdk::getCurrentHub()->setSpan(SentrySdk::getCurrentHub()->getTransaction());

253-265: ROLLBACK 同样结束了错误的 span(严重问题)。

与 COMMIT 相同,需用 Context 中保存的事务 span。

-        if (! $span = SentrySdk::getCurrentHub()->getSpan()) {
-            return;
-        }
-
-        $span->setStatus(SpanStatus::internalError())
-            ->setDescription('ROLLBACK')
-            ->finish();
+        $span = Context::get('sentry.db.transaction.span.' . $event->connectionName);
+        if (! $span) {
+            return;
+        }
+        $span->setStatus(SpanStatus::internalError())
+            ->setDescription('ROLLBACK')
+            ->finish();
+        Context::set('sentry.db.transaction.span.' . $event->connectionName, null);
+        SentrySdk::getCurrentHub()->setSpan(SentrySdk::getCurrentHub()->getTransaction());

458-501: 避免默认记录 Redis 参数,建议受开关控制;同时保持现有结果记录开关。

Redis 参数可能包含敏感信息(安全与合规风险)。建议仅在明确开启时记录。

应用以下修改:将参数写入从 setData 初始数组移除,改为在回调中按开关写入。

-        trace(
-            function (Scope $scope) use ($event) {
+        trace(
+            function (Scope $scope) use ($event) {
                 if (! $span = $scope->getSpan()) {
                     return;
                 }
 
                 if ($this->switcher->isTracingExtraTagEnabled('redis.result')) {
                     $span->setData(['db.redis.result' => $event->result]);
                 }
 
+                if ($this->switcher->isTracingExtraTagEnabled('redis.parameters')) {
+                    $span->setData(['db.redis.parameters' => $event->parameters]);
+                }
+
                 if ($exception = $event->throwable) {
                     $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]);
                     }
                 }
             },
             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)
         );
🧹 Nitpick comments (13)
composer.json (1)

238-238: 命名一致性建议:Function.php → Functions.php

其它子包普遍采用 Functions.php 命名,建议同一化,降低认知成本(可延后处理,不阻塞合并)。

src/sentry/src/Tracing/SpanStarter.php (6)

40-51: 缺少运行时弃用告警,建议显式触发

PR 说明称“trait 方法会发出弃用告警”,当前仅有 PHPDoc 标注,未触发运行时 deprecation。建议在方法入口触发 E_USER_DEPRECATED,便于应用方尽早迁移。

建议改动:

 protected function startTransaction(TransactionContext $transactionContext, array $customSamplingContext = []): Transaction
 {
+    @trigger_error(
+        'FriendsOfHyperf\Sentry\Tracing\SpanStarter::startTransaction() 已废弃,将在 v3.2 移除,请改用 FriendsOfHyperf\Sentry\startTransaction()。',
+        E_USER_DEPRECATED
+    );

64-105: 为 trace() 方法也添加弃用告警

与上同理,建议在方法开头加入触发弃用提示。

 protected function trace(callable $trace, SpanContext $context)
 {
+    @trigger_error(
+        'FriendsOfHyperf\Sentry\Tracing\SpanStarter::trace() 已废弃,将在 v3.2 移除,请改用 FriendsOfHyperf\Sentry\trace()。',
+        E_USER_DEPRECATED
+    );

110-133: 为 startSpan() 添加弃用告警

保持一致性。

 protected function startSpan(
     ?string $op = null,
     ?string $description = null,
     ?string $origin = null,
     bool $asParent = false
 ): ?Span {
+    @trigger_error(
+        'FriendsOfHyperf\Sentry\Tracing\SpanStarter::startSpan() 已废弃,将在 v3.2 移除。',
+        E_USER_DEPRECATED
+    );

139-144: 为 startRequestTransaction() 添加弃用告警

 protected function startRequestTransaction(ServerRequestInterface $request, ...$options): Transaction
 {
+    @trigger_error(
+        'FriendsOfHyperf\Sentry\Tracing\SpanStarter::startRequestTransaction() 已废弃,将在 v3.2 移除,请改用 FriendsOfHyperf\Sentry\startTransaction()。',
+        E_USER_DEPRECATED
+    );

149-152: 为 startCoroutineTransaction() 添加弃用告警

 protected function startCoroutineTransaction(Span $parent, ...$options): Transaction
 {
+    @trigger_error(
+        'FriendsOfHyperf\Sentry\Tracing\SpanStarter::startCoroutineTransaction() 已废弃,将在 v3.2 移除,请改用 FriendsOfHyperf\Sentry\startTransaction()。',
+        E_USER_DEPRECATED
+    );

157-186: 为 continueTrace() 添加弃用告警

 protected function continueTrace(string $sentryTrace = '', string $baggage = '', ...$options): Transaction
 {
+    @trigger_error(
+        'FriendsOfHyperf\Sentry\Tracing\SpanStarter::continueTrace() 已废弃,将在 v3.2 移除,请改用 FriendsOfHyperf\Sentry\startTransaction() + Sentry\continueTrace()。',
+        E_USER_DEPRECATED
+    );
src/sentry/src/Tracing/Aspect/RedisAspect.php (1)

82-95: 改用全局 trace() 无功能差异,建议附带参数脱敏开关

当前已通过 switcher 开关控制 redis.result。建议未来也为 db.redis.parameters 增加可选开关或脱敏(避免把 key/参数原样上传到 Sentry)。

src/sentry/src/Tracing/Aspect/RpcAspect.php (1)

102-122: 为上报的 rpc.context 增加可控与脱敏,避免潜在敏感数据泄露

当前会把 Rpc\Context 全量塞进 span data,可能含鉴权/业务敏感信息。建议用开关控制并按需裁剪。

-                    if ($span && $this->container->has(Rpc\Context::class)) {
+                    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(),
-                        ]);
+                        if ($this->switcher->isTracingExtraTagEnabled('rpc.context')) {
+                            $ctxData = $this->container->get(Rpc\Context::class)->getData();
+                            // 可在此处做白/黑名单过滤
+                            $span->setData(['rpc.context' => $ctxData]);
+                        }
src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php (1)

64-89: 建议将 arguments 记录改为可开关的额外标签,避免高开销与潜在序列化失败
arguments 可能体积大或含不可序列化内容,建议受开关控制,默认不记录。

可在当前片段内直接改为条件追加:

-            SpanContext::make()
+            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' => (string) json_encode($proceedingJoinPoint->arguments['keys'], JSON_UNESCAPED_UNICODE),
-                    // TODO
-                    // 'http.request.method' => '',
-                    // 'url.full' => '',
-                    // 'server.host' => '',
-                    // 'server.port' => '',
-                ])
+                ->setData([
+                    'coroutine.id' => Coroutine::id(),
+                    'db.system' => 'elasticsearch',
+                    'db.operation.name' => $proceedingJoinPoint->methodName,
+                    // TODO
+                    // 'http.request.method' => '',
+                    // 'url.full' => '',
+                    // 'server.host' => '',
+                    // 'server.port' => '',
+                ] + ($this->switcher->isTracingExtraTagEnabled('elasticsearch.arguments') ? [
+                    'arguments' => (string) json_encode($proceedingJoinPoint->arguments['keys'], JSON_UNESCAPED_UNICODE),
+                ] : []))
src/sentry/src/Tracing/Listener/EventHandleListener.php (1)

205-214: DB 查询跨度的结束时间可能不被采纳,建议在回调中显式 finish 指定 endTimestamp。

Sentry 的 trace() 会在回调返回后自动 finish 当前 span;若仅在 SpanContext 上设置 endTimestamp,finish() 可能用“现在”覆盖,导致时长失真。建议在回调内以事件时长计算的时间戳 finish。

可按以下方式修改本段,确保使用事件耗时作为结束时间:

-        trace(
-            fn () => null,
-            SpanContext::make()
-                ->setOp('db.sql.query')
-                ->setDescription($event->sql)
-                ->setOrigin('auto.db')
-                ->setStartTimestamp($startTimestamp)
-                ->setData($data)
-                ->setEndTimestamp($startTimestamp + $event->time / 1000)
-        );
+        trace(
+            function (Scope $scope) use ($event, $startTimestamp) {
+                $scope->getSpan()?->finish($startTimestamp + $event->time / 1000);
+                return null;
+            },
+            SpanContext::make()
+                ->setOp('db.sql.query')
+                ->setDescription($event->sql)
+                ->setOrigin('auto.db')
+                ->setStartTimestamp($startTimestamp)
+                ->setData($data)
+        );
src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php (1)

62-94: sendAsync 中 body 大小计算对非字符串值不安全,建议显式转为字符串。

避免 strlen 非字符串产生警告,建议对 value 做 (string) 转换后再计算长度。

示例(需在本段之外调整定义处):

  • $value = (string) ($proceedingJoinPoint->arguments['keys']['value'] ?? '');
  • $bodySize = strlen($value);
src/sentry/src/Function.php (1)

52-97: trace 封装合理,异常标注与开关检查完整,LGTM。

可选优化:

  • 为 trace 声明返回类型 mixed,增强类型提示。
  • 函数定义外层增加 function_exists 守卫,避免重复加载时潜在报错(低概率)。
-function trace(callable $trace, SpanContext $context)
+function trace(callable $trace, SpanContext $context): mixed

可选守卫(示例,需包裹函数定义,非必须):

if (! function_exists(__NAMESPACE__ . '\trace')) { /* 定义 trace */ }
if (! function_exists(__NAMESPACE__ . '\startTransaction')) { /* 定义 startTransaction */ }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aeb5ca2 and cc85d69.

📒 Files selected for processing (19)
  • composer.json (1 hunks)
  • src/sentry/composer.json (1 hunks)
  • src/sentry/src/Function.php (1 hunks)
  • src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/CacheAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/CoordinatorAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/CoroutineAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/DbAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/FilesystemAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/GrpcAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php (3 hunks)
  • src/sentry/src/Tracing/Aspect/RedisAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/RpcAspect.php (2 hunks)
  • src/sentry/src/Tracing/Aspect/TraceAnnotationAspect.php (2 hunks)
  • src/sentry/src/Tracing/Listener/EventHandleListener.php (10 hunks)
  • src/sentry/src/Tracing/SpanStarter.php (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (16)
src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/FilesystemAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Listener/EventHandleListener.php (2)
src/sentry/src/Function.php (2)
  • startTransaction (30-41)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (2)
  • startTransaction (40-51)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/GrpcAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/RpcAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/CoordinatorAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/CacheAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Function.php (3)
src/sentry/class_map/SentrySdk.php (3)
  • SentrySdk (24-65)
  • setCurrentHub (61-64)
  • getCurrentHub (51-54)
src/sentry/src/Tracing/SpanStarter.php (2)
  • trace (64-105)
  • startTransaction (40-51)
src/sentry/src/Switcher.php (2)
  • isTracingExtraTagEnabled (85-88)
  • Switcher (19-137)
src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/TraceAnnotationAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/RedisAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/CoroutineAspect.php (2)
src/sentry/src/Function.php (1)
  • startTransaction (30-41)
src/sentry/src/Tracing/SpanStarter.php (1)
  • startTransaction (40-51)
src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
src/sentry/src/Tracing/Aspect/DbAspect.php (2)
src/sentry/src/Function.php (1)
  • trace (52-97)
src/sentry/src/Tracing/SpanStarter.php (1)
  • trace (64-105)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Test on PHP 8.3 with Swoole 5.1.7
  • GitHub Check: Test on PHP 8.3 with Swoole 6.0.2
  • GitHub Check: Test on PHP 8.1 with Swoole 6.0.2
  • GitHub Check: Test on PHP 8.2 with Swoole 6.0.2
  • GitHub Check: Test on PHP 8.1 with Swoole 5.1.7
  • GitHub Check: Test on PHP 8.2 with Swoole 5.1.7
  • GitHub Check: Test on PHP 8.2 with Swoole 6.0.2
  • GitHub Check: Test on PHP 8.1 with Swoole 5.1.7
  • GitHub Check: Test on PHP 8.2 with Swoole 5.1.7
  • GitHub Check: Test on PHP 8.1 with Swoole 6.0.2
  • GitHub Check: Test on PHP 8.3 with Swoole 5.1.7
🔇 Additional comments (29)
src/sentry/src/Tracing/Aspect/GrpcAspect.php (1)

66-73: 迁移到全局 trace() 的改动正确

语义保持一致,父 Span 存在且采样时才创建子 Span,并注入分布式追踪头。改动 LGTM。

src/sentry/src/Tracing/Aspect/CoordinatorAspect.php (1)

42-52: 改用全局 trace() 实现一致化,LGTM

保持原有行为与数据字段,变更安全。

src/sentry/composer.json (1)

49-53: 已验证 Function.php 路径及大小写正确
在子包启用 Function.php 自动加载,符合预期,与根 composer.json 呼应,保证独立安装时可加载全局函数。

composer.json (1)

238-238: 确认无重复定义全局函数

经检索,trace()startTransaction() 仅在 src/sentry/src/Function.php 中以全局函数形式定义;SpanStarter trait 中的同名方法作用于类作用域,不会与全局函数冲突。

src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php (1)

21-22: 切换到全局 trace() 导入 — LGTM
实现与全局函数保持一致,清晰简洁。

src/sentry/src/Tracing/Aspect/CacheAspect.php (2)

21-21: 切换到全局 trace() 导入 — LGTM
保持与新 API 一致。


69-97: trace 包装迁移 — LGTM
行为保持一致,闭包内通过 tap 注入附加数据的方式清晰。

src/sentry/src/Tracing/Aspect/FilesystemAspect.php (2)

21-22: 切换到全局 trace() 导入 — LGTM
风格统一。


34-41: trace 包装迁移 — LGTM
逻辑保持不变,描述和数据结构一致。

src/sentry/src/Tracing/Aspect/AmqpProducerAspect.php (2)

27-28: 切换到全局 trace() 导入 — LGTM
符合本次重构方向。


81-116: trace 包装迁移 — LGTM
在闭包中注入 Carrier 并写入 AMQP headers 的逻辑保持一致。

src/sentry/src/Tracing/Aspect/TraceAnnotationAspect.php (2)

22-23: 切换到全局 trace() 导入 — LGTM
一致性良好。


55-71: trace 包装迁移 — LGTM
结果数据已受开关 annotation.result 控制,符合预期。

src/sentry/src/Tracing/Aspect/AsyncQueueJobMessageAspect.php (1)

25-26: 切换到全局 trace() 导入 — LGTM
无行为变更。

src/sentry/src/Tracing/Aspect/DbAspect.php (2)

25-26: 切换到全局 trace() 导入 — LGTM
无功能性风险。


88-103: trace 包装迁移 — LGTM
结果记录已受开关 db.result 控制,行为与原逻辑一致。

src/sentry/src/Tracing/Listener/EventHandleListener.php (7)

52-53: 引入全局函数方式正确,LGTM。


305-314: HTTP/RPC 事务启动逻辑清晰,LGTM。


391-399: 命令事务启动迁移到全局函数,LGTM。


512-520: Crontab 事务启动迁移到全局函数,LGTM。


581-589: AMQP 事务启动迁移到全局函数,LGTM。


663-671: Kafka 消费事务启动迁移到全局函数,LGTM。


729-737: 异步队列事务启动迁移到全局函数,LGTM。

src/sentry/src/Tracing/Aspect/CoroutineAspect.php (2)

24-24: 引入 startTransaction 全局函数方式正确,LGTM。


93-100: 协程内衍生独立事务的处理方式合理,LGTM。

  • 正确使用 continueTrace 继承 traceparent/baggage。
  • 作用域隔离依赖 Hub 的协程上下文,不干扰父事务。
src/sentry/src/Tracing/Aspect/KafkaProducerAspect.php (2)

25-26: 迁移到全局 trace 函数,LGTM。


102-129: 批量发送的链路注入与元数据设置正确,LGTM。

src/sentry/src/Function.php (2)

30-41: startTransaction 实现与既有 SpanStarter 行为一致,LGTM。


1-97: Composer autoload 配置正确

composer.json 已包含 src/sentry/src/Function.php,且 src/sentry/composer.json 已包含 src/Function.php,Function.php 已通过 autoload.files 正确加载,无需变更。

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the Sentry integration by replacing the SpanStarter trait with global function calls, streamlining the codebase and preparing for future deprecation cleanup.

  • Introduces new global trace() and startTransaction() functions in Function.php
  • Replaces trait usage across all aspect classes and listeners with direct function calls
  • Marks the SpanStarter trait as deprecated with removal planned for v3.2

Reviewed Changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/sentry/src/Function.php Adds new global functions with error handling and tracing functionality
src/sentry/src/Tracing/SpanStarter.php Marks trait and methods as deprecated with appropriate warnings
Multiple Aspect classes Removes SpanStarter trait usage and replaces with global function calls
src/sentry/src/Tracing/Listener/EventHandleListener.php Updates listener to use global functions instead of trait methods
composer.json files Adds Function.php to autoload configuration

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread src/sentry/src/Function.php
Comment thread src/sentry/src/Function.php Outdated
Copy link
Copy Markdown
Contributor Author

@huangdijia huangdijia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

代码审查反馈

🎯 变更摘要

这个 PR 成功地将 SpanStarter trait 重构为全局函数方式,提供了更简洁的 API 接口。主要变更包括:

  • 新增全局函数 trace() 和 startTransaction()
  • 更新 15+ 个 Aspect 类移除 trait 依赖
  • 保持向后兼容性,trait 标记为弃用

⚠️ 潜在风险

性能考虑:

  • 每次调用全局函数都会触发容器解析 Tracer::class,在高并发场景下可能产生性能开销
  • 建议考虑缓存 Tracer 实例以优化性能

架构影响:

  • 全局函数绕过了依赖注入机制,可能影响单元测试的便利性
  • 对 ApplicationContext::getContainer() 的硬依赖可能降低代码可测试性

💡 优化建议

  1. 性能优化 - 在 Function.php 中添加实例缓存
  2. 错误处理 - 为全局函数添加容器不可用时的优雅降级机制
  3. 文档完善 - 建议添加从 trait 到全局函数的迁移指南

✅ 合规性检查

符合项:

  • ✅ 命名规范遵循项目约定
  • ✅ 正确的命名空间使用
  • ✅ 保持了向后兼容性
  • ✅ 文件组织结构合理

需要关注:

  • 确保新的全局函数有充分的单元测试覆盖
  • 考虑为 Tracer 定义接口以提高可测试性

🎉 总体评价

这是一个设计良好的重构,成功简化了 API 并为未来的清理工作做好了准备。代码质量整体良好,主要建议集中在性能优化和测试覆盖方面。

感谢你在保持向后兼容性的同时推进代码现代化!👍

@huangdijia huangdijia merged commit 67d1e17 into main Sep 25, 2025
16 checks passed
@huangdijia huangdijia deleted the refactor/sentry-replace-spanstarter-trait-with-global-functions branch September 25, 2025 13:47
huangdijia added a commit that referenced this pull request Sep 25, 2025
* refactor(sentry): replace SpanStarter trait with global functions

- Create new Function.php with global trace() and startTransaction() functions
- Replace SpanStarter trait usage with global function calls across all aspects
- Add Function.php to autoload configuration in composer.json files
- Mark SpanStarter trait as deprecated with removal notice
- Improve code consistency and prepare for trait removal in v3.2

This change provides a cleaner API and reduces trait dependencies while
maintaining backward compatibility through deprecation warnings.

* refactor(trace): simplify tracing extra tag check logic

* fix(Function.php): remove unnecessary initialization of isTracingExtraTagEnabled

* feat(tracing): implement TracerProvider for transaction and trace management

* refactor(tracing): replace TracerProvider with Tracer and update transaction methods

* refactor(span): replace SpanStarter methods with Tracer methods for transaction and trace handling

---------

Co-Authored-By: Deeka Wong <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants