error_log这个指令在nginx的配置文件nginx.conf、php-fpm的配置文件php-fpm.conf以及php.ini三者中都存在,本文试图简要说明下这三个配置之间的区别和联系。
php.ini
error_log
string设置脚本错误将被记录到的文件。该文件必须是web服务器用户可写的。如果特殊值 syslog 被设置,则将错误信息发送到系统日志记录器。在Unix以及类似系统上,使用的是 syslog(3) ,而在 Windows NT 类系统上则为事件日志。Windows 95上不支持系统日志记录。参见: syslog(). 如果该配置没有设置,则错误信息会被发送到 SAPI 错误记录器。例如,出现在Apache的错误日志中,或者在CLI中发送到 stderr。
php-fpm.conf
error_log
string错误日志的位置。默认:#INSTALL_PREFIX#/log/php-fpm.log。 如果设置为 "syslog",日志将不会写入本地文件,而是发送到 syslogd。
nginx.conf
Syntax: error_log
file
[level
];Default: error_log logs/error.log error;
Context: main
,http
,stream
,server
,location
Configures logging. Several logs can be specified on the same level (1.5.2). If on the
main
configuration level writing a log to a file is not explicitly defined, the default file will be used.The first parameter defines a
file
that will store the log. The special valuestderr
selects the standard error file. Logging to syslog can be configured by specifying the “syslog:
” prefix. Logging to a cyclic memory buffer can be configured by specifying the “memory:
” prefix and buffersize
, and is generally used for debugging (1.7.11).The second parameter determines the
level
of logging, and can be one of the following:debug
,info
,notice
,warn
,error
,crit
,alert
, oremerg
. Log levels above are listed in the order of increasing severity. Setting a certain log level will cause all messages of the specified and more severe log levels to be logged. For example, the default levelerror
will causeerror
,crit
,alert
, andemerg
messages to be logged. If this parameter is omitted thenerror
is used.
从上面的文档初步可以看出 php.ini 中 error_log 优先级较高,下面依次实验这些配置的组合,让我们来看看它们的优先级,
测试报错使用以下简单的php代码:
<?php
throw new Exception('foobar');
其中各个error_log的配置值如下:
nginx:error_log /var/log/nginx/error.log;
php-fpm:error_log = /var/log/php-fpm/error.log
php.ini:error_log = /var/log/php/error.log
1、当三个值同时配置时,php的错误日志会写入php.ini中error_log指定的文件
[21-Apr-2019 22:19:13 Asia/Shanghai] PHP Fatal error: Uncaught Exception: foobar in /usr/share/nginx/html/error.php:5
Stack trace:
#0 {main}
thrown in /usr/share/nginx/html/error.php on line 5
但如果这个error_log指定的文件没有可写权限时会怎样呢,会不会记录到nginx或者php-fpm的error_log文件中呢?答案是否定的,此时报错信息会因为无法写入而丢失。
2、不配置php.ini 中的error_log,同时配置 nginx.conf 和php-fpm.conf 中的error_log,此时错误日志会写入到nginx的error_log文件中
2019/04/21 22:33:04 [error] 2031#0: *102 FastCGI sent in stderr: "PHP message: PHP Fatal error: Uncaught Exception: foobar in /usr/share/nginx/html/error.php:5
Stack trace:
#0 {main}
thrown in /usr/share/nginx/html/error.php on line 5" while reading response header from upstream, client: 127.0.0.1, server: _, request: "GET /error.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "127.0.0.1"
3、由于nginx的error_log不支持关闭,所以无法比较 nginx.conf 和 php-fpm.conf 中 error_log 的优先级,实际上 php-fpm.conf 中的error_log并不用来记录php的报错信息,而用来记录php-fpm进程本身的一些运行时信息。
4、虽然php-fpm.conf 中的error_log 不会记录php的报错信息,但是在php-fpm.conf 中可以用 php_value/php_flag 或 php_admin_value/php_admin_flag 配置来覆盖php.ini中的配置:
还可以在为一个运行池传递附加的环境变量,或者更新 PHP 的配置值。可以在进程池配置文件中如下面的配置参数来做到:
Example #1 给运行池传递环境变量和设置 PHP 的配置值
PHP配置值通过 php_value 或者 php_flag 设置,并且会覆盖以前的值。请注意 disable_functions 或者 disable_classes 在 php.ini 之中定义的值不会被覆盖掉,但是会将新的设置附加在原有值的后面。env[HOSTNAME] = $HOSTNAME env[PATH] = /usr/local/bin:/usr/bin:/bin env[TMP] = /tmp env[TMPDIR] = /tmp env[TEMP] = /tmp php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com php_flag[display_errors] = off php_admin_value[error_log] = /var/log/fpm-php.www.log php_admin_flag[log_errors] = on php_admin_value[memory_limit] = 32M
使用 php_admin_value 或者 php_admin_flag 定义的值,不能被 PHP 代码中的 ini_set() 覆盖。
例如,在php-fpm.conf 中配置 php_admin_value[error_log] = /var/log/php-fpm/www-error.log , 同时配置php.ini 中的error_log,会发现php报错信息会写入 /var/log/php-fpm/www-error.log文件中
总结:
error_log优先级:php-fpm.conf 中的 php_value[error_log] / php_admin_value[error_log]
大于 php.ini 中的 error_log
大于 nginx.conf 中的 error_log
而 php-fpm.conf 中的error_log 跟记录php运行时报错信息无关。
而最简单的获取php的错误日志记录的地方就是查看phpinfo() 信息,看其中的error_log 的值,如果有值,则错误日志就是记录在这个值指定的地方,没有则记录在nginx的error_log中。
有的框架使用set_exception_handler 和 set_error_handler 以及 register_shutdown_function重新设置了异常处理和报错处理,可能把错误日志写到另外一个地方,所以在开发环境下还是临时打开 display_errors 吧,这是最快速的定位错误的方法。
That's all