PHP错误日志默认关闭,必须手动开启log_errors=On并配置error_log绝对路径,同时确保目录写权限、重启Web服务,且display_errors与log_errors需协同启用才能既显示又记录错误。

PHP错误日志默认关了?先确认error_log和log_errors
PHP默认不把错误写进文件,哪怕display_errors开着,你也看不到日志——因为log_errors默认是Off。必须手动打开它,否则error_log()函数调用、trigger_error()抛出的警告全都不会落地。
检查当前配置:
var_dump(ini_get('log_errors')); // 应该是 '1' 或 'On'
var_dump(ini_get('error_log')); // 可能为空,或指向 /var/log/php_errors.log 等路径
修改方式有三种,按优先级排序:
- 在
php.ini中设:log_errors = On,并指定error_log = /var/log/php-app.log(注意目录需有写权限) - 在
.htaccess(Apache)中:php_flag log_errors on+php_value error_log "/path/to/app.log" - 运行时临时启用(仅限当前请求):
ini_set('log_errors', '1'); ini_set('error_log', '/tmp/myapp.log');
⚠️ 常见坑:Linux下Web用户(如www-data或apache)没权限往/var/log/写;Windows下路径斜杠写成\导致error_log静默失败。
立即学习“PHP免费学习笔记(深入)”;
error_log()函数怎么用才不丢日志
error_log()是PHP最轻量的自定义日志入口,但它不是“追加写”,而是依赖error_log配置——如果error_log没设文件路径,它会发到SAPI错误日志(如Apache的error_log),而不是你期望的文件里。
正确用法分两类:
- 直接写入指定文件(绕过
error_log配置):error_log("User login failed: {$user_id}", 3, "/var/log/myapp.log");—— 第二个参数3表示写文件,第三个参数必须是绝对路径 - 写入系统日志(Linux):
error_log("DB timeout", 4);—— 参数4调用syslog(),需配合openlog()设置标识
⚠️ 注意:error_log($msg, 3, $file)每次调用都会fopen(..., "a"),高并发下可能触发文件锁或I/O瓶颈;别在循环里无节制调用。
用Monolog做结构化日志前,先搞清它和error_log的关系
Monolog不是替代error_log,而是封装它。它的StreamHandler底层还是调用fopen+fwrite,SyslogHandler则调用openlog/syslog。关键区别在于:它自动加时间戳、级别标签、上下文数组,并支持滚动、过滤、异步写入。
最小可用示例:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('myapp');
$logger->pushHandler(new StreamHandler('/var/log/myapp.log', Logger::WARNING));
$logger->warning('Login failed', ['user_id' => 123, 'ip' => $_SERVER['REMOTE_ADDR']]);
常见疏漏点:
- 没设
Logger级别(如Logger::DEBUG),导致info()被静默丢弃 -
StreamHandler第二个参数传Logger::INFO,但Logger实例本身级别是WARNING,结果info()不输出 - 多个进程同时写同一日志文件,没配
RotatingFileHandler或GroupWriteHandler,导致日志错乱
线上环境禁用display_errors,但错误仍要进日志
开发时开display_errors方便调试,但上线必须关——否则敏感路径、数据库密码可能随错误堆栈暴露在HTML里。这时候唯一可靠的是日志。
确保三件事同时成立:
-
display_errors = Off(php.ini或运行时ini_set('display_errors', '0')) -
log_errors = On(否则所有E_WARNING、E_NOTICE都不记录) -
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT(推荐值,覆盖绝大多数问题)
额外建议:用set_error_handler()捕获未声明变量等E_NOTICE,再转给Monolog,避免它们被error_log忽略(默认error_reporting可能不含E_NOTICE)。
日志路径权限、磁盘满、时区未设(导致时间戳全是UTC)——这些细节比选什么库更容易让日志失效。



















