ThinkPHP6.1日志静默丢弃的根本原因是权限、驱动、级别、环境四者中任一环节失效;runtime/log目录及父级需可写可执行,level需匹配日志等级,driver不得被运行时覆盖,APP_DEBUG=false才捕获致命错误。

ThinkPHP6.1 日志写入失败,**根本原因不是“配置没填全”,而是权限、驱动、级别、环境四者中任一环节卡死导致日志静默丢弃**。它不报错、不提示、不抛异常,只让日志“凭空消失”——这是最让人困惑的地方。
runtime/log 目录及其父级不可写
90% 的写入失败卡在这一步。TP6.1 默认将日志写入 runtime/log/(注意不是 storage/logs),该路径必须满足:
- runtime/ 和 log/ 两级目录都存在,且对 PHP 进程用户(如 www-data、nginx)有 w 权限
- 每一级父目录(包括项目根目录)都需具备 x(执行)权限,否则无法进入路径
- Linux 下用 ls -ld runtime log 检查属主和权限;临时验证可执行:
sudo chown -R www-data:www-data runtime && sudo chmod -R 755 runtime - Docker 环境必须确保挂载卷的 UID/GID 与容器内 Web 用户完全一致,否则 chown 无效
log.level 设置过严或未生效
日志写入是“门禁式”的:低于 level 阈值的日志连磁盘 I/O 都不会触发。
- 默认配置下,level => ['error'],意味着 Log::info()、Log::debug() 全部被过滤
- 开发期建议设为 'level' => ['debug'];生产环境至少设为 ['warning']
- 注意:APP_DEBUG=true 仅影响错误页面展示,和日志写入完全无关
- 若使用多通道(如 file + socket),需检查每个通道是否单独配置了 level,避免全局改了但通道级被覆盖
日志驱动被运行时代码覆盖或误配
哪怕 config/log.php 配置正确,一行 Log::driver('socket') 就能让所有后续日志走错路。
立即学习“PHP免费学习笔记(深入)”;
- 全局搜索项目中是否在中间件、app/common.php、命令行入口或单元测试里调用了 Log::driver()
- 确认 config/log.php 中 'default' => 'file',且 'type' => 'file'(不是 'trace' 或 'test' —— 这两个是内存驱动,不落盘)
- Socket 驱动依赖外部 log-server 进程,服务未启动则日志直接丢弃,且无 fallback
- CLI 模式下若 storage/logs 或 runtime/log 对 root 用户不可写,Log::info() 也会静默失败
APP_DEBUG=true 导致致命错误不进日志
这是很多人忽略的关键逻辑:TP6.1 对 Fatal Error、Parse Error 等致命错误的捕获,只在 APP_DEBUG === false 时才注册 shutdown handler。
- APP_DEBUG=true(开发模式):错误直接渲染到页面,runtime/log/ 几乎为空
- APP_DEBUG=false(生产模式):错误交由异常处理器处理,再由 config/exception.php 中的 'log' => true 控制是否写入
- .env 文件中必须写成 APP_DEBUG=false(无空格、无引号),Nginx/Apache 要显式透传该变量
- 404 错误是否记录,还取决于 config/log.php 的 'ignore_404' => false 和 exception.php 的 'log' => true



















