thinkphp日志静默丢失主因是storage/logs目录权限不足、log.level设置过严及log::driver()被运行时覆盖;需确认web进程用户可写、级别匹配调用、驱动未切换。

storage/logs 目录不可写,日志直接静默丢弃
ThinkPHP 6.0 默认把日志写进 storage/logs,但这个目录常被忽略权限问题。Linux 下如果 Web 进程用户(如 www-data 或 nginx)没有写权限,Log::info() 会执行成功、无报错、也不落盘——日志就“消失”了。
- 用
ls -ld storage/logs看属主和权限,确认运行 PHP 的用户(不是你当前登录用户)有w权限 -
runtime目录本身也必须可写,否则连日志文件都创建不了——别只改logs子目录 - 临时验证:执行
sudo chown -R www-data:www-data storage(Debian/Ubuntu)或sudo chown -R nginx:nginx storage(CentOS) - Docker 环境要检查挂载卷的 UID/GID 是否匹配容器内 Web 用户,否则
chown无效
log.level 设置高于实际调用级别,日志根本没触发写入
ThinkPHP 日志写入是“门禁式”的:Log::record() 在底层受 level 控制,低于阈值的日志连磁盘 I/O 都不会发起。你写了 Log::info('test') 却没日志,大概率是配置里设了 'level' => 'error'。
- 检查
config/log.php中的level值,开发期建议设为'debug',生产环境至少'warning' - 注意:级别是“最低记录门槛”,
level => 'warning'表示只记warning、error、critical,不记info或debug -
APP_DEBUG只控制错误页面展示,和日志写入无关;别指望开调试模式就能看到info日志
Log::driver() 被中间件或命令行手动覆盖,后续日志走错通道
很多人只改了 config/log.php,却在中间件、app/common.php 或 Console 命令里显式调用了 Log::driver('socket'),导致后续所有日志都尝试走 socket,而 socket 驱动依赖外部 log-server 进程——服务没起,日志就彻底丢弃。
- 全局搜索项目中是否出现
Log::driver(,尤其检查中间件、命令类、单元测试入口 - 确认
config/log.php中'default' => 'file',且没被运行时代码覆盖 -
'type' => 'trace'或'type' => 'test'是内存驱动,不落盘;线上误配等于关掉日志
CLI 模式下路径不可写,又没 fallback,日志无声失败
TP6 在 CLI 和 Web 下共用同一套日志配置,但 CLI 进程用户(如 root)和 Web 用户(如 www-data)往往不同。如果 storage/logs 对 CLI 用户不可写,php think hello 里的 Log::info() 就会静默失败。
- 不要依赖 Web 环境下的权限设置来保 CLI 日志;要么统一属主(如都设为
www-data),要么给 CLI 单独配路径 - 可在
config/log.php中按环境区分路径:'path' => env('APP_ENV') === 'cli' ? '/tmp/tp6-cli-log/' : 'storage/logs/' - 记得确保 CLI 路径父目录存在且可写,否则
mkdir都失败,更别说写日志
真正卡住排查的,往往是权限叠加 + 级别过滤 + 驱动覆盖三者同时发生。先盯死 storage/logs 是否真能写,再确认 Log::info() 调用后 Log::getLog() 是否有缓存条目——有则说明写入逻辑跑通,问题出在落盘环节;没有则说明连记录都没进队列。











