可通过监听 dbqueryexecuted 事件获取 mysql 原始 sql,该事件在 sql 执行完成后触发,包含 $event->sql(带占位符的原始语句)、$event->bindings(参数数组)、$event->time(毫秒耗时)及连接配置等协程安全信息,无需修改底层驱动。

Hyperf 里怎么拿到 MySQL 执行的原始 SQL?
Hyperf 的 Database 组件默认不暴露原始 SQL,但可以通过监听 DbQueryExecuted 事件拿到——这是最轻量、最贴近业务逻辑的埋点入口,不需要改驱动或 Hook 底层 socket。
关键点:这个事件在 SQL 执行完成(无论成功失败)后触发,包含完整 SQL 字符串、绑定参数、执行耗时、连接信息,且天然协程安全。
- 必须在
config/autoload/events.php中注册监听器:Hyperf\Database\Event\DbQueryExecuted::class => [App\Listener\SqlLogListener::class] -
SqlLogListener中通过$event->sql获取原始语句,$event->bindings是参数数组,$event->time是毫秒级耗时 - 注意:如果用了 Query Builder,
$event->sql是已拼好的带问号占位符的 SQL;如果用了原生DB::select('SELECT ?'),则bindings为空,SQL 已含实际值
如何避免日志写入拖慢数据库请求?
直接在监听器里调用 $logger->info() 同步写文件,会把协程卡在 IO 上,尤其高并发时明显拉长 P95 延迟。必须异步化,但不能简单丢进协程里不管。
- 推荐用
BufferHandler+RotatingFileHandler组合,配置bufferSize为 50~100,避免小日志频繁刷盘 - 不要用
AsyncHandler—— Hyperf 的AsyncHandler本质是投递到独立 Worker 进程,反而增加 IPC 开销和上下文切换 - 若需上报到远端(如 ES 或 Loki),务必启用压缩(
compress => true)并限制单条日志大小,否则网络缓冲区易满导致协程阻塞 - 生产环境建议只对
time > 100(毫秒)的慢查询打标记录,或按接口名白名单过滤,比如只埋点order_*相关 SQL
携程式埋点需要哪些字段才真正有用?
单纯记下 SELECT * FROM user WHERE id = ? 没意义。携程系监控体系依赖结构化上下文,至少要补全 4 类字段:
-
来源标识:从
$event->connection->getConfig('name')取连接池名(如mysql-primary),区分读写分离链路 -
调用栈快照:用
debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)截取最上层业务方法(如OrderService::create()),不打全栈避免性能损耗 -
租户/业务线标记:从当前协程上下文取,例如
ApplicationContext::getContainer()->get(CoroutineContext::class)->get('tenant_id') -
错误标记:检查
$event->exception是否非 null;若为 null 但$event->sql包含INSERT且$event->result->rowCount() === 0,也应标记为“影响行数为 0”类弱异常
为什么不能依赖 MySQL 通用日志(general_log)?
因为 general_log 是服务端全局开关,与应用层完全解耦——你无法关联到具体请求 ID、用户 ID、TraceID,也无法过滤出某次下单流程涉及的所有 SQL,更没法区分是哪个 Hyperf Worker 进程发的请求。
- 开启后所有连接都记,包括健康检查、定时任务、后台脚本,日志噪音极大
- 输出到表(
mysql.general_log)时,event_time精度只到秒,协程场景下多个请求可能时间戳相同,无法排序还原执行顺序 - 路径权限问题频发:MySQL 进程往往没权限往
/data/logs/写,而改路径又需 DBA 配合,上线卡点 - 最致命的是:它记录的是“收到的 SQL”,不是“执行后的结果”。比如
INSERT ... ON DUPLICATE KEY UPDATE成功但未更新任何行,general_log 里看不出,而应用层监听能拿到rowCount()
真正可靠的 SQL 日志,必须扎根在应用框架内,由业务代码可控地生成、标注、分级落库——这正是 Hyperf 事件监听方案不可替代的地方。











