nginx、php-fpm、php 三者的配置文件中都有 error_log 项,指定各自错误日志的保存路径。理论上它们三者的错误应该不会重合,即 nginx error_log 记录的是 nginx 进程自己的错误,php-fpm error_log 记录的是 php-fpm 进程自己的错误, php error_log 记录的是 php 脚本执行时候的错误。
用户访问 nginx 服务,nginx 将用户请求转发给 php-fpm,然后由 php-fpm 调用 php 解析器来执行 php 脚本文件。在这个过程中我们最关心的是执行 php 脚本文件时候产生的 php 错误。
默认配置
通常,默认的配置文件如下所示:
nginx.conf
http { error_log /var/log/nginx/error.log warn; }通常,我们还会在 nginx.conf 中指定不同 server 段自己的 error_log,这样就可以把不同 server 的错误日志分开到不同的日志文件中。
php-fpm.conf (/etc/php-fpm.d/www.conf)
error_log = /var/log/php-fpm/error.log ;catch_workers_output = yes php_admin_value[error_log] = /var/log/php-fpm/www-error.log php_admin_flag[log_errors] = onphp-fpm 的 error_log 正常情况下只会记录 php-fpm 进程自己的信息,不会记录 php 脚本的执行错误。
后面三个配置项通常是放在 /etc/php-fpm.d/www.conf 中。
catch_workers_output 表示是否将每个 php-fpm worker 的 stdout 和 stderr 输出重定向到 error_log 中,默认不开启。而 php-fpm 的每个 worker 实际上就可以看作是 php 解析器。
php_admin_value[error_log] 会覆盖 php.ini 中的 error_log 配置。
php_admin_flag[log_errors] 会覆盖 php.ini 中的 log_errors 配置。
之所以会需要在 php-fpm.conf 覆盖 php.ini 中的配置项,是因为 php.ini 定义了整个 php 环境的配置,这就包括了在命令行直接执行
php script.php
时候的配置。而有些配置我们并不想影响全局,只想在 php-fpm 调用时起作用。
php.ini
log_errors = On ;error_log = php_errors.log ;error_log = sysloglog_errors 表示是否输出错误信息,如果关闭的话,连 stderr 都不会输出。
error_log 表示将错误信息输出到何处。可以指定日志文件的具体路径,指定为 syslog 的话则表示输出到系统日志中。如果不设置该值,则表示将错误信息输出到 stderr。php.ini 默认不设置该值。
所以根据上面的配置,/var/log/nginx/error.log,/var/log/php-fpm/error.log,/var/log/php-fpm/www-error.log 分别记录的是 nginx,php-fpm,php 脚本的错误信息。
php 日志读写权限
有时候即使确认了配置如上述一样,却无法在 /var/log/php-fpm/ 目录下找到 www-error.log 文件,而与此同时却在 /var/log/nginx/error.log 文件中发现了 php 脚本执行时错误信息。比如这样:
这很可能是因为 php 没有 /var/log/php-fpm/ 目录的读写权限,无法写入 /var/log/php-fpm/www-error.log。这时它就会将错误信息输出到 php-fpm worker 进程的 stderr,而 nginx 就会将它从 php-fpm 的 stderr 收到的任何信息以 error 等级写入自己的错误日志。
php-fpm master 进程通常是 root 用户,而 php-fpm 执行 php 脚本所使用的用户(亦即 php-fpm worker 进程的用户)是定义在 /etc/php-fpm.d/www.conf 文件中。
user = www group = www
所以只需要确保 php-fpm worker 有读写 /var/log/php-fpm/ 目录的权限,php 错误信息就能正确写入 /var/log/php-fpm/www-error.log 文件中。而 nginx 的 error_log 也就不会再收到 php 错误信息。
但是其实这种误打误撞的结果倒是我想要的。因为有时候我们会在 nginx 服务上部署多个网站,每个网站都通过 server 段中的 error_log 配置指定了自己的错误日志路径。所以我会更希望将 php 错误信息输出到对应网站的错误日志中,而不是统一输出到 php 的 error_log 中。
将 php 错误信息写到 nginx 站点的 error_log
不像上面那种 www-error.log 无写权限的歪路子,为了正确的将 php 错误信息写入到 nginx 每个站点各自的 error_log 文件中,需要保证如下几点:
- 在 /etc/php-fpm.d/www.conf 中开启 php_admin_flag[log_errors] = on。
- 在 /etc/php-fpm.d/www.conf 中注释掉 php_admin_value[error_log] 配置(并确保 php.ini 中也没有设置 error_log),让 php 的错误信息输出到 php-fpm worker 进程的 stderr。
- 在 nginx 的站点配置的 server 段中,配置站点自己的 error_log。并保证日志等级不大于 error。