Hyperf 多库慢查询监控需为每个连接单独配置 PDO 慢日志与 DbLogger 实例,并通过自定义监听器按连接名统一捕获上报;默认 DbLogger 仅作用于主库,多库须显式绑定并启用调试模式。

Hyperf 多库连接下慢查询监控,核心在于为每个数据库连接单独配置 PDO 日志与慢 SQL 捕获逻辑,并通过 DbLogger 或自定义监听器统一收集上报。默认的 DbLogger 只作用于主库,多库需显式绑定日志器并启用调试模式。
1. 为每个数据库连接启用慢查询日志
在 config/autoload/databases.php 中,对每个数据库配置开启 options 中的 PDO::ATTR_STATEMENT_CLASS 和日志开关:
'default' => [
'driver' => env('DB_DRIVER', 'mysql'),
'host' => env('DB_HOST', 'localhost'),
'port' => (int) env('DB_PORT', 3306),
'database' => env('DB_DATABASE', 'hyperf'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => env('DB_PREFIX', ''),
'strict' => true,
'options' => [
PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
// 关键:启用慢查询记录(需配合 DbLogger)
PDO::ATTR_STATEMENT_CLASS => ['Hyperf\Database\Statement', ['slowlog' => true, 'slowlog_threshold' => 100]], // 单位毫秒
],
],
'slave' => [
'driver' => env('DB_SLAVE_DRIVER', 'mysql'),
'host' => env('DB_SLAVE_HOST', 'localhost'),
'port' => (int) env('DB_SLAVE_PORT', 3306),
'database' => env('DB_SLAVE_DATABASE', 'hyperf_slave'),
'username' => env('DB_SLAVE_USERNAME', 'root'),
'password' => env('DB_SLAVE_PASSWORD', ''),
'charset' => env('DB_SLAVE_CHARSET', 'utf8mb4'),
'collation' => env('DB_SLAVE_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => env('DB_SLAVE_PREFIX', ''),
'strict' => true,
'options' => [
PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_STATEMENT_CLASS => ['Hyperf\Database\Statement', ['slowlog' => true, 'slowlog_threshold' => 200]],
],
],2. 注册多库专用 DbLogger 实例
Hyperf 的 DbLogger 默认只监听 default 连接。要支持多库,需为每个连接名注册独立 logger:
- 在
config/autoload/logger.php中新增对应通道(可选,用于隔离日志输出) - 在
app/Listener/DbSlowQueryListener.php中监听Hyperf\Database\Event\SlowQuery事件,按连接名区分处理 - 或更推荐:在
dependencies.php中为每个连接绑定专属DbLogger
// config/autoload/dependencies.php
use Hyperf\Database\Logger\DbLogger;
use Hyperf\Di\Container;
use Psr\Log\LoggerInterface;
<p>return [
// 主库 logger
DbLogger::class . '.default' => function (Container $container) {
return make(DbLogger::class, ['channel' => 'sql.default']);
},
// 从库 logger
DbLogger::class . '.slave' => function (Container $container) {
return make(DbLogger::class, ['channel' => 'sql.slave']);
},
];3. 自定义 SlowQuery 监听器统一捕获
创建监听器接收所有慢查询事件,并根据 $event->connectionName 分发日志或告警:
// app/Listener/DbSlowQueryListener.php
<?php
<p>declare(strict_types=1);</p><p>namespace App\Listener;</p><p>use Hyperf\Database\Event\SlowQuery;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Psr\Log\LoggerInterface;
use Hyperf\Utils\Str;</p><h1>[Listener]</h1><p>class DbSlowQueryListener implements ListenerInterface
{
public function __construct(protected LoggerInterface $logger)
{
}</p><pre class="brush:php;toolbar:false;">public function listen(): array
{
return [
SlowQuery::class,
];
}
public function process(object $event): void
{
if (! $event instanceof SlowQuery) {
return;
}
$conn = $event->connectionName;
$sql = $event->sql;
$time = round($event->time * 1000, 2); // ms
$params = $event->bindings ?? [];
$this->logger->warning(sprintf('[%s] Slow SQL detected: %s | Time: %sms | Params: %s', $conn, Str::limit($sql, 120), $time, json_encode($params, JSON_UNESCAPED_UNICODE)));
// 可扩展:上报 Prometheus、写入 Elasticsearch、触发告警等
// if ($conn === 'slave' && $time > 500) { $this->alert($event); }
}}
4. 启用调试模式并验证效果
确保 APP_ENV=dev 或手动开启调试开关,否则 SlowQuery 事件不会触发:
- 在
config/autoload/db.php确保'debug' => true已开启(全局开关) - 运行一条人为构造的慢查询测试:
sleep(1); SELECT SLEEP(1);(MySQL)或使用usleep(150000)模拟 150ms 延迟 - 查看日志输出是否包含
[default]或[slave]标识及对应 SQL - 检查
var/log/hyperf.log或你指定的 channel 日志文件


















