自定义错误处理器不自动写日志,需在回调中显式调用 file_put_contents、error_log(0) 或 error_log(4) 并确保路径权限正确、并发安全;常见丢失原因为 stderr 丢弃、路径错误或框架接管未适配。

PHP自定义错误处理函数的日志默认不写文件
调用 set_error_handler() 或 set_exception_handler() 注册的自定义处理器,本身不会自动把错误写进 error_log 文件。它只是接管了错误分发流程,后续怎么记录、记到哪,完全由你写的回调函数决定。很多迁移后“日志消失”的情况,其实是回调里只做了 echo 或 var_dump,而这些输出在 FPM 模式下默认被丢弃或混进响应体,根本不会落地成日志。
常见错误处理日志丢失的三个实际原因
不是配置没生效,而是日志流向被隐式重定向了:
-
error_log()在容器中默认写到/proc/self/fd/2(即 stderr),但若没配catch_workers_output = yes,PHP-FPM 子进程的 stderr 输出会被直接丢弃 - 自定义 handler 里用了
error_log($msg, 3, $file),但$file路径不存在、权限不对,或父目录属主是root而 PHP 进程以www-data运行,写入静默失败 - 框架(如 Laravel)已全局接管异常,你的
set_exception_handler()根本没机会执行——得先关掉框架的异常捕获,或在框架日志通道里加一层转发
让自定义错误日志落到指定位置的实操方式
别依赖默认行为,显式控制输出目标:
- 在 handler 函数里用
file_put_contents('/var/log/myapp/error.log', $msg . "\n", FILE_APPEND | LOCK_EX),并确保/var/log/myapp/目录存在且chown www-data:www-data - 改用
error_log($msg, 4)写入系统日志,然后在容器启动时挂载/dev/log或配syslog日志驱动 - 更推荐:handler 中调用
error_log($msg, 0),即写入 PHP 默认error_log路径,然后统一把 PHP 的error_log指向/proc/self/fd/2,再靠 Docker 日志驱动收走
容器里查不到自定义日志?先确认这三件事
排查顺序比盲目改配置更有效:
- 进容器执行
ps aux | grep php-fpm,确认主进程和 worker 进程用户都是www-data,不是root - 运行
php -i | grep error_log,看输出是否为/proc/self/fd/2;如果不是,说明你的php.ini或 pool 配置没生效 - 临时在 handler 里加一句
file_put_contents('/tmp/test.log', 'hit', FILE_APPEND),然后ls -l /tmp/test.log看文件是否存在、内容是否追加——这是验证权限和路径最直接的方式
最常被忽略的是:自定义 handler 里调用 error_log() 时,第二个参数类型选错,或者没意识到 FILE_APPEND 必须配合 LOCK_EX 防并发写乱,否则多 worker 场景下日志会截断或覆盖。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











