ci4日志服务由config\logger.php静态配置驱动,非容器注册,service('logger')总返回默认实例;自定义必须修改该文件的$threshold、$path等属性,分文件需自行封装channellogger。

CI4 的日志服务不是通过服务容器(Service Container)直接“注册日志实例”来配置的,而是由 Logger 类在启动时读取 app/Config/Logger.php 静态配置初始化的。你不能像绑定 MyService 那样用 $container->set('logger', new MyLogger()) 替换它——框架底层硬编码依赖 Config\Logger 实例,且只在首次调用 log_message() 或 service('logger') 时懒加载一次。
为什么 service('logger') 总是返回默认实例?
因为 CodeIgniter 4 的 Logger 服务是“单例 + 配置驱动”,不是容器可替换的服务。即使你在 app/Config/Services.php 里重写 logger() 方法,只要没动 Config\Logger,实际行为仍由该类的 $threshold、$path、$filePermissions 等属性决定。
真正生效的自定义入口只有 app/Config/Logger.php
所有关键控制项都集中在这里:
-
$threshold:整数,对应日志级别阈值(0= 全开,1= error,2= critical,3= alert,4= emergency;注意它不是字符串数组,和 ThinkPHP 的level数组完全不同) -
$path:必须是绝对路径,且末尾带/,例如WRITEPATH . 'logs/';若路径不存在或无写权限,日志静默失败(不报错) -
$fileExt:默认php,但建议设为log,避免被 Web 服务器直接解析执行 -
$dateFormat:影响每行日志开头的时间格式,如'Y-m-d H:i:s',不支持 ISO8601 中的T和O -
$filePermissions:八进制整数,如0644,别写成字符串'0644',否则 chmod 失效
想按模块/业务分文件?得自己封装一层
CI4 原生不支持多通道(如 pay、api 独立日志),Logger 只有一个实例、一个目录、一个阈值。要实现分文件,必须绕过原生 log_message():
- 新建
app/Logging/ChannelLogger.php,构造时接收$channelName和独立路径(如WRITEPATH . 'logs/pay/') - 复用
CodeIgniter\Log\Handlers\FileHandler的写入逻辑,但把$this->path指向子目录 - 确保子目录存在并有权限:
if (! is_dir($path)) { mkdir($path, 0755, true); } - 调用时用
(new ChannelLogger('pay'))->error('xxx'),而不是log_message('error', 'xxx')
注意:这种封装无法享受框架自动轮转(daily 或 size 切割)功能,需自行实现文件大小检查与归档。
生产环境禁用 debug 日志的唯一可靠方式
不要试图在控制器里用 if (ENVIRONMENT === 'production') { log_message('debug', ...); } —— 这增加运行时判断,且容易漏掉。正确做法是在 app/Config/Logger.php 中动态设 $threshold:
public $threshold = (ENVIRONMENT === 'production') ? 1 : 0;
这样从源头掐断:开发环境 log_message('debug', ...) 能写,生产环境连格式化都跳过,性能无损耗。
最易被忽略的是 $path 权限和 $filePermissions 的类型——写错一个斜杠或少一个 0,日志就彻底消失,还查不出原因。











