摘要
咱们项目框架是 ThinkPHP5.0.24 ,系统环境为 Linux(Red Hat 4.8.5-11) 。
由于一些缘由,每次到月初,项目应用总会报错:php
error_log(runtime/log/201903/20_sql.log): failed to open stream: Permission deniedhtml
记录一下,解决的过程和方法。linux
心路历程
round 1
根据报错信息能够知道,有多是文件夹的权限问题。
解决方法是: 经过命令行或者图形化工具授予该日志文件夹 777 的权限 。web
若是问题就这么解决了,就不会有这篇文章了。sql
round 2
这个月处理完以后,下个月一样会出现这个问题。shell
这就引发重视了呀。否则,难道每月都要调闹钟、手动受权新增的文件夹写入的权限吗?vim
这不行。bash
欸!新增文件夹?服务器
为何新增的文件夹会权限不足呢?框架
查看各级日志文件夹信息:
> ll runtime/log/201903/
total 588
-rw-r--r-- 1 root root 370701 Mar 20 23:24 20.log
-rw-r--r-- 1 root root 217029 Mar 20 21:52 20_sql.log
-rw-r--r-- 1 root root 1192016 Mar 21 15:03 21_cli.log
此时文件夹内只能生成所属 root 的文件。
> ll runtime/log/
total 4
drwxr-xr-x 2 root root 4096 Mar 20 17:55 201903 // 此时报错,error 日志无权限写入
// 改为 drwxrwxrwx 2 root root 4096 Mar 20 17:55 201903 可解决,可是下月问题重现
// 删除此文件夹,主动请求接口生成:drwxr-xr-x 2 www www 4096 Mar 20 17:55 201903 可顺利写入
通过删除文件夹「runtime/log/201903/」,跑接口测试从新生成文件夹发现,此时生成的文件夹所属组和所属用户是 www 。
那么说明,出问题的这个文件夹(所属 root)不是跑框架的接口记录日志时生成的。
那么这个 root 所属的文件夹是谁生成的呢?
观察成功生成的日志文件可发现有以 _cli.log 结尾的文件。这不是定时任务的日志文件吗?只有它能正常运行?
缘由是:以 root 权限设置的 crontab 里每分钟执行的计划任务,在每月初第一时间执行并在框架下建立了 _cli.log 类型的日志。因此该月的文件夹所属就为 root ,而用户 www 在此文件夹内默认没有写入的权限,从而致使的报错。
round 3
既然知道了是 crontab 的定时任务的问题,那就重点盘它吧。
在进一步了解 crontab 的知识root 下能够设定指定用户(好比个人 www 用户)的时程表。原文以下:
-u user 是指设定指定 user 的时程表,这个前提是你必需要有其权限(好比说是 root)才可以指定他人的时程表。若是不使用 -u user 的话,就是表示设定本身的时程表。
经过如下操做:
> crontab -e -u www
把原来每分钟执行框架脚本的定时任务所有搬到了这个只针对 www 用户的时程表里。这样第一时间生成的文件夹「runtime/log/201903/」的所属就是 www 了。
搬到以 www 用户运行的时程表后,发现:
生成的日志文件夹「runtime/log/201903/」的所属用户(组)确实变为了 www ,也没有发生错误日志生成权限不足的问题(也就是上文说起的问题成功解决了,证实这个方向是可取的);
没有生成 _cli.log 等定时任务运行产生的日志文件,也就是说新的定时任务没有执行成功。
round 4
排查为什么定时任务没有执行成功。
先排查系统日志
> tail -f /var/log/cron
Mar 21 10:18:01 localhost CROND[22349]: (www) CMD (「时程表中的 command」)
... (www) MAIL (mailed 58 bytes of output but got status 0x004b#012)
注意到上面的 MAIL 的信息,查了一下:
这个实际上是 postfix 的配置问题,本次的问题不在这,是计划任务在执行完以后会经过 postfix 发邮件给执行完的用户邮箱,如今发不出去致使的,修改下配置就好了。
修改配置:
> vim /etc/postfix/main.cf
inet_interfaces = all
inet_protocols = all
确保这两个都是all 就能够了,而后重启 postfix。
重启后确实没有了那条关于 MAIL 的信息,可是会有以下提醒:
You have new mail in /var/spool/mail/root
经过命令查看:
> tail -f /var/spool/mail/root
X-Cron-Env:
X-Cron-Env:
X-Cron-Env:
X-Cron-Env:
X-Cron-Env:
Message-Id:
Date: Thu, 21 Mar 2019 10:17:01 +0800 (CST)
/bin/bash: ***.log: Permission denied
好了,Permission denied,也就是说时程表里的任务后面的输出日志权限不足咯。
由于时程表改为了指定用户的了,因此权限不足也正常。
找到缘由了,那么解决方案有两个:
找到输出日志的默认文件夹,受权给 www 用户写入的权限;
删除输出日志。
基于种种缘由想偷懒,好比时程表里跑的是框架内的 php 文件,会在框架内的日志文件夹生成 _cli.log 或 _error_cli.log 的日志,因此就选择了直接删掉了时程表中的输出日志部分。
删除了输出日志,可是若是报错,依旧会发送 mail 到 /var/spool/mail/root ,此时能够在命令后面加上 >/dev/null 2>&1 ,就不会发送 mail 了。
至此,定时任务恢复正常。
也就是 KO!
其它问题
1. 日志文件生成的全部者为 root
经过命令:
> crontab -e
默认设定当前用户的时程表。
若是以 root 用户登录(果真要尽可能避免啊摔),设定的时程表就属于 root 的了。
2. 关于 TP5 生成的错误日志是否报错的问题
测试以下:
try {
Log::write('test', 'error');
//Log::error('test:');
} catch (\Exception $e) {
echo '抛出异常啦!';
}
一样是无写入 error 文件的权限,Log::write 会抛出异常,中断程序;而 Log::error 不会抛出异常,也不生成文件。
总结
虽然解决了困惑已久的问题颇有成就感,可是归根结底是由于使用了 root 登录管理服务器致使的问题。
流下了没有技术的泪水啊。但愿同道中人能避免踩坑吧。