hyperf日志配置文件必须位于config/autoload/logger.php,返回数组结构,顶层键为channel名(如'default'、'sql'),每个channel独立配置handler、formatter和processors;需确保runtime/logs目录可写,多目标输出应定义多个channel而非复用handlers。

日志配置文件位置和基础结构
Hyperf 日志配置必须放在 config/autoload/logger.php,不是 logging.php 或其他路径。这个文件返回一个数组,顶层键是 channel 名(如 'default'、'sql'),每个 channel 对应一套 handler + formatter + processors。
常见错误是把多个 handler 写进同一个 channel 的 handlers 数组里,结果只生效第一个;正确做法是:每个 channel 只配一个 handler,需要多输出目标就定义多个 channel(比如 'access' 和 'error')。
-
BASE_PATH . '/runtime/logs/hyperf.log'必须确保目录可写,否则日志静默失败(无报错,但文件为空) - 若用
RotatingFileHandler,maxFiles参数必须显式传入 constructor,否则默认只保留 0 个旧文件(即不轮转) - 不要在
constructor中直接写__DIR__,它指向当前配置文件路径,不是项目根目录;一律用BASE_PATH
JSON 格式日志怎么配才真正结构化
光用 JsonFormatter 不等于结构化——如果没控制上下文字段,最终 JSON 里只有 message 和 level,其余全塞进空的 context 对象里,查起来还是得正则提取。
关键在两处:一是调用时传 context 数组,二是 formatter 要支持扁平字段。推荐配置:
- formatter class 设为
\Monolog\Formatter\JsonFormatter::class - constructor 中设
'batchMode' => \Monolog\Formatter\JsonFormatter::BATCH_MODE_JSON和'appendNewline' => true - 业务代码中写日志时,必须显式传 context:
$logger->info('order created', ['order_id' => $id, 'user_id' => $uid]) - 避免用
$logger->info("order created order_id:{$id}")这种拼字符串方式,字段就进不了 JSON key
多 channel 日志分流怎么匹配配置键
调用 $loggerFactory->get('sql', 'sql') 时,第一个参数 'sql' 是 logger 实例的 name(可用于 PSR-3 上下文识别),第二个参数 'sql' 才是去 logger.php 里找的 channel 键名。两者可以不同,但初学者常混淆。
典型错误:配置里写了 'sql_log' => [ ... ],代码却写 $loggerFactory->get('sql', 'sql'),结果 fallback 到 default channel,SQL 日志混进主日志文件。
- 检查
logger.php中是否存在对应键名的 channel 定义 - 确认该 channel 的
handlerclass 是否存在且已 autoload(比如用了自定义 handler 却没跑composer dump-autoload) - 协程安全要求:若 handler 写文件,禁用
useLocking(Monolog 默认关着,但自定义 handler 可能开)
对接阿里云 SLS 或 ELK 时容易漏的点
日志能写到文件 ≠ 能被采集服务解析。SLS 和 Filebeat 都依赖行边界和字段结构,而 Hyperf 默认 LineFormatter 输出带方括号和空格的非标准格式,正则极易写崩。
必须统一走 JSON 输出,并关闭 formatter 的换行干扰:
- 禁用
LineFormatter的includeStacktraces(第三参数),否则堆栈会破坏单行 JSON 结构 - 用
JsonFormatter时,appendNewline必须为true,否则 SLS 的“按行解析”模式会卡住 - Logtail 或 Filebeat 的采集路径要精确匹配日志文件名,比如配置了
'filename' => BASE_PATH . '/runtime/logs/access.log',采集规则就必须写/path/to/runtime/logs/access.log,不能漏掉runtime
channel 名和 formatter 类型一旦配错,日志就变成半结构化文本,后续所有分析链路都会失效——这不是性能问题,是数据契约断裂。











