Hyperf 3.0 日志组件不原生支持按级别自动拆分通道,但可通过配置多个独立 channel 并为每个 handler 设置 level 和 bubble=false 实现等效分级存储,配合 ContextLevelProcessor 可进一步实现上下文级精准分流。

Hyperf 3.0 的日志组件本身不支持“按级别自动拆分通道”,比如把 ERROR 全部写进 error.log、INFO 全部写进 info.log——Monolog 默认不提供基于 level 的路由转发能力。但你可以通过配置多个独立 channel + 自定义 handler 过滤逻辑,实现效果等价的分级存储。
用多通道 + 级别过滤器模拟“按级别拆分”
核心思路:为每个目标级别(如 error、warning、info)单独定义一个 channel,并在对应 handler 中设置 level 和启用 Bubble = false,确保该 handler 只处理指定级别及更高级别的日志,且不向下游传递。
- 在
config/autoload/logger.php的channels中新增多个通道,例如:'error'、'warning'、'info' - 每个通道的 handler 使用
StreamHandler或RotatingFileHandler,并显式指定level(如Logger::ERROR) - 关键:设置
'bubble' => false,避免日志被重复写入其他通道或默认通道 - 示例片段:
搭配 Processor 实现上下文级精准分流
纯靠 level 拆分有时不够精细(比如想把 DB 异常单独归到 error-sql.log)。这时可在 channel 配置中加入 processors,或在代码中用 context 标记类型,再配合自定义 handler 判断是否写入。
- 注册一个
ContextLevelProcessor,检查$record['context']['category'] === 'sql'且$record['level'] >= Logger::ERROR - 让 error channel 的 handler 调用该 processor,满足条件才真正写入
- 这样 error-sql.log 和 error-api.log 就能共存,互不干扰
注意协程安全与性能陷阱
生产环境务必避开同步写入阻塞协程:
- 禁用裸
StreamHandler;改用BufferHandler包裹RotatingFileHandler实现异步批量刷盘 - 确保所有 handler 的
useLocking设为false(Swoole 已协程化文件 I/O,加锁反而降低性能) - 多个通道共享 formatter 时,确认时区统一(如
DateTimeZone::setTimezone(new DateTimeZone('Asia/Shanghai')))
调用时按需获取对应 channel 的 logger
不要只依赖 $loggerFactory->get() 返回默认实例。要明确指定 channel 名:
-
$loggerFactory->get('error')→ 写入 error.log -
$loggerFactory->get('warning')→ 写入 warning.log - 若某业务方法同时需记录 info 和 error,分别获取两个 logger 实例,各自调用


















