FrankenPHP 默认将访问日志和PHP错误统一输出到stderr,需通过Caddyfile配置access log、在PHP入口注册自定义错误处理器写入独立error日志,并配合logrotate实现轮转。

FrankenPHP 本身不提供传统意义上的 access 日志和 PHP 错误日志(error_log)的独立配置项,它默认将 HTTP 访问行为和 PHP 错误输出统一交由底层 Go 日志系统处理,并写入标准错误流(stderr)。但你可以通过明确的配置方式实现等效功能——即生成可读、可轮转、带上下文的访问与错误日志文件。
启用 FrankenPHP 的 HTTP 访问日志(access log)
FrankenPHP 基于 Caddy 的路由引擎,其访问日志通过 Caddyfile 配置控制,不是 PHP 层面设置:
- 在 Caddyfile 的站点块中添加
log指令,例如:
localhost:8080 {
php_server
log {
output file /var/log/frankenphp_access.log
format json
}
}
- 支持格式:plain(默认)、json、common(Apache 风格),推荐 json 方便后续解析
- 确保
/var/log目录存在,且运行 FrankenPHP 的用户(如www-data或当前用户)有写权限:sudo mkdir -p /var/log/frankenphp && sudo chown $USER:www-data /var/log/frankenphp && sudo chmod 755 /var/log/frankenphp - 重启 FrankenPHP 后,每次 HTTP 请求都会记录一条结构化日志
捕获 PHP 运行时错误并写入独立 error 日志
FrankenPHP 不读取 php_admin_value[error_log] 或 error_log = ... 这类 FPM/ini 配置。PHP 错误默认输出到 stderr,你需要主动接管:
立即学习“PHP免费学习笔记(深入)”;
- 在应用入口(如
public/index.php)顶部注册自定义错误处理器:
ini_set('log_errors', '1');
ini_set('display_errors', '0');
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
function write_php_error($errno, $errstr, $errfile, $errline) {
$msg = sprintf("[%s] %s in %s on line %d\n", date('Y-m-d H:i:s'), $errstr, basename($errfile), $errline);
file_put_contents('/var/log/frankenphp_php_error.log', $msg, FILE_APPEND | LOCK_EX);
}
set_error_handler('write_php_error');
- 补充 fatal error 捕获(如 parse error、内存耗尽):
register_shutdown_function(function () {
if ($e = error_get_last()) {
if (in_array($e['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR])) {
$msg = sprintf("[%s] FATAL: %s in %s on line %d\n", date('Y-m-d H:i:s'), $e['message'], basename($e['file']), $e['line']);
file_put_contents('/var/log/frankenphp_php_error.log', $msg, FILE_APPEND | LOCK_EX);
}
}
});
- 确保日志路径目录可写,建议用绝对路径,避免相对路径失效
- 该方式绕过 PHP 的内置
error_log机制,完全可控,也兼容 Laravel/Symfony 等框架(它们通常已接管,但底层仍依赖此逻辑)
可选:集中管理日志与轮转
FrankenPHP 自身不提供 logrotate 功能,需系统级配合:
- 为两个日志文件(access 和 php_error)配置
logrotate,例如新建/etc/logrotate.d/frankenphp:
/var/log/frankenphp_*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 644 $USER www-data
sharedscripts
postrotate
# 若 FrankenPHP 以 systemd 运行,可触发 reload(实际无热重载,仅示意)
endscript
}
- 也可接入 Fluent Bit / Filebeat 推送到 ELK 或 Loki,尤其适合多实例部署场景



















