CodeIgniter 原生不支持 Monolog,log_message() 硬编码调用框架内置 Logger,需手动替换:CI4 推荐在 Services.php 中重写 logger() 方法注入 Monolog 实例;CI3 则应绕过 log_message() 直接使用 Monolog。

CodeIgniter 原生不支持 Monolog,必须手动替换日志管道;直接 require 或 composer install 后调用,log_message() 会失效——它只认 CI 自己的 Log 类。
为什么 log_message() 不会自动走 Monolog
CI 的 log_message() 是硬编码调用 $this->logger->write_log()(CI3)或 Services::logger()(CI4),底层绑定的是框架内置 Log 类。Monolog 是完全独立的 PSR-3 实现,两者无自动桥接。你 composer require monolog/monolog 后,log_message('error', 'xxx') 依然写进 application/logs/,和 Monolog 毫无关系。
CI4 中替换默认 logger 服务(推荐)
CI4 允许通过依赖注入容器覆盖 LoggerInterface,这是最干净的接入方式:
- 在
app/Config/Services.php的logger()方法中,注释掉原有return new Logger(...),改用 Monolog 实例 - 确保已安装:
composer require monolog/monolog - 示例代码(使用 StreamHandler 写入自定义路径):
use Monolog\Logger; use Monolog\Handler\StreamHandler; use Monolog\Processor\UidProcessor; public static function logger($getShared = true) { if ($getShared) { return static::getSharedInstance('logger'); } $logger = new Logger('ci4'); $logger->pushHandler(new StreamHandler(WRITEPATH . 'logs/monolog-' . date('Y-m-d') . '.log', Logger::INFO)); $logger->pushProcessor(new UidProcessor()); return $logger; } - 之后所有
log_message()调用都会经由这个 Monolog 实例——但注意:CI4 的log_message()仍要求第一个参数是小写字符串('error'、'info'等),它会映射为 Monolog 对应级别
CI3 中无法安全替换,只能绕过 log_message()
CI3 的日志系统是单例且硬耦合,强行替换 $this->logger 容易引发不可预知错误。更可行的做法是:
- 在需要的地方直接 new Monolog 实例,不碰
log_message() - 例如在控制器中:
use Monolog\Logger; use Monolog\Handler\StreamHandler; $log = new Logger('myapp'); $log->pushHandler(new StreamHandler(APPPATH . 'logs/custom.log', Logger::INFO)); $log->info('user_login', ['user_id' => $id, 'ip' => $this->input->ip_address()]); - 避免在模型或库中重复 new,可封装为一个 MY_Log 类,放在
application/core/下,通过$this->load->library('my_log')使用 - 切记:此时
log_message()和你的 Monolog 完全无关,不要混用;否则日志分散、格式不一、排查困难
容易被忽略的关键点
Monolog 的处理器(Handler)默认不自动创建目录,WRITEPATH . 'logs/' 必须存在且 Web 用户有写权限;log_date_format 配置对 Monolog 无效,时间格式由 Handler 或 Formatter 控制;如果你用了 RotatingFileHandler,注意它依赖 date() 和时区设置,而 CI 默认时区可能不是 UTC——这会导致轮转文件名错乱或漏写。


















