hyperf多库sql日志需独立channel分离、结构化输出并标识连接名。必须在logger.php定义专用channel(如'sql'),绑定rotatingfilehandler与line/jsonformatter,监听器调用$loggerfactory->get('sql','sql')确保键名一致,写入时传context含connection、sql、bindings,避免字符串拼接,并验证目录权限与配置匹配。

Hyperf 多数据库连接时,日志打印容易混乱或缺失——不是查不到 SQL,就是分不清哪个库执行了哪条语句。关键不在“能不能打”,而在“打到哪、怎么分、是否结构化”。配置对了,调试效率翻倍;配错一个键名或 channel 名,日志就静默跑进 default 里,排查时完全找不到线索。
确保 SQL 日志走独立通道,不混入主日志
默认情况下,DbQueryExecutedListener 会把所有 SQL 日志发往 default channel。多库场景下必须显式分离:
- 在 config/autoload/logger.php 中定义专用 channel,比如 'sql' 或 'db_log',不要复用 handlers 数组,每个 channel 只配一个 handler
- handler 推荐用 RotatingFileHandler,设
'filename' => BASE_PATH . '/runtime/logs/sql.log',并开启'maxFiles' => 30 - formatter 必须用 LineFormatter 或 JsonFormatter,且构造参数中启用
'allowInlineLineBreaks' => true(Line)或'batchMode' => JsonFormatter::BATCH_MODE_JSON(JSON) - 监听器需绑定到该 channel:在
dependencies.php或事件监听配置中,确认DbQueryExecutedListener的 logger 实例是$loggerFactory->get('sql', 'sql'),第二个参数必须和 logger.php 里的 channel 键名一致
给每条 SQL 日志打上连接标识
光分文件不够,得知道这条 SQL 来自 log_db 还是 report_db:
- 在自定义的 QueryListener 或中间件中,从当前查询上下文提取连接名:
$connectionName = $event->getConnection()->getName(); - 写日志时带上 context:
$logger->info('SQL executed', ['connection' => $connectionName, 'sql' => $event->getSql(), 'bindings' => $event->getBindings()]) - 避免拼接字符串,否则字段进不了结构化 JSON;也别漏掉 bindings,它能帮你快速还原真实参数值
验证多库日志是否真正生效
常见静默失败原因不是代码错,而是配置链断了一环:
- 检查 logger.php 是否存在对应 channel 键名(如
'sql'),且该键下有完整handler和formatter配置 - 确认
$loggerFactory->get('sql', 'sql')第二个参数和配置键名完全一致(大小写、空格、下划线都敏感) - 运行时临时加一行测试:
$loggerFactory->get('sql', 'sql')->info('test connection tag');,看 runtime/logs/sql.log 是否立刻出现 - 若没输出,检查
runtime/logs/目录权限是否可写,以及是否被 BufferHandler 缓存(可临时设'bufferSize' => 1强制即时刷盘)
生产环境建议异步 + 分级 + 脱敏
高并发下同步打 SQL 日志会拖慢请求,还可能泄露敏感字段:
- 替换
StreamHandler为BufferHandler包裹RotatingFileHandler,'bufferSize' => 50较平衡 - 为不同连接配置不同 channel:比如
'log_db_sql'和'report_db_sql',便于按业务隔离分析 - 加 Processor 剔除 password、token 等字段:
new \Hyperf\Logger\Processor\RemoveSensitiveDataProcessor(['password', 'token']) - SQL 日志级别建议设为
Monolog\Logger::DEBUG,但通过环境变量控制开关,上线后默认关闭,出问题再动态调高











