ThinkPHP 6+ 日志配置在 config/log.php,需确保 'default' => 'file'、'level' => 'error'、'ignore_404' => false、'close' => false,并在线上环境设 APP_DEBUG=false 且 runtime/log/ 目录可写。

日志配置文件在哪、改什么参数
ThinkPHP 6+ 的日志配置集中在 config/log.php,不是 app.php 或中间件里。关键不是“开启日志”,而是确保错误级别被真正捕获并写入——默认配置下,error 级别日志其实不会记录 PHP 致命错误(比如 Fatal error),因为那发生在框架启动前。
必须检查这几项:
-
'default' => 'file':确保默认驱动是file(非test或空) -
'channels' => ['file' => [...]]下的'level' => 'error':这里只控制日志门面(如Log::error())的最低输出级别,不等于能捕获所有报错 -
'ignore_404' => false:如果关了,404 不会进日志;但更关键的是'close' => false(别设成true,否则全关)
为什么 try-catch 捕不到的错误仍不写日志
PHP 的 Fatal error、Parse error、TypeError(未被 catch 的)不会走 ThinkPHP 的异常处理流程,它们触发的是 PHP 自身的 set_error_handler 和 register_shutdown_function。ThinkPHP 默认已注册 shutdown 函数,但前提是 APP_DEBUG 为 false ——开发时开 debug,错误直接抛到页面,根本不会落盘。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 线上环境务必设
APP_DEBUG = false(在.env中),否则error_log不生效 - 确认
config/exception.php中的'log' => true已开启(它控制未捕获异常是否写日志) - 不要依赖
Log::error()手动记录致命错误——它根本执行不到
日志路径权限和文件名动态问题
ThinkPHP 默认把日志写到 runtime/log/,但容易踩两个坑:一是目录不存在或无写权限,二是日期文件名(如 20240512.log)导致排查时找不到“最新”的那个文件。
常见现象:file_put_contents(runtime/log/20240512.log): failed to open stream: No such file or directory
解决方法:
- 部署时手动创建
runtime/log/并chmod -R 755 runtime/(Linux)或确保 IIS/Apache 用户有写权(Windows) - 如需固定文件名便于监控,改
config/log.php中'file' => 'log/error.log'(注意路径是相对于runtime/) - 别用
date('Ym')这类动态目录名——ThinkPHP 不自动创建多级目录,会静默失败
自定义错误处理器要不要加
除非你明确要捕获 E_DEPRECATED 或 E_USER_WARNING 并转成日志,否则不用自己写 set_error_handler。ThinkPHP 的 think\facade\Log 已通过 think\log\driver\File 统一接管了 trigger_error 和异常,额外注册反而可能冲突。
真要扩展,只建议做这一件事:
- 在
app/exception/Handler.php的report方法里,对特定异常类型(如数据库连接失败)追加Log::alert(),带上下文信息,比如['sql' => $e->getSql()] - 别在
render里写日志——那是响应阶段,出错时可能已无法写磁盘
最常被忽略的一点:日志内容是否包含 trace?默认 trace 是开启的,但如果在 config/log.php 里把 'format' 改成自定义字符串且漏了 {trace} 占位符,就看不到堆栈——查错基本靠猜。



















