error_log() 在 frankenphp 里默认输出到标准错误(stderr),即终端、systemd journal 或 docker logs;需通过 php.ini 设置 error_log = /path/to/file 才能写入指定文件,推荐使用 monolog 写入 php://stdout 以获得结构化日志和请求上下文。

error_log() 在 FrankenPHP 里默认写到哪里?
FrankenPHP 默认把 error_log() 输出重定向到 PHP 的 error_log 配置项指定位置,而它又默认继承自 SAPI —— 也就是 FrankenPHP 自身的日志输出目标。实际运行中,error_log("hello") 不会出现在 Apache 或 Nginx 那类传统 Web 服务器的 error.log 里,而是直接落到 FrankenPHP 进程的标准错误(stderr),最终出现在你启动 FrankenPHP 时的终端、systemd journal、或 Docker logs 中。
这意味着:不显式配置,你就得去查 journalctl -u frankenphp 或 docker logs frankenphp 才能看到内容,而不是在某个文件里。
想写进指定文件?必须改 php.ini 或运行时设置
要让 error_log() 写入固定文件(比如 /var/log/php-app.log),不能只靠代码调用 error_log("msg", 3, "/path/to/file") —— 这种方式在 FrankenPHP 的多 worker 场景下容易因并发写入导致日志错乱、覆盖或权限失败(尤其是容器环境)。
- 推荐做法:在
php.ini里设error_log = /var/log/php-app.log,并确保 FrankenPHP 启动用户(如www-data)对该路径有写权限 - 如果用
frankenphp:alpine镜像,记得提前mkdir -p /var/log并chown www-data:www-data /var/log - 不要依赖
ini_set("error_log", "..."):它在 CLI 模式下生效,但在 FrankenPHP 的 HTTP 请求生命周期中可能被重置或忽略
为什么不用 error_log($msg, 3, $file)?
虽然语法合法,但这个用法在 FrankenPHP 下有几个硬伤:
- 每个请求都打开/追加写文件,无缓冲、无锁,高并发时日志行可能被截断或混序
- 路径硬编码在代码里,不利于不同环境(dev/staging/prod)切换
- FrankenPHP 的 worker 复用机制会让文件句柄长期持有,若日志轮转(logrotate)没配
copytruncate,旧 worker 仍往已清空/重命名的文件写,导致日志丢失 - 错误信息不会进入 FrankenPHP 的 structured log(JSON 格式),丧失 trace_id、request_id 等上下文关联能力
更稳妥的日志方案:用 Monolog + stdout
FrankenPHP 原生支持将结构化日志输出到 stdout/stderr,并自动注入请求上下文(如 request_id)。与其折腾 error_log(),不如直接用 Monolog\Handler\StreamHandler 写到 php://stdout:
$logger = new Logger('app');
$logger->pushHandler(new StreamHandler('php://stdout'));
$logger->error('User login failed', ['user_id' => 123]);
这样输出会被 FrankenPHP 拦截、打上时间戳和 request_id,再转发给宿主日志系统(journald / Docker / systemd)。比裸用 error_log() 更可靠,也更容易做集中采集(比如通过 fluentd 抓取 stdout)。
真正难的不是“怎么写进去”,而是“怎么让每条日志带上下文、不丢、不乱、可检索”——这些恰恰是直接调 error_log() 最容易忽略的点。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











