log_message() 必须传 'error'、'debug' 或 'info' 小写字符串,ci3/ci4 均仅匹配这三值;log_threshold 是日志开关门槛而非过滤器,设为 1 仅记录 error;log_path 需绝对可写路径且结尾带斜杠;业务日志需手动调用,不可依赖自动记录。

log_message() 必须传小写级别字符串
调用 log_message() 时,第一个参数不是随便写个单词就行的——必须是 'error'、'debug' 或 'info' 这三个小写字符串之一。写成 'Error'、'ERROR'、'warning' 都会被静默丢弃,不报错也不写日志。
这个限制在 CI3 和 CI4 中都存在,且不校验参数合法性,只做字符串匹配。常见踩坑点:
- 复制粘贴时带了全角空格或不可见字符,导致匹配失败
- 误以为支持 RFC 5424 全部八级(如
'notice'),实际框架只识别这三个 - CI3 项目迁移 CI4 后仍沿用旧习惯,在模型里漏掉
$this->load->library('log'),直接报Fatal error: Call to a member function write_log()
log_threshold 是日志开关总闸,不是过滤器
$config['log_threshold'] 不是“选哪些级别记录”,而是“低于该值的级别一律不写”。它像一个门槛:设为 1,只有 log_message('error', ...) 能落地;设为 0,连 404 错误、控制器缺失都不会进日志文件。
生产环境别贪图“多记点”,长期开 4(含 SQL 查询)会导致磁盘 IO 暴涨,尤其高频接口下日志文件每小时增长百 MB 很常见。推荐策略:
- 开发环境:设为
3(记录error/debug/info),SQL 单独用 Profiler 查 - 预发/灰度:设为
1,加钩子捕获关键业务 SQL(如支付、下单) - 线上:保持
1,错误发生后临时提至2或3抓上下文,完事立刻降回
日志路径必须是可写绝对路径,结尾带斜杠
$config['log_path'] 不接受相对路径,也不能是空字符串。写成 'logs/' 看似省事,但实际会拼到 Web 根目录下(比如 /var/www/html/logs/),极不安全——日志文件后缀仍是 .php,若被直接访问可能泄露敏感信息。
正确做法是用绝对路径并确认权限:
- 设为
"/var/www/myapp/logs/"(注意结尾斜杠) - 执行
ls -ld /var/www/myapp/logs/,确保 Web 用户(如www-data)有写权限 - SELinux 启用时,还需检查是否拦截:
ausearch -m avc -ts recent | grep httpd - 别把日志目录留在
application/logs/—— 它默认就在 Web 可达路径内
用户行为日志不能靠 $config['log_threshold'] 自动产生
框架默认日志只记录系统事件(类加载、SQL 执行、404),不会自动打点“张三登录”“李四删除订单”。要记录业务动作,必须手动介入:
- 在控制器关键方法里调用
log_message('info', 'user_login|id:' . $user_id . '|ip:' . $this->input->ip_address()) - 用钩子在
post_controller点统一捕获 DB 操作,但需过滤INSERT|UPDATE|DELETE,避免记录SELECT导致日志爆炸 - 永远先处理用户输入:
html_escape($this->input->get('search'))再拼进日志,否则可能引入日志注入 - 别把行为日志写数据库——高频小写入在真实压测中超过 50 QPS 就会拖慢 API 响应
log_threshold 的联动关系——哪怕代码里写了十次 log_message('error', ...),只要配置值是 0 或目录不可写,就等于没写。











