log::channel()拼错channel名会导致日志静默丢失,因monolog默认fallback至nullhandler且webman未启用存在性校验;需重写logger::channel方法加入配置键名校验并抛异常。

Log::channel() 调用日志 channel 时拼错名字,日志就静默丢失——没有报错、没有警告、连 warning 都不触发,这是 Webman 多 channel 日志最隐蔽的坑。
为什么 Log::channel('xxx') 拼错名不会报错
Monolog 的 Logger::channel() 在找不到对应 channel 时,会 fallback 到一个空的 NullHandler,而不是抛异常或触发 warning。这意味着你写了 Log::channel('purhcaseOrder')->info('test')(少了个 c),代码完全合法、运行无报错,但日志永远不会落地。
根本原因在于 Webman 默认未启用 channel 存在性校验,且插件 webman-tech/logger 的 getLogChannelConfigs() 只负责合并配置,不拦截非法 channel 名。
- 必须靠人工核对
config/plugin/webman-tech/logger/log-channel.php中的channels数组是否包含该 key - IDE 无法自动提示 channel 名,除非你手动在自定义
Logger类上加@method注释 - 线上环境更难发现:日志文件里查不到记录,又没错误反馈,容易误判为业务没走到那条路径
如何让非法 channel 名立刻暴露
在自定义的 support\facade\Logger 类中,重写 channel() 方法,加入存在性断言:
public static function channel(string $name)
{
$validChannels = array_keys(config('plugin.webman-tech.logger.log-channel.channels', []));
if (!in_array($name, $validChannels)) {
throw new \InvalidArgumentException("Invalid log channel: '$name'. Valid channels: " . implode(', ', $validChannels));
}
return parent::channel($name);
}
这样只要 channel 名拼错,立刻抛出明确异常,开发期就能拦截。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 不要依赖 IDE 提示——它只认
@method注释,不校验真实配置 - 测试阶段建议跑一遍所有 channel 调用,比如在单元测试里循环调用
Logger::channel($c)->info('ping') - 上线前可临时加个 health check 接口,遍历
config('plugin.webman-tech.logger.log-channel.channels')并尝试写入一行 debug 日志
RotatingFileHandler 的 $maxFiles 参数实际含义
很多人以为 RotatingFileHandler 的第三个构造参数(如 [runtime_path().'/logs/app.log', 7, Logger::INFO] 中的 7)是“最多保留 7 个文件”,其实它是“最多保留 7 天的日志文件”——前提是启用了日期滚动(useDayRotation 为 true);否则它就是“最多轮转 7 次”,和天数无关。
Webman 默认配置中 RotatingFileHandler 不启用日期滚动,所以这个 7 是指:当当前日志文件达到大小上限(默认无限制)或主动 close 时,旧文件依次重命名为 app.log.1, app.log.2, ..., 最多到 app.log.7,再老的会被删掉。
- 若想按天切割,需显式传入
'useDayRotation' => true,此时$maxFiles才表示保留天数 - 不设
useDayRotation时,单个日志文件可能无限增长,务必配合logrotate或监控磁盘使用 - 多个进程同时写同一
RotatingFileHandler文件会导致轮转混乱,生产环境应确保每个 worker 写独立文件(如用%process_id%插入文件名)
异步日志写入真的安全吗
Webman 本身不提供原生异步日志能力。所谓“异步”,本质是把日志写入操作扔进另一个协程或进程——但这不等于零风险。
常见做法是用 Swoole\Coroutine::create() 包裹 Log::info(),但问题在于:如果协程被强制 kill(如超时、worker 重启)、或日志 handler 是同步阻塞型(如 StreamHandler 写 stdout),协程仍会卡住主逻辑。
- 真正安全的异步日志,应使用消息队列(如 Redis list + 独立 consumer worker)或系统级管道(
syslog) - Monolog 自带
Handler\WhatFailureGroupHandler可兜底失败 handler,但无法解决写入延迟问题 - 高频日志场景下,优先考虑降低日志密度(如抽样、聚合),而非强行异步——协程调度开销可能比写文件还高










