ThinkPHP日志写不进的主因是runtime/log目录权限不足、log.level配置过低、type驱动误配为trace/test、file_size非零导致不按天滚动,以及命令行创建日志文件引发的权限冲突。

日志写不进去,90% 是 runtime/log 目录或其父目录对 Web 进程用户不可写,不是配置错,是权限卡死。
runtime 和 log 目录都得对 Web 用户可写
ThinkPHP 的 Log::write() 会在 runtime/log 下创建日期文件(如 20260421.log),但前提是:runtime 目录本身必须可写——否则连文件都建不了,更别说写内容。常见错误是只改了 log 权限,却忘了 runtime 也要可写。
- 用
ls -ld runtime log查权限和属组,确认两者都是 Web 用户(如www-data、nginx或www)所有 - 典型安全权限组合:目录设
755,属主属组为 Web 用户,例如drwxr-xr-x 2 www-data www-data - 别用
chmod 777 runtime,线上环境禁止;推荐chown -R www-data:www-data runtime && chmod -R 755 runtime - Docker 环境要额外检查挂载卷 UID/GID 是否与容器内 Web 用户一致,否则
chown无效
log.level 配置低于实际调用级别,日志就“静默丢弃”
你写了 Log::info('user login') 却没看到日志?大概率是 log.level 设成了 'error' 或 'warning',而 info 级别低于它,直接被框架过滤掉。
- 配置在
config/log.php,关键项是'level' => 'error',可选值有'debug'、'info'、'warning'、'error'等 -
level是“最低记录门槛”:设为'warning'就只记warning、error、critical,不记info和debug - 开发环境建议设
'debug';生产环境至少'warning',避免info日志撑爆磁盘 - 如果用了多通道(如文件 + 邮件),每个通道可单独配
level,别只改全局配置却漏掉通道级覆盖
type 驱动误配成 trace 或 test,根本不会落盘
config/log.php 中的 'type' 决定日志是否真写进文件。'trace' 和 'test' 是内存驱动,只存临时数据,不生成任何文件——线上误配后,日志就“凭空消失”。
立即学习“PHP免费学习笔记(深入)”;
- 确认
'type'值是'file'(默认)、'socket'或'database'等真实落盘驱动 -
'type' => 'trace'只在app_debug = true时生效,且仅用于内置 Trace 页面,和日志文件无关 - 想看实时日志又不想刷盘?可用
'type' => 'socket',但需额外起服务监听(如nc -l 2000),别指望它自动写文件 - 用
Log::getLog()可查当前所有未刷新的日志条目,适合验证是“没写”,还是“写了但没 flush”
log.file_size 不为 0,日志文件名含日期也不按天滚动
ThinkPHP 文件驱动默认按日期生成文件(如 20260421.log),但“按天滚动”不是靠文件名决定的,而是靠 log.file_size 是否为 0。
-
'file_size' => 0:启用日期分割,每天新建一个文件 -
'file_size' => 1048576(1MB):按大小滚动,不按天,文件名仍带日期但内容跨天 - 这个值一旦非零,即使你看到
20260421.log,它也可能持续写入好几天,直到满 1MB 才切新文件 - 若要严格按天归档,必须确保
'file_size' => 0,且不要被其他配置(如多通道)意外覆盖
最易忽略的是:命令行执行 PHP 脚本(如定时任务)时,若日志文件尚未存在,会以 root 或当前 shell 用户身份创建,导致后续 Web 请求因权限不匹配而写失败——这种问题只在混合运行模式下暴露,单查 Web 权限找不到根因。



















