Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
23f2a15
feat: add additional Sentry singleton classes to aspect configuration
huangdijia Nov 27, 2025
83dfd96
fix: reorder Sentry singleton classes in SingletonAspect
huangdijia Nov 27, 2025
f18ffc7
fix: update SingletonAspect to use TraceMetrics singleton instance
huangdijia Nov 28, 2025
14c9808
feat: add enable_metrics configuration option to Sentry settings
huangdijia Nov 28, 2025
6fd4f57
feat: add metrics tracking and related listeners for enhanced perform…
huangdijia Nov 28, 2025
255a74f
feat: add new metrics listeners for enhanced monitoring capabilities
huangdijia Nov 28, 2025
94cd380
fix: remove PoolWatcher listener from ConfigProvider
huangdijia Nov 28, 2025
52a049f
feat: update event parameter types in metrics listeners for improved …
huangdijia Nov 28, 2025
c263c76
fix: optimize queue retrieval in QueueWatcher listener
huangdijia Nov 28, 2025
7d273b6
feat: add metrics interval configuration and update timer intervals i…
huangdijia Nov 28, 2025
082920d
feat: add metrics interval configuration to Sentry settings
huangdijia Nov 28, 2025
65a56ef
feat: remove unnecessary comment and improve PoolWatcher with metric …
huangdijia Nov 28, 2025
a8cff6f
fix: add return type declaration to watch method in PoolWatcher class
huangdijia Nov 28, 2025
60f7e90
fix: add missing newline for better code readability in PoolWatcher c…
huangdijia Nov 28, 2025
e4e6d1e
feat: enforce minimum metrics interval of 5 in getMetricsInterval method
huangdijia Nov 28, 2025
cdf795b
refactor: simplify process method in RequestWatcher class by removing…
huangdijia Nov 28, 2025
bb3a2df
fix: add missing newline for improved readability in RedisPoolWatcher…
huangdijia Nov 28, 2025
87c9180
feat: add Counter and CounterAspect classes for metrics annotation an…
huangdijia Nov 28, 2025
95e01d8
feat: add CounterAspect to ConfigProvider for metrics tracking
huangdijia Nov 28, 2025
70ff61e
feat: add HistogramAspect and Histogram annotation for enhanced metri…
huangdijia Nov 28, 2025
0e3eeb4
feat: add Unit::second() to HistogramAspect for improved metrics trac…
huangdijia Nov 28, 2025
58d6468
feat: enhance RequestWatcher to track HTTP request metrics with Trace…
huangdijia Nov 28, 2025
9e62103
feat: add defer calls to flush TraceMetrics in various aspects and li…
huangdijia Nov 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/sentry/publish/sentry.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#enable_logs
'enable_logs' => env('SENTRY_ENABLE_LOGS', true),

// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#enable_metrics
'enable_metrics' => env('SENTRY_ENABLE_METRICS', true),
'metrics_interval' => (int) env('SENTRY_METRICS_INTERVAL', 10),

'logs_channel_level' => env('SENTRY_LOGS_CHANNEL_LEVEL', Sentry\Logs\LogLevel::debug()),

// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send_default_pii
Expand Down
3 changes: 3 additions & 0 deletions src/sentry/src/Aspect/SingletonAspect.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ class SingletonAspect extends AbstractAspect
\Sentry\EventType::class . '::getInstance',
\Sentry\MonitorScheduleUnit::class . '::getInstance',
\Sentry\Integration\IntegrationRegistry::class . '::getInstance',
\Sentry\Logs\LogLevel::class . '::getInstance',
\Sentry\Metrics\TraceMetrics::class . '::getInstance',
\Sentry\State\HubAdapter::class . '::getInstance',
\Sentry\Tracing\SpanStatus::class . '::getInstance',
\Sentry\Tracing\TransactionSource::class . '::getInstance',
\Sentry\Transport\ResultStatus::class . '::getInstance',
\Sentry\Unit::class . '::getInstance',
];

public function process(ProceedingJoinPoint $proceedingJoinPoint)
Expand Down
10 changes: 10 additions & 0 deletions src/sentry/src/ConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public function __invoke(): array
Aspect\LoggerAspect::class,
Aspect\RedisAspect::class,
Aspect\SingletonAspect::class,
Metrics\Aspect\CounterAspect::class,
Metrics\Aspect\HistogramAspect::class,
Tracing\Aspect\AmqpProducerAspect::class,
Tracing\Aspect\AsyncQueueJobMessageAspect::class,
Tracing\Aspect\CacheAspect::class,
Expand Down Expand Up @@ -60,6 +62,14 @@ public function __invoke(): array
Listener\SetupSentryListener::class,
Listener\EventHandleListener::class => PHP_INT_MAX - 1,
Crons\Listener\EventHandleListener::class => PHP_INT_MAX - 1,
Metrics\Listener\DBPoolWatcher::class,
Metrics\Listener\OnBeforeHandle::class,
Metrics\Listener\OnCoroutineServerStart::class,
Metrics\Listener\OnMetricFactoryReady::class,
Metrics\Listener\OnWorkerStart::class,
Metrics\Listener\QueueWatcher::class,
Metrics\Listener\RedisPoolWatcher::class,
Metrics\Listener\RequestWatcher::class,
Tracing\Listener\EventHandleListener::class => PHP_INT_MAX, // !! Make sure it is the first one to handle the event
],
'annotations' => [
Expand Down
2 changes: 2 additions & 0 deletions src/sentry/src/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@ class Constants
public const BAGGAGE = 'baggage';

public const TRACEPARENT = 'traceparent';

public const RUN_IN_COMMAND = 'sentry.run_in_command';
}
1 change: 1 addition & 0 deletions src/sentry/src/Factory/ClientBuilderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class ClientBuilderFactory
'http_chanel_size', // deprecated, will be removed in v3.2
'http_concurrent_limit', // deprecated, will be removed in v3.2
'logs_channel_level',
'metrics_interval',
'transport_channel_size',
'transport_concurrent_limit',
'tracing',
Expand Down
16 changes: 16 additions & 0 deletions src/sentry/src/Feature.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ public function isBreadcrumbEnabled(string $key, bool $default = true): bool
return (bool) $this->config->get('sentry.breadcrumbs.' . $key, $default);
}

public function isMetricsEnabled(bool $default = true): bool
{
return (bool) $this->config->get('sentry.enable_metrics', $default);
}

public function getMetricsInterval(int $default = 10): int
{
$interval = (int) $this->config->get('sentry.metrics_interval', $default);

if ($interval < 5) {
return 5;
}

return $interval;
}

public function isTracingEnabled(string $key, bool $default = true): bool
{
return (bool) $this->config->get('sentry.tracing.' . $key, $default);
Expand Down
2 changes: 2 additions & 0 deletions src/sentry/src/Integration.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Sentry\Event;
use Sentry\Integration\IntegrationInterface;
use Sentry\Logs\Logs;
use Sentry\Metrics\TraceMetrics;
use Sentry\SentrySdk;
use Sentry\State\Scope;
use Sentry\Tracing\Span;
Expand Down Expand Up @@ -111,6 +112,7 @@ public static function flushEvents(): void
$client->flush();

Logs::getInstance()->flush();
TraceMetrics::getInstance()->flush();
}
}

Expand Down
23 changes: 23 additions & 0 deletions src/sentry/src/Metrics/Annotation/Counter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

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

namespace FriendsOfHyperf\Sentry\Metrics\Annotation;

use Attribute;
use Hyperf\Di\Annotation\AbstractAnnotation;

#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Counter extends AbstractAnnotation
{
public function __construct(public string $name = '')
{
}
}
23 changes: 23 additions & 0 deletions src/sentry/src/Metrics/Annotation/Histogram.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

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

namespace FriendsOfHyperf\Sentry\Metrics\Annotation;

use Attribute;
use Hyperf\Di\Annotation\AbstractAnnotation;

#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Histogram extends AbstractAnnotation
{
public function __construct(public string $name = '')
{
}
}
70 changes: 70 additions & 0 deletions src/sentry/src/Metrics/Aspect/CounterAspect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

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

namespace FriendsOfHyperf\Sentry\Metrics\Aspect;

use FriendsOfHyperf\Sentry\Feature;
use FriendsOfHyperf\Sentry\Metrics\Annotation\Counter;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;
use Sentry\Metrics\TraceMetrics;

use function Hyperf\Coroutine\defer;

class CounterAspect extends AbstractAspect
{
public array $classes = [];

public array $annotations = [
Counter::class,
];

public function __construct(protected Feature $feature)
{
}

public function process(ProceedingJoinPoint $proceedingJoinPoint): mixed
{
if ($this->feature->isMetricsEnabled()) {
$metadata = $proceedingJoinPoint->getAnnotationMetadata();
$source = $this->fromCamelCase($proceedingJoinPoint->className . '::' . $proceedingJoinPoint->methodName);

/** @var null|Counter $annotation */
$annotation = $metadata->method[Counter::class] ?? null;

if ($annotation) {
$name = $annotation->name ?: $source;
} else {
$name = $source;
}

defer(fn () => TraceMetrics::getInstance()->flush());

TraceMetrics::getInstance()
->count($name, 1, [
'class' => $proceedingJoinPoint->className,
'method' => $proceedingJoinPoint->methodName,
]);
}

return $proceedingJoinPoint->process();
}

private function fromCamelCase(string $input): string
{
preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
$ret = $matches[0];
foreach ($ret as &$match) {
$match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
}
return implode('_', $ret);
}
}
78 changes: 78 additions & 0 deletions src/sentry/src/Metrics/Aspect/HistogramAspect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

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

namespace FriendsOfHyperf\Sentry\Metrics\Aspect;

use FriendsOfHyperf\Sentry\Feature;
use FriendsOfHyperf\Sentry\Metrics\Annotation\Histogram;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;
use Sentry\Metrics\TraceMetrics;
use Sentry\Unit;

use function Hyperf\Coroutine\defer;
use function Hyperf\Tappable\tap;

class HistogramAspect extends AbstractAspect
{
public array $classes = [];

public array $annotations = [
Histogram::class,
];

public function __construct(protected Feature $feature)
{
}

public function process(ProceedingJoinPoint $proceedingJoinPoint): mixed
{
if (! $this->feature->isMetricsEnabled()) {
return $proceedingJoinPoint->process();
}

$metadata = $proceedingJoinPoint->getAnnotationMetadata();
$source = $this->fromCamelCase($proceedingJoinPoint->className . '::' . $proceedingJoinPoint->methodName);
/** @var null|Histogram $annotation */
$annotation = $metadata->method[Histogram::class] ?? null;
if ($annotation) {
$name = $annotation->name ?: $source;
} else {
$name = $source;
}

$startAt = microtime(true);

return tap($proceedingJoinPoint->process(), function () use ($name, $proceedingJoinPoint, $startAt) {
defer(fn () => TraceMetrics::getInstance()->flush());

TraceMetrics::getInstance()->distribution(
$name,
(microtime(true) - $startAt) * 1000,
[
'class' => $proceedingJoinPoint->className,
'method' => $proceedingJoinPoint->methodName,
],
Unit::second()
);
});
}

private function fromCamelCase(string $input): string
{
preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
$ret = $matches[0];
foreach ($ret as &$match) {
$match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
}
return implode('_', $ret);
}
}
56 changes: 56 additions & 0 deletions src/sentry/src/Metrics/CoroutineServerStats.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

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

namespace FriendsOfHyperf\Sentry\Metrics;

use Hyperf\Contract\Arrayable;

/**
* @property int $start_time 服务器启动的时间
* @property int $connection_num 当前连接的数量
* @property int $accept_count 接受了多少个连接
* @property int $close_count 关闭的连接数量
* @property int $worker_num 开启了多少个 worker 进程
* @property int $idle_worker_num 空闲的 worker 进程数
* @property int $task_worker_num 开启了多少个 task_worker 进程【v4.5.7 可用】
* @property int $tasking_num 当前正在排队的任务数
* @property int $request_count Server 收到的请求次数【只有 onReceive、onMessage、onRequset、onPacket 四种数据请求计算 request_count】
* @property int $response_count Server 发送的响应次数【只有 onReceive、onMessage、onRequset、onPacket 四种数据请求计算 response_count】
* @property int $dispatch_count Server 发送到 Worker 的包数量【v4.5.7 可用,仅在 SWOOLE_PROCESS 模式下有效】
* @property int $worker_request_count 当前 Worker 进程收到的请求次数【worker_request_count 超过 max_request 时工作进程将退出】
* @property int $worker_dispatch_count master 进程向当前 Worker 进程投递任务的计数,在 master 进程进行 dispatch 时增加计数
* @property int $task_queue_num 消息队列中的 task 数量【用于 Task】
* @property int $task_queue_bytes 消息队列的内存占用字节数【用于 Task】
* @property int $task_idle_worker_num 空闲的 task 进程数量
* @property int $coroutine_num 当前协程数量【用于 Coroutine】,想获取更多信息参考此节
Comment on lines +19 to +33
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

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

The class docblock contains multiple spelling and grammar errors in the Chinese comments:

  • Line 19: "接受了" should be "已接受" (accepted)
  • Line 25: "request_count Server 收到的请求次数" - missing punctuation
  • Line 26: "response_count Server 发送的响应次数" - missing punctuation

These should be corrected for clarity and consistency with standard documentation practices.

Suggested change
* @property int $accept_count 接受了多少个连接
* @property int $close_count 关闭的连接数量
* @property int $worker_num 开启了多少个 worker 进程
* @property int $idle_worker_num 空闲的 worker 进程数
* @property int $task_worker_num 开启了多少个 task_worker 进程【v4.5.7 可用】
* @property int $tasking_num 当前正在排队的任务数
* @property int $request_count Server 收到的请求次数【只有 onReceive、onMessage、onRequset、onPacket 四种数据请求计算 request_count】
* @property int $response_count Server 发送的响应次数【只有 onReceive、onMessage、onRequset、onPacket 四种数据请求计算 response_count】
* @property int $dispatch_count Server 发送到 Worker 的包数量【v4.5.7 可用,仅在 SWOOLE_PROCESS 模式下有效】
* @property int $worker_request_count 当前 Worker 进程收到的请求次数【worker_request_count 超过 max_request 时工作进程将退出】
* @property int $worker_dispatch_count master 进程向当前 Worker 进程投递任务的计数,在 master 进程进行 dispatch 时增加计数
* @property int $task_queue_num 消息队列中的 task 数量【用于 Task】
* @property int $task_queue_bytes 消息队列的内存占用字节数【用于 Task】
* @property int $task_idle_worker_num 空闲的 task 进程数量
* @property int $coroutine_num 当前协程数量【用于 Coroutine】,想获取更多信息参考此节
* @property int $accept_count 已接受的连接数量
* @property int $close_count 关闭的连接数量
* @property int $worker_num 开启了多少个 worker 进程
* @property int $idle_worker_num 空闲的 worker 进程数
* @property int $task_worker_num 开启了多少个 task_worker 进程【v4.5.7 可用】
* @property int $tasking_num 当前正在排队的任务数
* @property int $request_count Server 收到的请求次数【只有 onReceive、onMessage、onRequset、onPacket 四种数据请求计算 request_count】
* @property int $response_count Server 发送的响应次数【只有 onReceive、onMessage、onRequset、onPacket 四种数据请求计算 response_count】
* @property int $dispatch_count Server 发送到 Worker 的包数量【v4.5.7 可用,仅在 SWOOLE_PROCESS 模式下有效】
* @property int $worker_request_count 当前 Worker 进程收到的请求次数【worker_request_count 超过 max_request 时工作进程将退出】
* @property int $worker_dispatch_count master 进程向当前 Worker 进程投递任务的计数,在 master 进程进行 dispatch 时增加计数
* @property int $task_queue_num 消息队列中的 task 数量【用于 Task】
* @property int $task_queue_bytes 消息队列的内存占用字节数【用于 Task】
* @property int $task_idle_worker_num 空闲的 task 进程数量
* @property int $coroutine_num 当前协程数量【用于 Coroutine】。如需获取更多信息,请参考相关章节。

Copilot uses AI. Check for mistakes.
*/
class CoroutineServerStats implements Arrayable
{
protected array $stats = [
'worker_num' => 1,
'idle_worker_num' => 0,
];

public function __get($name)
{
return $this->stats[$name] ?? 0;
}

public function __set($name, $value)
{
$this->stats[$name] = $value;
}

public function toArray(): array
{
return $this->stats;
}
}
19 changes: 19 additions & 0 deletions src/sentry/src/Metrics/Event/MetricFactoryReady.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

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

namespace FriendsOfHyperf\Sentry\Metrics\Event;

class MetricFactoryReady
{
public function __construct(public int $workerId = 0)
{
}
}
Loading